Sfoglia il codice sorgente

filesystem: Added SDL_GetExeName().

core/unix had a more-limited copy of filesystem/unix's implementation, called
SDL_GetExeName(). Replace that with a real implementation in filesystem, and
allow each platform to implement it as appropriate.

Implemented for Unix and Windows; most implementations are currently FIXME
stubs at the moment.

Reference Issue #15692.
Ryan C. Gordon 23 ore fa
parent
commit
7d29ce8e31

+ 3 - 0
src/SDL_internal.h

@@ -267,6 +267,9 @@ extern "C" {
    anything calling it without an extremely good reason. */
 extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
 
+// Get just the process's binary name, no path. Calculates and caches the string on first call. String lives until SDL_Quit(). This is not a public API right now!
+extern const char *SDL_GetExeName(void);
+
 #ifdef HAVE_LIBC
 #define SDL_abort() abort()
 #else

+ 0 - 1
src/SDL_utils.c

@@ -625,4 +625,3 @@ void SDL_DebugLogBackend(const char *subsystem, const char *backend)
 {
     SDL_LogDebug(SDL_LOG_CATEGORY_SYSTEM, "SDL chose %s backend '%s'", subsystem, backend);
 }
-

+ 1 - 0
src/core/linux/SDL_fcitx.c

@@ -54,6 +54,7 @@ typedef struct FcitxClient
 
 static FcitxClient fcitx_client;
 
+// !!! FIXME: should this just be dumped for src/core/unix's SDL_GetAppID()?
 static const char *GetAppName(void)
 {
     const char *exe_name = SDL_GetExeName();

+ 1 - 33
src/core/unix/SDL_appid.c

@@ -24,39 +24,6 @@
 #include "SDL_appid.h"
 #include <unistd.h>
 
-const char *SDL_GetExeName(void)
-{
-    static const char *proc_name = NULL;
-
-    // TODO: Use a fallback if BSD has no mounted procfs (OpenBSD has no procfs at all)
-    if (!proc_name) {
-#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_FREEBSD) || defined (SDL_PLATFORM_NETBSD) || defined(SDL_PLATFORM_HURD)
-        static char linkfile[1024];
-        int linksize;
-
-#if defined(SDL_PLATFORM_LINUX) || defined(SDL_PLATFORM_HURD)
-        const char *proc_path = "/proc/self/exe";
-#elif defined(SDL_PLATFORM_FREEBSD)
-        const char *proc_path = "/proc/curproc/file";
-#elif defined(SDL_PLATFORM_NETBSD)
-        const char *proc_path = "/proc/curproc/exe";
-#endif
-        linksize = readlink(proc_path, linkfile, sizeof(linkfile) - 1);
-        if (linksize > 0) {
-            linkfile[linksize] = '\0';
-            proc_name = SDL_strrchr(linkfile, '/');
-            if (proc_name) {
-                ++proc_name;
-            } else {
-                proc_name = linkfile;
-            }
-        }
-#endif
-    }
-
-    return proc_name;
-}
-
 const char *SDL_GetAppID(void)
 {
     const char *id_str = SDL_GetAppMetadataProperty(SDL_PROP_APP_METADATA_IDENTIFIER_STRING);
@@ -79,3 +46,4 @@ const char *SDL_GetAppID(void)
 
     return id_str;
 }
+

+ 0 - 1
src/core/unix/SDL_appid.h

@@ -24,7 +24,6 @@ freely, subject to the following restrictions:
 #ifndef SDL_appid_h_
 #define SDL_appid_h_
 
-extern const char *SDL_GetExeName(void);
 extern const char *SDL_GetAppID(void);
 
 #endif // SDL_appid_h_

+ 38 - 0
src/core/windows/SDL_windows.c

@@ -730,4 +730,42 @@ const char *WIN_CheckDefaultArgcArgv(int *pargc, char ***pargv, void **pallocate
     return NULL;  // no error string.
 }
 
+char *WIN_GetModulePath(HMODULE handle)
+{
+    DWORD buflen = 128;
+    WCHAR *path = NULL;
+    DWORD len = 0;
+
+    while (true) {
+        void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR));
+        if (!ptr) {
+            SDL_free(path);
+            return NULL;
+        }
+
+        path = (WCHAR *)ptr;
+
+        len = GetModuleFileNameW(handle, path, buflen);
+        // if it truncated, then len >= buflen - 1
+        // if there was enough room (or failure), len < buflen - 1
+        if (len < (buflen - 1)) {
+            break;
+        }
+
+        // buffer too small? Try again.
+        buflen *= 2;
+    }
+
+    char *retval = NULL;
+    if (len == 0) {
+        WIN_SetError("Couldn't locate module");
+    } else {
+        retval = WIN_StringToUTF8W(path);
+    }
+
+    SDL_free(path);
+
+    return retval;
+}
+
 #endif // defined(SDL_PLATFORM_WINDOWS)

