SDL: filesystem: SDL_EnumerateDirectoryCallback uses an enum now, not an int.

From 7d21a49c9cac39e8803ce152b121470ec5bbb77f Mon Sep 17 00:00:00 2001
From: "Ryan C. Gordon" <[EMAIL REDACTED]>
Date: Fri, 27 Sep 2024 22:28:47 -0400
Subject: [PATCH] filesystem: SDL_EnumerateDirectoryCallback uses an enum now,
 not an int.

Fixes #10955.
---
 include/SDL3/SDL_filesystem.h         | 41 +++++++++++++++++++++++----
 src/filesystem/SDL_filesystem.c       | 12 ++++----
 src/filesystem/posix/SDL_sysfsops.c   |  6 ++--
 src/filesystem/windows/SDL_sysfsops.c | 10 +++----
 test/testfilesystem.c                 |  6 ++--
 5 files changed, 53 insertions(+), 22 deletions(-)

diff --git a/include/SDL3/SDL_filesystem.h b/include/SDL3/SDL_filesystem.h
index 40df39b0da130..30bfea0fca4a7 100644
--- a/include/SDL3/SDL_filesystem.h
+++ b/include/SDL3/SDL_filesystem.h
@@ -264,11 +264,42 @@ typedef Uint32 SDL_GlobFlags;
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_CreateDirectory(const char *path);
 
