|
|
|
|
@ -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<std::size_t>(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); |
|
|
|
|
|