cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_sysfilesystem.c (6015B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#ifdef SDL_FILESYSTEM_UNIX
     24
     25/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
     26/* System dependent filesystem routines                                */
     27
     28#include <errno.h>
     29#include <stdio.h>
     30#include <unistd.h>
     31#include <stdlib.h>
     32#include <sys/stat.h>
     33#include <sys/types.h>
     34#include <limits.h>
     35
     36#ifdef __FREEBSD__
     37#include <sys/sysctl.h>
     38#endif
     39
     40#include "SDL_error.h"
     41#include "SDL_stdinc.h"
     42#include "SDL_filesystem.h"
     43
     44static char *
     45readSymLink(const char *path)
     46{
     47    char *retval = NULL;
     48    ssize_t len = 64;
     49    ssize_t rc = -1;
     50
     51    while (1)
     52    {
     53        char *ptr = (char *) SDL_realloc(retval, (size_t) len);
     54        if (ptr == NULL) {
     55            SDL_OutOfMemory();
     56            break;
     57        }
     58
     59        retval = ptr;
     60
     61        rc = readlink(path, retval, len);
     62        if (rc == -1) {
     63            break;  /* not a symlink, i/o error, etc. */
     64        } else if (rc < len) {
     65            retval[rc] = '\0';  /* readlink doesn't null-terminate. */
     66            return retval;  /* we're good to go. */
     67        }
     68
     69        len *= 2;  /* grow buffer, try again. */
     70    }
     71
     72    SDL_free(retval);
     73    return NULL;
     74}
     75
     76
     77char *
     78SDL_GetBasePath(void)
     79{
     80    char *retval = NULL;
     81
     82#if defined(__FREEBSD__)
     83    char fullpath[PATH_MAX];
     84    size_t buflen = sizeof (fullpath);
     85    const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
     86    if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) {
     87        retval = SDL_strdup(fullpath);
     88        if (!retval) {
     89            SDL_OutOfMemory();
     90            return NULL;
     91        }
     92    }
     93#elif defined(__SOLARIS__)
     94    const char *path = getexecname();
     95    if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */
     96        retval = SDL_strdup(path);
     97        if (!retval) {
     98            SDL_OutOfMemory();
     99            return NULL;
    100        }
    101    }
    102#endif
    103
    104    /* is a Linux-style /proc filesystem available? */
    105    if (!retval && (access("/proc", F_OK) == 0)) {
    106#if defined(__FREEBSD__)
    107        retval = readSymLink("/proc/curproc/file");
    108#elif defined(__NETBSD__)
    109        retval = readSymLink("/proc/curproc/exe");
    110#else
    111        retval = readSymLink("/proc/self/exe");  /* linux. */
    112#endif
    113        if (retval == NULL) {
    114            /* older kernels don't have /proc/self ... try PID version... */
    115            char path[64];
    116            const int rc = (int) SDL_snprintf(path, sizeof(path),
    117                                              "/proc/%llu/exe",
    118                                              (unsigned long long) getpid());
    119            if ( (rc > 0) && (rc < sizeof(path)) ) {
    120                retval = readSymLink(path);
    121            }
    122        }
    123    }
    124
    125    /* If we had access to argv[0] here, we could check it for a path,
    126        or troll through $PATH looking for it, too. */
    127
    128    if (retval != NULL) { /* chop off filename. */
    129        char *ptr = SDL_strrchr(retval, '/');
    130        if (ptr != NULL) {
    131            *(ptr+1) = '\0';
    132        } else {  /* shouldn't happen, but just in case... */
    133            SDL_free(retval);
    134            retval = NULL;
    135        }
    136    }
    137
    138    if (retval != NULL) {
    139        /* try to shrink buffer... */
    140        char *ptr = (char *) SDL_realloc(retval, strlen(retval) + 1);
    141        if (ptr != NULL)
    142            retval = ptr;  /* oh well if it failed. */
    143    }
    144
    145    return retval;
    146}
    147
    148char *
    149SDL_GetPrefPath(const char *org, const char *app)
    150{
    151    /*
    152     * We use XDG's base directory spec, even if you're not on Linux.
    153     *  This isn't strictly correct, but the results are relatively sane
    154     *  in any case.
    155     *
    156     * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
    157     */
    158    const char *envr = SDL_getenv("XDG_DATA_HOME");
    159    const char *append;
    160    char *retval = NULL;
    161    char *ptr = NULL;
    162    size_t len = 0;
    163
    164    if (!envr) {
    165        /* You end up with "$HOME/.local/share/Game Name 2" */
    166        envr = SDL_getenv("HOME");
    167        if (!envr) {
    168            /* we could take heroic measures with /etc/passwd, but oh well. */
    169            SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set");
    170            return NULL;
    171        }
    172        append = "/.local/share/";
    173    } else {
    174        append = "/";
    175    }
    176
    177    len = SDL_strlen(envr);
    178    if (envr[len - 1] == '/')
    179        append += 1;
    180
    181    len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3;
    182    retval = (char *) SDL_malloc(len);
    183    if (!retval) {
    184        SDL_OutOfMemory();
    185        return NULL;
    186    }
    187
    188    SDL_snprintf(retval, len, "%s%s%s/%s/", envr, append, org, app);
    189
    190    for (ptr = retval+1; *ptr; ptr++) {
    191        if (*ptr == '/') {
    192            *ptr = '\0';
    193            if (mkdir(retval, 0700) != 0 && errno != EEXIST)
    194                goto error;
    195            *ptr = '/';
    196        }
    197    }
    198    if (mkdir(retval, 0700) != 0 && errno != EEXIST) {
    199error:
    200        SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno));
    201        SDL_free(retval);
    202        return NULL;
    203    }
    204
    205    return retval;
    206}
    207
    208#endif /* SDL_FILESYSTEM_UNIX */
    209
    210/* vi: set ts=4 sw=4 expandtab: */