Explorar o código

filesystem: Added SDL_GetCurrentDirectory().

Fixes #11531.
Ryan C. Gordon hai 4 meses
pai
achega
f852038384

+ 16 - 0
include/SDL3/SDL_filesystem.h

@@ -447,6 +447,22 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo
  */
 extern SDL_DECLSPEC char ** SDLCALL SDL_GlobDirectory(const char *path, const char *pattern, SDL_GlobFlags flags, int *count);
 
+/**
+ * Get what the system believes is the "current working directory."
+ *
+ * For systems without a concept of a current working directory, this will
+ * still attempt to provide something reasonable.
+ *
+ * SDL does not provide a means to _change_ the current working directory;
+ * for platforms without this concept, this would cause surprises with file
+ * access outside of SDL.
+ *
+ * \returns a UTF-8 string of the current working directory in
+ *          platform-dependent notation. NULL if there's a problem. This
+ *          should be freed with SDL_free() when it is no longer needed.
+ */
+extern SDL_DECLSPEC char * SDLCALL SDL_GetCurrentDirectory(void);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 1 - 0
src/dynapi/SDL_dynapi.sym

@@ -1186,6 +1186,7 @@ SDL3_0.0.0 {
     SDL_CancelGPUCommandBuffer;
     SDL_SaveFile_IO;
     SDL_SaveFile;
+    SDL_GetCurrentDirectory;
     # extra symbols go here (don't modify this line)
   local: *;
 };

+ 1 - 0
src/dynapi/SDL_dynapi_overrides.h

@@ -1211,3 +1211,4 @@
 #define SDL_CancelGPUCommandBuffer SDL_CancelGPUCommandBuffer_REAL
 #define SDL_SaveFile_IO SDL_SaveFile_IO_REAL
 #define SDL_SaveFile SDL_SaveFile_REAL
+#define SDL_GetCurrentDirectory SDL_GetCurrentDirectory_REAL

+ 1 - 0
src/dynapi/SDL_dynapi_procs.h

@@ -1217,3 +1217,4 @@ SDL_DYNAPI_PROC(SDL_Sandbox,SDL_GetSandbox,(void),(),return)
 SDL_DYNAPI_PROC(bool,SDL_CancelGPUCommandBuffer,(SDL_GPUCommandBuffer *a),(a),return)
 SDL_DYNAPI_PROC(bool,SDL_SaveFile_IO,(SDL_IOStream *a,const void *b,size_t c,bool d),(a,b,c,d),return)
 SDL_DYNAPI_PROC(bool,SDL_SaveFile,(const char *a,const void *b,size_t c),(a,b,c),return)
+SDL_DYNAPI_PROC(char*,SDL_GetCurrentDirectory,(void),(),return)

+ 5 - 2
src/filesystem/SDL_filesystem.c

@@ -495,10 +495,13 @@ const char *SDL_GetUserFolder(SDL_Folder folder)
 
 char *SDL_GetPrefPath(const char *org, const char *app)
 {
-    char *path = SDL_SYS_GetPrefPath(org, app);
-    return path;
+    return SDL_SYS_GetPrefPath(org, app);
 }
 
+char *SDL_GetCurrentDirectory(void)
+{
+    return SDL_SYS_GetCurrentDirectory();
+}
 
 void SDL_InitFilesystem(void)
 {

+ 1 - 0
src/filesystem/SDL_sysfilesystem.h

@@ -26,6 +26,7 @@
 extern char *SDL_SYS_GetBasePath(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);
 
 extern bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata);
 extern bool SDL_SYS_RemovePath(const char *path);

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

@@ -45,4 +45,10 @@ char *SDL_SYS_GetUserFolder(SDL_Folder folder)
     return NULL;
 }
 
+char *SDL_SYS_GetCurrentDirectory(void)
+{
+    SDL_Unsupported();
+    return NULL;
+}
+
 #endif // SDL_FILESYSTEM_DUMMY || SDL_FILESYSTEM_DISABLED

+ 32 - 0
src/filesystem/posix/SDL_sysfsops.c

@@ -33,6 +33,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata)
 {
@@ -185,5 +186,36 @@ bool SDL_SYS_GetPathInfo(const char *path, SDL_PathInfo *info)
     return true;
 }
 
+// Note that this isn't actually part of filesystem, not fsops, but everything that uses posix fsops uses this implementation, even with separate filesystem code.
+char *SDL_SYS_GetCurrentDirectory(void)
+{
+    size_t buflen = 64;
+    char *buf = NULL;
+
+    while (true) {
+        void *ptr = SDL_realloc(buf, buflen);
+        if (!ptr) {
+            SDL_free(buf);
+            return NULL;
+        }
+        buf = (char *) ptr;
+
+        if (getcwd(buf, buflen) != NULL) {
+            break;  // we got it!
+        }
+
+        if (errno == ERANGE) {
+            buflen *= 2;  // try again with a bigger buffer.
+            continue;
+        }
+
+        SDL_free(buf);
+        SDL_SetError("getcwd failed: %s", strerror(errno));
+        return NULL;
+    }
+
+    return buf;
+}
+
 #endif // SDL_FSOPS_POSIX
 

+ 28 - 0
src/filesystem/windows/SDL_sysfilesystem.c

@@ -345,4 +345,32 @@ done:
     }
     return result;
 }
+
+char *SDL_SYS_GetCurrentDirectory(void)
+{
+    WCHAR *wstr = NULL;
+    DWORD buflen = 0;
+    while (true) {
+        const DWORD bw = GetCurrentDirectoryW(buflen, wstr);
+        if (bw == 0) {
+            WIN_SetError("GetCurrentDirectoryW failed");
+            return NULL;
+        } else if (bw < buflen) {
+            break;  // we got it!
+        }
+
+        void *ptr = SDL_realloc(wstr, bw * sizeof (WCHAR));
+        if (!ptr) {
+            SDL_free(wstr);
+            return NULL;
+        }
+        wstr = (WCHAR *) ptr;
+        buflen = bw;
+    }
+
+    char *retval = WIN_StringToUTF8W(wstr);
+    SDL_free(wstr);
+    return retval;
+}
+
 #endif // SDL_FILESYSTEM_WINDOWS

+ 10 - 0
test/testfilesystem.c

@@ -62,6 +62,7 @@ int main(int argc, char *argv[])
 {
     SDLTest_CommonState *state;
     char *pref_path;
+    char *curdir;
     const char *base_path;
 
     /* Initialize test framework */
@@ -106,6 +107,15 @@ int main(int argc, char *argv[])
     }
     SDL_free(pref_path);
 
+    curdir = SDL_GetCurrentDirectory();
+    if (!curdir) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't find current directory: %s\n",
+                     SDL_GetError());
+    } else {
+        SDL_Log("current directory: '%s'\n", curdir);
+    }
+    SDL_free(curdir);
+
     if (base_path) {
         char **globlist;
         SDL_IOStream *stream;