+ 4 - 1
src/core/windows/SDL_windows.h

@@ -223,7 +223,10 @@ extern SDL_AudioFormat SDL_WaveFormatExToSDLFormat(WAVEFORMATEX *waveformat);
 extern int WIN_WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWCH lpWideCharStr, int cchWideChar, LPSTR lpMultiByteStr, int cbMultiByte, LPCCH lpDefaultChar, LPBOOL lpUsedDefaultChar);
 
 // parse out command lines from OS if argv is NULL, otherwise pass through unchanged. `*pallocated` must be HeapFree'd by caller if not NULL on successful return. Returns NULL on success, error string on problems.
-const char *WIN_CheckDefaultArgcArgv(int *pargc, char ***pargv, void **pallocated);
+extern const char *WIN_CheckDefaultArgcArgv(int *pargc, char ***pargv, void **pallocated);
+
+// Does all the win32 tapdancing to make GetModuleFileName work. Returns a SDL_malloc'd UTF-8 string, or NULL on failure.
+extern char *WIN_GetModulePath(HMODULE handle);
 
 // Ends C function definitions when using C++
 #ifdef __cplusplus

+ 14 - 4
src/filesystem/SDL_filesystem.c

@@ -518,6 +518,14 @@ const char *SDL_GetUserFolder(SDL_Folder folder)
     return CachedUserFolders[idx];
 }
 