-/* Callback for directory enumeration. Return 1 to keep enumerating,
-   0 to stop enumerating (no error), -1 to stop enumerating and
-   report an error. `dirname` is the directory being enumerated,
-   `fname` is the enumerated entry. */
-typedef int (SDLCALL *SDL_EnumerateDirectoryCallback)(void *userdata, const char *dirname, const char *fname);
+/**
+ * Possible results from an enumeration callback.
+ *
+ * \since This enum is available since SDL 3.0.0.
+ *
+ * \sa SDL_EnumerateDirectoryCallback
+ */
+typedef enum SDL_EnumerationResult
+{
+    SDL_ENUM_CONTINUE,   /**< Value that requests that enumeration continue. */
+    SDL_ENUM_SUCCESS,    /**< Value that requests that enumeration stop, successfully. */
+    SDL_ENUM_FAILURE     /**< Value that requests that enumeration stop, as a failure. */
+} SDL_EnumerationResult;
+
+/**
+ * Callback for directory enumeration.
+ *
+ * Enumeration of directory entries will continue until either all entries
+ * have been provided to the callback, or the callback has requested a stop
+ * through its return value.
+ *
+ * Returning SDL_ENUM_CONTINUE will let enumeration proceed, calling the
+ * callback with further entries. SDL_ENUM_SUCCESS and SDL_ENUM_FAILURE will
+ * terminate the enumeration early, and dictate the return value of the
+ * enumeration function itself.
+ *
+ * \param userdata an app-controlled pointer that is passed to the callback.
+ * \param dirname the directory that is being enumerated.
+ * \param fname the next entry in the enumeration.
+ * \returns how the enumeration should proceed.
+ *
+ * \since This datatype is available since SDL 3.0.0.
+ *
+ * \sa SDL_EnumerateDirectory
+ */
+typedef SDL_EnumerationResult (SDLCALL *SDL_EnumerateDirectoryCallback)(void *userdata, const char *dirname, const char *fname);
 
 /**
  * Enumerate a directory through a callback function.
diff --git a/src/filesystem/SDL_filesystem.c b/src/filesystem/SDL_filesystem.c
index 05f184d35965b..2f2b66c94a9bb 100644
--- a/src/filesystem/SDL_filesystem.c
+++ b/src/filesystem/SDL_filesystem.c
@@ -290,7 +290,7 @@ typedef struct GlobDirCallbackData
     SDL_IOStream *string_stream;
 } GlobDirCallbackData;
 
-static int SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, const char *fname)
+static SDL_EnumerationResult SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, const char *fname)
 {
     SDL_assert(userdata != NULL);
     SDL_assert(dirname != NULL);
@@ -305,14 +305,14 @@ static int SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, co
 
     char *fullpath = NULL;
     if (SDL_asprintf(&fullpath, "%s/%s", dirname, fname) < 0) {
-        return -1;
+        return SDL_ENUM_FAILURE;
     }
 
     char *folded = NULL;
     if (data->flags & SDL_GLOB_CASEINSENSITIVE) {
         folded = CaseFoldUtf8String(fullpath);
         if (!folded) {
-            return -1;
+            return SDL_ENUM_FAILURE;
         }
     }
 
@@ -326,18 +326,18 @@ static int SDLCALL GlobDirectoryCallback(void *userdata, const char *dirname, co
         const size_t slen = SDL_strlen(subpath) + 1;
         if (SDL_WriteIO(data->string_stream, subpath, slen) != slen) {
             SDL_free(fullpath);
-            return -1;  // stop enumerating, return failure to the app.
+            return SDL_ENUM_FAILURE;  // stop enumerating, return failure to the app.
         }
         data->num_entries++;
     }
 
-    int result = 1;  // keep enumerating by default.
+    SDL_EnumerationResult result = SDL_ENUM_CONTINUE;  // keep enumerating by default.
     if (matched_to_dir) {
         SDL_PathInfo info;
         if (data->getpathinfo(fullpath, &info, data->fsuserdata) && (info.type == SDL_PATHTYPE_DIRECTORY)) {
             //SDL_Log("GlobDirectoryCallback: Descending into subdir '%s'", fname);
             if (!data->enumerator(fullpath, GlobDirectoryCallback, data, data->fsuserdata)) {
-                result = -1;
+                result = SDL_ENUM_FAILURE;
             }
         }
     }
diff --git a/src/filesystem/posix/SDL_sysfsops.c b/src/filesystem/posix/SDL_sysfsops.c
index 5b199c7f84bff..36f539257d64a 100644
--- a/src/filesystem/posix/SDL_sysfsops.c
+++ b/src/filesystem/posix/SDL_sysfsops.c
@@ -36,7 +36,7 @@
 
 bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata)
 {
-    int result = 1;
+    SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
 
     DIR *dir = opendir(path);
     if (!dir) {
@@ -45,7 +45,7 @@ bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_Enume
     }
 
     struct dirent *ent;
-    while ((result == 1) && ((ent = readdir(dir)) != NULL))
+    while ((result == SDL_ENUM_CONTINUE) && ((ent = readdir(dir)) != NULL))
     {
         const char *name = ent->d_name;
         if ((SDL_strcmp(name, ".") == 0) || (SDL_strcmp(name, "..") == 0)) {
@@ -56,7 +56,7 @@ bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_Enume
 
     closedir(dir);
 
-    return (result >= 0);
+    return (result != SDL_ENUM_FAILURE);
 }
 
 bool SDL_SYS_RemovePath(const char *path)
diff --git a/src/filesystem/windows/SDL_sysfsops.c b/src/filesystem/windows/SDL_sysfsops.c
index b782b660d0cf4..a8f3759ee60d1 100644
--- a/src/filesystem/windows/SDL_sysfsops.c
+++ b/src/filesystem/windows/SDL_sysfsops.c
@@ -31,11 +31,11 @@
 
 bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_EnumerateDirectoryCallback cb, void *userdata)
 {
-    int result = 1;
+    SDL_EnumerationResult result = SDL_ENUM_CONTINUE;
     if (*path == '\0') {  // if empty (completely at the root), we need to enumerate drive letters.
         const DWORD drives = GetLogicalDrives();
         char name[3] = { 0, ':', '\0' };
-        for (int i = 'A'; (result == 1) && (i <= 'Z'); i++) {
+        for (int i = 'A'; (result == SDL_ENUM_CONTINUE) && (i <= 'Z'); i++) {
             if (drives & (1 << (i - 'A'))) {
                 name[0] = (char) i;
                 result = cb(userdata, dirname, name);
@@ -78,17 +78,17 @@ bool SDL_SYS_EnumerateDirectory(const char *path, const char *dirname, SDL_Enume
 
             char *utf8fn = WIN_StringToUTF8W(fn);
             if (!utf8fn) {
-                result = -1;
+                result = SDL_ENUM_FAILURE;
             } else {
                 result = cb(userdata, dirname, utf8fn);
                 SDL_free(utf8fn);
             }
-        } while ((result == 1) && (FindNextFileW(dir, &entw) != 0));
+        } while ((result == SDL_ENUM_CONTINUE) && (FindNextFileW(dir, &entw) != 0));
 
         FindClose(dir);
     }
 
-    return (result >= 0);
+    return (result != SDL_ENUM_FAILURE);
 }
 
 bool SDL_SYS_RemovePath(const char *path)
diff --git a/test/testfilesystem.c b/test/testfilesystem.c
index 848d6bbe1c8fb..3a068a0f2b863 100644
--- a/test/testfilesystem.c
+++ b/test/testfilesystem.c
@@ -15,7 +15,7 @@
 #include <SDL3/SDL_main.h>
 #include <SDL3/SDL_test.h>
 
-static int SDLCALL enum_callback(void *userdata, const char *origdir, const char *fname)
+static SDL_EnumerationResult SDLCALL enum_callback(void *userdata, const char *origdir, const char *fname)
 {
     SDL_PathInfo info;
     char *fullpath = NULL;
@@ -29,7 +29,7 @@ static int SDLCALL enum_callback(void *userdata, const char *origdir, const char
 
     if (SDL_asprintf(&fullpath, "%s%s%s", origdir, *origdir ? pathsep : "", fname) < 0) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!");
-        return -1;
+        return SDL_ENUM_FAILURE;
     }
 
     if (!SDL_GetPathInfo(fullpath, &info)) {
@@ -54,7 +54,7 @@ static int SDLCALL enum_callback(void *userdata, const char *origdir, const char
     }
 
     SDL_free(fullpath);
-    return 1;  /* keep going */
+    return SDL_ENUM_CONTINUE;  /* keep going */
 }