From fe26f96b753b82e06c8def7dcb7b778711477d27 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 19 Apr 2021 03:42:21 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=A7=B9=20SDL1=20backports:=20Move=20GetBa?= =?UTF-8?q?se/PrefPath=20to=20cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/utils/sdl2_to_1_2_backports.cpp | 225 +++++++++++++++++++++++++ Source/utils/sdl2_to_1_2_backports.h | 223 +----------------------- 2 files changed, 227 insertions(+), 221 deletions(-) diff --git a/Source/utils/sdl2_to_1_2_backports.cpp b/Source/utils/sdl2_to_1_2_backports.cpp index 72ed0ec8b..384eb6424 100644 --- a/Source/utils/sdl2_to_1_2_backports.cpp +++ b/Source/utils/sdl2_to_1_2_backports.cpp @@ -485,3 +485,228 @@ int SDL_BlitScaled(SDL_Surface *src, SDL_Rect *srcrect, return SDL_SoftStretch(src, &final_src, dst, &final_dst); } + +// = Filesystem + +namespace { +#if !defined(__QNXNTO__) +char *readSymLink(const char *path) +{ + // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c + char *retval = NULL; + ssize_t len = 64; + ssize_t rc = -1; + + while (1) { + char *ptr = (char *)SDL_realloc(retval, (size_t)len); + if (ptr == NULL) { + SDL_OutOfMemory(); + break; + } + + retval = ptr; + + rc = readlink(path, retval, len); + if (rc == -1) { + break; /* not a symlink, i/o error, etc. */ + } else if (rc < len) { + retval[rc] = '\0'; /* readlink doesn't null-terminate. */ + return retval; /* we're good to go. */ + } + + len *= 2; /* grow buffer, try again. */ + } + + SDL_free(retval); + return NULL; +} +#endif +} // namespace + +char *SDL_GetBasePath() +{ + // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c + + char *retval = NULL; + +#if defined(__FREEBSD__) + char fullpath[PATH_MAX]; + size_t buflen = sizeof(fullpath); + const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) { + retval = SDL_strdup(fullpath); + if (!retval) { + SDL_OutOfMemory(); + return NULL; + } + } +#endif +#if defined(__OPENBSD__) + char **retvalargs; + size_t len; + const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; + if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) { + retvalargs = SDL_malloc(len); + if (!retvalargs) { + SDL_OutOfMemory(); + return NULL; + } + sysctl(mib, 4, retvalargs, &len, NULL, 0); + retval = SDL_malloc(PATH_MAX + 1); + if (retval) + realpath(retvalargs[0], retval); + + SDL_free(retvalargs); + } +#endif +#if defined(__SOLARIS__) + const char *path = getexecname(); + if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */ + retval = SDL_strdup(path); + if (!retval) { + SDL_OutOfMemory(); + return NULL; + } + } +#endif +#if defined(__3DS__) + retval = SDL_strdup("file:sdmc:/3ds/devilutionx/"); + return retval; +#endif + + /* is a Linux-style /proc filesystem available? */ + if (!retval && (access("/proc", F_OK) == 0)) { + /* !!! FIXME: after 2.0.6 ships, let's delete this code and just + use the /proc/%llu version. There's no reason to have + two copies of this plus all the #ifdefs. --ryan. */ +#if defined(__FREEBSD__) + retval = readSymLink("/proc/curproc/file"); +#elif defined(__NETBSD__) + retval = readSymLink("/proc/curproc/exe"); +#elif defined(__QNXNTO__) + retval = SDL_LoadFile("/proc/self/exefile", NULL); +#else + retval = readSymLink("/proc/self/exe"); /* linux. */ + if (retval == NULL) { + /* older kernels don't have /proc/self ... try PID version... */ + char path[64]; + const int rc = (int)SDL_snprintf(path, sizeof(path), + "/proc/%llu/exe", + (unsigned long long)getpid()); + if ((rc > 0) && (static_cast(rc) < sizeof(path))) { + retval = readSymLink(path); + } + } +#endif + } + + /* If we had access to argv[0] here, we could check it for a path, + or troll through $PATH looking for it, too. */ + + if (retval != NULL) { /* chop off filename. */ + char *ptr = SDL_strrchr(retval, '/'); + if (ptr != NULL) { + *(ptr + 1) = '\0'; + } else { /* shouldn't happen, but just in case... */ + SDL_free(retval); + retval = NULL; + } + } + + if (retval != NULL) { + /* try to shrink buffer... */ + char *ptr = (char *)SDL_realloc(retval, strlen(retval) + 1); + if (ptr != NULL) + retval = ptr; /* oh well if it failed. */ + } + + return retval; +} + +char *SDL_GetPrefPath(const char *org, const char *app) +{ + // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c + /* + * We use XDG's base directory spec, even if you're not on Linux. + * This isn't strictly correct, but the results are relatively sane + * in any case. + * + * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + */ + const char *envr = SDL_getenv("XDG_DATA_HOME"); + const char *append; + char *retval = NULL; + char *ptr = NULL; + size_t len = 0; + +#if defined(__3DS__) + retval = SDL_strdup("sdmc:/3ds/devilutionx/"); + return retval; +#endif + + if (!app) { + SDL_InvalidParamError("app"); + return NULL; + } + if (!org) { + org = ""; + } + + if (!envr) { + /* You end up with "$HOME/.local/share/Game Name 2" */ + envr = SDL_getenv("HOME"); + if (!envr) { + /* we could take heroic measures with /etc/passwd, but oh well. */ + SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set"); + return NULL; + } +#if defined(__unix__) || defined(__unix) + append = "/.local/share/"; +#else + append = "/"; +#endif + } else { + append = "/"; + } + + len = SDL_strlen(envr); + if (envr[len - 1] == '/') + append += 1; + + len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; + retval = (char *)SDL_malloc(len); + if (!retval) { + SDL_OutOfMemory(); + return NULL; + } + + if (*org) { + SDL_snprintf(retval, len, "%s%s%s/%s", envr, append, org, app); + } else { + SDL_snprintf(retval, len, "%s%s%s", envr, append, app); + } + + for (ptr = retval + 1; *ptr; ptr++) { + if (*ptr == '/') { + *ptr = '\0'; + if (mkdir(retval, 0700) != 0 && errno != EEXIST) + goto error; + *ptr = '/'; + } + } + if (mkdir(retval, 0700) != 0 && errno != EEXIST) { + error: + SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno)); + SDL_free(retval); + return NULL; + } + + // Append trailing / + size_t final_len = SDL_strlen(retval); + if (final_len + 1 < len) { + retval[final_len++] = '/'; + retval[final_len] = '\0'; + } + + return retval; +} diff --git a/Source/utils/sdl2_to_1_2_backports.h b/Source/utils/sdl2_to_1_2_backports.h index 4a7f53b93..2d2fbe319 100644 --- a/Source/utils/sdl2_to_1_2_backports.h +++ b/Source/utils/sdl2_to_1_2_backports.h @@ -313,224 +313,5 @@ int SDL_BlitScaled(SDL_Surface *src, SDL_Rect *srcrect, //== Filesystem -#if !defined(__QNXNTO__) -inline char * -readSymLink(const char *path) -{ - // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c - char *retval = NULL; - ssize_t len = 64; - ssize_t rc = -1; - - while (1) { - char *ptr = (char *)SDL_realloc(retval, (size_t)len); - if (ptr == NULL) { - SDL_OutOfMemory(); - break; - } - - retval = ptr; - - rc = readlink(path, retval, len); - if (rc == -1) { - break; /* not a symlink, i/o error, etc. */ - } else if (rc < len) { - retval[rc] = '\0'; /* readlink doesn't null-terminate. */ - return retval; /* we're good to go. */ - } - - len *= 2; /* grow buffer, try again. */ - } - - SDL_free(retval); - return NULL; -} -#endif - -inline char *SDL_GetBasePath() -{ - // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c - - char *retval = NULL; - -#if defined(__FREEBSD__) - char fullpath[PATH_MAX]; - size_t buflen = sizeof(fullpath); - const int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; - if (sysctl(mib, SDL_arraysize(mib), fullpath, &buflen, NULL, 0) != -1) { - retval = SDL_strdup(fullpath); - if (!retval) { - SDL_OutOfMemory(); - return NULL; - } - } -#endif -#if defined(__OPENBSD__) - char **retvalargs; - size_t len; - const int mib[] = { CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV }; - if (sysctl(mib, 4, NULL, &len, NULL, 0) != -1) { - retvalargs = SDL_malloc(len); - if (!retvalargs) { - SDL_OutOfMemory(); - return NULL; - } - sysctl(mib, 4, retvalargs, &len, NULL, 0); - retval = SDL_malloc(PATH_MAX + 1); - if (retval) - realpath(retvalargs[0], retval); - - SDL_free(retvalargs); - } -#endif -#if defined(__SOLARIS__) - const char *path = getexecname(); - if ((path != NULL) && (path[0] == '/')) { /* must be absolute path... */ - retval = SDL_strdup(path); - if (!retval) { - SDL_OutOfMemory(); - return NULL; - } - } -#endif -#if defined(__3DS__) - retval = SDL_strdup("file:sdmc:/3ds/devilutionx/"); - return retval; -#endif - - /* is a Linux-style /proc filesystem available? */ - if (!retval && (access("/proc", F_OK) == 0)) { - /* !!! FIXME: after 2.0.6 ships, let's delete this code and just - use the /proc/%llu version. There's no reason to have - two copies of this plus all the #ifdefs. --ryan. */ -#if defined(__FREEBSD__) - retval = readSymLink("/proc/curproc/file"); -#elif defined(__NETBSD__) - retval = readSymLink("/proc/curproc/exe"); -#elif defined(__QNXNTO__) - retval = SDL_LoadFile("/proc/self/exefile", NULL); -#else - retval = readSymLink("/proc/self/exe"); /* linux. */ - if (retval == NULL) { - /* older kernels don't have /proc/self ... try PID version... */ - char path[64]; - const int rc = (int)SDL_snprintf(path, sizeof(path), - "/proc/%llu/exe", - (unsigned long long)getpid()); - if ((rc > 0) && (static_cast(rc) < sizeof(path))) { - retval = readSymLink(path); - } - } -#endif - } - - /* If we had access to argv[0] here, we could check it for a path, - or troll through $PATH looking for it, too. */ - - if (retval != NULL) { /* chop off filename. */ - char *ptr = SDL_strrchr(retval, '/'); - if (ptr != NULL) { - *(ptr + 1) = '\0'; - } else { /* shouldn't happen, but just in case... */ - SDL_free(retval); - retval = NULL; - } - } - - if (retval != NULL) { - /* try to shrink buffer... */ - char *ptr = (char *)SDL_realloc(retval, strlen(retval) + 1); - if (ptr != NULL) - retval = ptr; /* oh well if it failed. */ - } - - return retval; -} - -inline char *SDL_GetPrefPath(const char *org, const char *app) -{ - // From sdl2-2.0.9/src/filesystem/unix/SDL_sysfilesystem.c - /* - * We use XDG's base directory spec, even if you're not on Linux. - * This isn't strictly correct, but the results are relatively sane - * in any case. - * - * http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - */ - const char *envr = SDL_getenv("XDG_DATA_HOME"); - const char *append; - char *retval = NULL; - char *ptr = NULL; - size_t len = 0; - -#if defined(__3DS__) - retval = SDL_strdup("sdmc:/3ds/devilutionx/"); - return retval; -#endif - - if (!app) { - SDL_InvalidParamError("app"); - return NULL; - } - if (!org) { - org = ""; - } - - if (!envr) { - /* You end up with "$HOME/.local/share/Game Name 2" */ - envr = SDL_getenv("HOME"); - if (!envr) { - /* we could take heroic measures with /etc/passwd, but oh well. */ - SDL_SetError("neither XDG_DATA_HOME nor HOME environment is set"); - return NULL; - } -#if defined(__unix__) || defined(__unix) - append = "/.local/share/"; -#else - append = "/"; -#endif - } else { - append = "/"; - } - - len = SDL_strlen(envr); - if (envr[len - 1] == '/') - append += 1; - - len += SDL_strlen(append) + SDL_strlen(org) + SDL_strlen(app) + 3; - retval = (char *)SDL_malloc(len); - if (!retval) { - SDL_OutOfMemory(); - return NULL; - } - - if (*org) { - SDL_snprintf(retval, len, "%s%s%s/%s", envr, append, org, app); - } else { - SDL_snprintf(retval, len, "%s%s%s", envr, append, app); - } - - for (ptr = retval + 1; *ptr; ptr++) { - if (*ptr == '/') { - *ptr = '\0'; - if (mkdir(retval, 0700) != 0 && errno != EEXIST) - goto error; - *ptr = '/'; - } - } - if (mkdir(retval, 0700) != 0 && errno != EEXIST) { - error: - SDL_SetError("Couldn't create directory '%s': '%s'", retval, strerror(errno)); - SDL_free(retval); - return NULL; - } - - // Append trailing / - size_t final_len = SDL_strlen(retval); - if (final_len + 1 < len) { - retval[final_len++] = '/'; - retval[final_len] = '\0'; - } - - return retval; -} +char *SDL_GetBasePath(); +char *SDL_GetPrefPath(const char *org, const char *app);