+static char *CachedExeName = NULL;
+const char *SDL_GetExeName(void)
+{
+    if (!CachedExeName) {
+        CachedExeName = SDL_SYS_GetExeName();
+    }
+    return CachedExeName;
+}
 
 char *SDL_GetPrefPath(const char *org, const char *app)
 {
@@ -545,10 +553,12 @@ void SDL_InitFilesystem(void)
 
 void SDL_QuitFilesystem(void)
 {
-    if (CachedBasePath) {
-        SDL_free(CachedBasePath);
-        CachedBasePath = NULL;
-    }
+    SDL_free(CachedBasePath);
+    CachedBasePath = NULL;
+
+    SDL_free(CachedExeName);
+    CachedExeName = NULL;
+
     for (int i = 0; i < SDL_arraysize(CachedUserFolders); i++) {
         if (CachedUserFolders[i]) {
             SDL_free(CachedUserFolders[i]);

+ 1 - 0
src/filesystem/SDL_sysfilesystem.h

@@ -24,6 +24,7 @@
 
 // return a string that we can SDL_free(). It will be cached at the higher level.
 extern char *SDL_SYS_GetBasePath(void);
+extern char *SDL_SYS_GetExeName(void);
 extern char *SDL_SYS_GetPrefPath(const char *org, const char *app);
 extern char *SDL_SYS_GetUserFolder(SDL_Folder folder);
 extern char *SDL_SYS_GetCurrentDirectory(void);

+ 5 - 0
src/filesystem/android/SDL_sysfilesystem.c

@@ -34,6 +34,11 @@ char *SDL_SYS_GetBasePath(void)
     return SDL_strdup("assets://");
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // !!! FIXME: probably just use the Linux path?
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     const char *path = SDL_GetAndroidInternalStoragePath();

+ 6 - 0
src/filesystem/cocoa/SDL_sysfilesystem.m

@@ -63,6 +63,12 @@ char *SDL_SYS_GetBasePath(void)
     }
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     @autoreleasepool {

+ 6 - 0
src/filesystem/dos/SDL_sysfilesystem.c

@@ -104,6 +104,12 @@ char *SDL_SYS_GetBasePath(void)
     return retval;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME: Move most of SDL_SYS_GetBasePath to a separate function and reuse it here.
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     char *result = NULL;

+ 6 - 0
src/filesystem/dummy/SDL_sysfilesystem.c

@@ -33,6 +33,12 @@ char *SDL_SYS_GetBasePath(void)
     return NULL;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     SDL_Unsupported();

+ 5 - 0
src/filesystem/emscripten/SDL_sysfilesystem.c

@@ -37,6 +37,11 @@ char *SDL_SYS_GetBasePath(void)
     return SDL_strdup("/");
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // no EXE name on this system.
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     #ifdef SDL_EMSCRIPTEN_PERSISTENT_PATH_STRING

+ 8 - 0
src/filesystem/gdk/SDL_sysfilesystem.cpp

@@ -38,6 +38,8 @@ SDL_SYS_GetBasePath(void)
 {
     /* NOTE: This function is a UTF8 version of the Win32 SDL_GetBasePath()!
      * The GDK actually _recommends_ the 'A' functions over the 'W' functions :o
+     *
+     * !!! FIXME: But can we use WIN_GetModulePath anyhow? (or change WIN_GetModulePath to use GetModuleFileNameA when built for GDK?)
      */
     DWORD buflen = 128;
     CHAR *path = NULL;
@@ -82,6 +84,12 @@ SDL_SYS_GetBasePath(void)
     return path;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME: use WIN_GetModulePath
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     XUserHandle user = NULL;

+ 5 - 0
src/filesystem/haiku/SDL_sysfilesystem.cc

@@ -64,6 +64,11 @@ char *SDL_SYS_GetBasePath(void)
     return result;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME: Move most of SDL_SYS_GetBasePath to a separate function and reuse it here.
+    return NULL;
+}
 
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {

+ 5 - 0
src/filesystem/n3ds/SDL_sysfilesystem.c

@@ -40,6 +40,11 @@ char *SDL_SYS_GetBasePath(void)
     return base_path;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // there isn't an "exe name" on this platform.
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     char *pref_path = NULL;

+ 6 - 0
src/filesystem/ngage/SDL_sysfilesystem.c

@@ -30,6 +30,12 @@ char *SDL_SYS_GetBasePath(void)
     return base_path;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME: see code in NGAGE_GetAppPath
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     char *pref_path = NULL;

+ 5 - 0
src/filesystem/ps2/SDL_sysfilesystem.c

@@ -46,6 +46,11 @@ char *SDL_SYS_GetBasePath(void)
     return result;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // no EXE name on this system.
+}
+
 // Do a recursive mkdir of parents folders
 static void recursive_mkdir(const char *dir)
 {

+ 5 - 0
src/filesystem/psp/SDL_sysfilesystem.c

@@ -46,6 +46,11 @@ char *SDL_SYS_GetBasePath(void)
     return result;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // no EXE name on this system.
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     char *result = NULL;

+ 6 - 0
src/filesystem/riscos/SDL_sysfilesystem.c

@@ -152,6 +152,12 @@ char *SDL_SYS_GetBasePath(void)
     return result;
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    SDL_Unsupported();  // !!! FIXME: see code in SDL_SYS_GetBasePath.
+    return NULL;
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     char *canon, *dir, *result;

+ 31 - 16
src/filesystem/unix/SDL_sysfilesystem.c

@@ -122,7 +122,7 @@ static char *search_path_for_binary(const char *bin)
 }
 #endif
 
-char *SDL_SYS_GetBasePath(void)
+static char *GetExePath(void)
 {
     char *result = NULL;
 
@@ -235,27 +235,42 @@ char *SDL_SYS_GetBasePath(void)
     /* If we had access to argv[0] here, we could check it for a path,
         or troll through $PATH looking for it, too. */
 
-    if (result) { // chop off filename.
-        char *ptr = SDL_strrchr(result, '/');
-        if (ptr) {
-            *(ptr + 1) = '\0';
-        } else { // shouldn't happen, but just in case...
-            SDL_free(result);
-            result = NULL;
-        }
+    return result;
+}
+
+char *SDL_SYS_GetBasePath(void)
+{
+    char *path = GetExePath();
+    if (!path) {
+        return NULL;
     }
 
-    if (result) {
-        // try to shrink buffer...
-        char *ptr = (char *)SDL_realloc(result, SDL_strlen(result) + 1);
-        if (ptr) {
-            result = ptr; // oh well if it failed.
-        }
+    char *ptr = SDL_strrchr(path, '/');
+    SDL_assert(ptr != NULL);  // Should have been an absolute path.
+
+    ptr[1] = '\0'; // chop off filename, leave '/'.
+
+    ptr = (char *) SDL_realloc(path, ((size_t) (ptr - path)) + 2);  // try to shrink this allocation down a little.
+    return ptr ? ptr : path;  // return shrunk buffer if shrink worked out, unchanged original buffer if not.
+}
+
+
+char *SDL_SYS_GetExeName(void)
+{
+    char *path = GetExePath();
+    if (!path) {
+        return NULL;
     }
 
-    return result;
+    char *ptr = SDL_strrchr(path, '/');
+    SDL_assert(ptr != NULL);  // Should have been an absolute path.
+    const size_t slen = SDL_strlen(ptr);  // counts null terminator because we're still sitting on path separator.
+    SDL_memmove(path, ptr + 1, slen);  // move filename string to start of SDL_realloc'd region.
+    ptr = (char *) SDL_realloc(path, slen);  // try to shrink this allocation down a little.
+    return ptr ? ptr : path;  // return shrunk buffer if shrink worked out, unchanged original buffer if not.
 }
 
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     /*

+ 5 - 0
src/filesystem/vita/SDL_sysfilesystem.c

@@ -41,6 +41,11 @@ char *SDL_SYS_GetBasePath(void)
     return SDL_strdup("app0:/");
 }
 
+char *SDL_SYS_GetExeName(void)
+{
+    return NULL;  // no EXE name on this system.
+}
+
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)
 {
     const char *envr = "ux0:/data/";

+ 20 - 39
src/filesystem/windows/SDL_sysfilesystem.c

@@ -45,51 +45,32 @@ DEFINE_GUID(SDL_FOLDERID_Videos, 0x18989B1D, 0x99B5, 0x455B, 0x84, 0x1C, 0xAB, 0
 
 char *SDL_SYS_GetBasePath(void)
 {
-    DWORD buflen = 128;
-    WCHAR *path = NULL;
-    char *result = NULL;
-    DWORD len = 0;
-    int i;
-
-    while (true) {
-        void *ptr = SDL_realloc(path, buflen * sizeof(WCHAR));
-        if (!ptr) {
-            SDL_free(path);
-            return NULL;
-        }
-
-        path = (WCHAR *)ptr;
-
-        len = GetModuleFileNameW(NULL, path, buflen);
-        // if it truncated, then len >= buflen - 1
-        // if there was enough room (or failure), len < buflen - 1
-        if (len < buflen - 1) {
-            break;
-        }
-
-        // buffer too small? Try again.
-        buflen *= 2;
+    char *path = WIN_GetModulePath(NULL);  // look up full path of the current process's EXE file.
+    if (!path) {
+        return NULL;  // error message was already set.
     }
 
-    if (len == 0) {
-        SDL_free(path);
-        WIN_SetError("Couldn't locate our .exe");
-        return NULL;
-    }
+    char *ptr = SDL_strrchr(path, '\\');
+    SDL_assert(ptr != NULL);  // Should have been an absolute path.
 
-    for (i = len - 1; i > 0; i--) {
-        if (path[i] == '\\') {
-            break;
-        }
-    }
+    ptr[1] = '\0'; // chop off filename, leave '\\'.
 
-    SDL_assert(i > 0);  // Should have been an absolute path.
-    path[i + 1] = '\0'; // chop off filename.
+    ptr = (char *) SDL_realloc(path, ((size_t) (ptr - path)) + 2);  // try to shrink this allocation down a little.
+    return ptr ? ptr : path;  // return shrunk buffer if shrink worked out, unchanged original buffer if not.
+}
 
-    result = WIN_StringToUTF8W(path);
-    SDL_free(path);
+char *SDL_SYS_GetExeName(void)
+{
+    char *path = WIN_GetModulePath(NULL);  // look up full path of the current process's EXE file.
+    if (!path) {
+        return NULL;  // error message was already set.
+    }
 
-    return result;
+    char *ptr = SDL_strrchr(path, '\\');
+    const size_t slen = SDL_strlen(ptr);  // counts null terminator because we're still sitting on path separator.
+    SDL_memmove(path, ptr + 1, slen);  // move filename string to start of SDL_realloc'd region.
+    ptr = (char *) SDL_realloc(path, slen);  // try to shrink this allocation down a little.
+    return ptr ? ptr : path;  // return shrunk buffer if shrink worked out, unchanged original buffer if not.
 }
 
 char *SDL_SYS_GetPrefPath(const char *org, const char *app)