shithub: choc

Download patch

ref: f5da1a45b1d34e40b4687a6add3b8a2b3685f525
parent: 5705be4c622af4a4027a711c5dbbb42d9ce0ea8a
author: Simon Howard <fraggle@soulsphere.org>
date: Sat Nov 3 09:11:55 EDT 2018

glob: Add multi-pattern matching.

Sometimes we want to glob for more than one type of file at once.

--- a/src/i_glob.c
+++ b/src/i_glob.c
@@ -72,7 +72,8 @@
 
 struct glob_s
 {
-    char *glob;
+    char **globs;
+    int num_globs;
     int flags;
     DIR *dir;
     char *directory;
@@ -83,10 +84,33 @@
     int next_index;
 };
 
-glob_t *I_StartGlob(const char *directory, const char *glob, int flags)
+glob_t *I_StartMultiGlob(const char *directory, int flags,
+                         const char *glob, ...)
 {
+    char **globs;
+    int num_globs;
     glob_t *result;
+    va_list args;
 
+    globs = malloc(sizeof(char *));
+    globs[0] = M_StringDuplicate(glob);
+    num_globs = 1;
+
+    va_start(args, glob);
+    for (;;)
+    {
+        const char *arg = va_arg(args, const char *);
+        if (arg == NULL)
+        {
+            break;
+        }
+
+        globs = realloc(globs, sizeof(char *) * (num_globs + 1));
+        globs[num_globs] = M_StringDuplicate(arg);
+        ++num_globs;
+    }
+    va_end(args);
+
     result = malloc(sizeof(glob_t));
     if (result == NULL)
     {
@@ -101,7 +125,8 @@
     }
 
     result->directory = M_StringDuplicate(directory);
-    result->glob = M_StringDuplicate(glob);
+    result->globs = globs;
+    result->num_globs = num_globs;
     result->flags = flags;
     result->last_filename = NULL;
     result->filenames = NULL;
@@ -110,6 +135,11 @@
     return result;
 }
 
+glob_t *I_StartGlob(const char *directory, const char *glob, int flags)
+{
+    return I_StartMultiGlob(directory, flags, glob, NULL);
+}
+
 void I_EndGlob(glob_t *glob)
 {
     int i;
@@ -119,15 +149,20 @@
         return;
     }
 
+    for (i = 0; i < glob->num_globs; ++i)
+    {
+        free(glob->globs[i]);
+    }
+
     for (i = 0; i < glob->filenames_len; ++i)
     {
         free(glob->filenames[i]);
     }
 
+    free(glob->globs);
     free(glob->filenames);
     free(glob->directory);
     free(glob->last_filename);
-    free(glob->glob);
     (void) closedir(glob->dir);
     free(glob);
 }
@@ -177,6 +212,20 @@
     return *name == '\0';
 }
 
+static boolean MatchesAnyGlob(const char *name, glob_t *glob)
+{
+    int i;
+
+    for (i = 0; i < glob->num_globs; ++i)
+    {
+        if (MatchesGlob(name, glob->globs[i], glob->flags))
+        {
+            return true;
+        }
+    }
+    return false;
+}
+
 static char *NextGlob(glob_t *glob)
 {
     struct dirent *de;
@@ -189,7 +238,7 @@
             return NULL;
         }
     } while (IsDirectory(glob->directory, de)
-          || !MatchesGlob(de->d_name, glob->glob, glob->flags));
+          || !MatchesAnyGlob(de->d_name, glob));
 
     // Return the fully-qualified path, not just the bare filename.
     return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL);
--- a/src/i_glob.h
+++ b/src/i_glob.h
@@ -28,6 +28,11 @@
 // the given glob pattern. I_EndGlob() must be called on completion.
 glob_t *I_StartGlob(const char *directory, const char *glob, int flags);
 
+// Same as I_StartGlob but multiple glob patterns can be provided. The list
+// of patterns must be terminated with NULL.
+glob_t *I_StartMultiGlob(const char *directory, int flags,
+                         const char *glob, ...);
+
 // Finish reading file list.
 void I_EndGlob(glob_t *glob);