2
0
Эх сурвалжийг харах

filesystem: SDL_CreateDirectory should make parent directories.

Fixes #10502.
Ryan C. Gordon 10 сар өмнө
parent
commit
428f2f35be

+ 6 - 1
include/SDL3/SDL_filesystem.h

@@ -249,7 +249,12 @@ typedef Uint32 SDL_GlobFlags;
 #define SDL_GLOB_CASEINSENSITIVE (1u << 0)
 
 /**
- * Create a directory.
+ * Create a directory, and any missing parent directories.
+ *
+ * This reports success if `path` already exists as a directory.
+ *
+ * If parent directories are missing, it will also create them. Note that
+ * if this fails, it will not remove any parent directories it already made.
  *
  * \param path the path of the directory to create.
  * \returns true on success or false on failure; call SDL_GetError() for more

+ 51 - 2
src/filesystem/SDL_filesystem.c

@@ -55,11 +55,60 @@ bool SDL_CopyFile(const char *oldpath, const char *newpath)
 
 bool SDL_CreateDirectory(const char *path)
 {
-    // TODO: Recursively create subdirectories
     if (!path) {
         return SDL_InvalidParamError("path");
     }
-    return SDL_SYS_CreateDirectory(path);
+
+    bool retval = SDL_SYS_CreateDirectory(path);
+    if (!retval && *path) {  // maybe we're missing parent directories?
+        char *parents = SDL_strdup(path);
+        if (!parents) {
+            return false;  // oh well.
+        }
+
+        // in case there was a separator at the end of the path and it was
+        // upsetting something, chop it off.
+        const size_t slen = SDL_strlen(parents);
+        #ifdef SDL_PLATFORM_WINDOWS
+        if ((parents[slen - 1] == '/') || (parents[slen - 1] == '\\'))
+        #else
+        if (parents[slen - 1] == '/')
+        #endif
+        {
+            parents[slen - 1] = '\0';
+            retval = SDL_SYS_CreateDirectory(parents);
+        }
+
+        if (!retval) {
+            for (char *ptr = parents; *ptr; ptr++) {
+                const char ch = *ptr;
+                #ifdef SDL_PLATFORM_WINDOWS
+                const bool issep = (ch == '/') || (ch == '\\');
+                if (issep && ((ptr - parents) == 2) && (parents[1] == ':')) {
+                    continue;  // it's just the drive letter, skip it.
+                }
+                #else
+                const bool issep = (ch == '/');
+                #endif
+
+                if (issep) {
+                    *ptr = '\0';
+                    // (this does not fail if the path already exists as a directory.)
+                    retval = SDL_SYS_CreateDirectory(parents);
+                    if (!retval) {  // still failing when making parents? Give up.
+                        break;
+                    }
+                    *ptr = ch;
+                }
+            }
+
+            // last chance: did it work this time?
+            retval = SDL_SYS_CreateDirectory(parents);
+        }
+
+        SDL_free(parents);
+    }
+    return retval;
 }
 
 bool SDL_EnumerateDirectory(const char *path, SDL_EnumerateDirectoryCallback callback, void *userdata)