ref: 65c7edcdb2f438320e3f8f506207be1c6414dbea
parent: 0a85811d624b68684dad0469405a4850907dd03b
author: Simon Howard <fraggle@soulsphere.org>
date: Mon Oct 29 16:53:06 EDT 2018
glob: Add flag for reading filenames sorted. This will be important for autoload functionality. As a start, set the flag for substitute MIDI .cfg files.
--- a/src/i_glob.c
+++ b/src/i_glob.c
@@ -79,6 +79,10 @@
DIR *dir;
char *directory;
char *last_filename;
+ // These fields are only used when the GLOB_FLAG_SORTED flag is set:
+ char **filenames;
+ int filenames_len;
+ int next_index;
};
glob_t *I_StartGlob(const char *directory, const char *glob, int flags)
@@ -102,16 +106,27 @@
result->glob = M_StringDuplicate(glob);
result->flags = flags;
result->last_filename = NULL;
+ result->filenames = NULL;
+ result->filenames_len = 0;
+ result->next_index = -1;
return result;
}
void I_EndGlob(glob_t *glob)
{
+ int i;
+
if (glob == NULL)
{
return;
}
+ for (i = 0; i < glob->filenames_len; ++i)
+ {
+ free(glob->filenames[i]);
+ }
+
+ free(glob->filenames);
free(glob->directory);
free(glob->last_filename);
free(glob->glob);
@@ -164,7 +179,7 @@
return *name == '\0';
}
-const char *I_NextGlob(glob_t *glob)
+static char *NextGlob(glob_t *glob)
{
struct dirent *de;
@@ -179,10 +194,86 @@
|| !MatchesGlob(de->d_name, glob->glob, glob->flags));
// Return the fully-qualified path, not just the bare filename.
- free(glob->last_filename);
- glob->last_filename = M_StringJoin(glob->directory, DIR_SEPARATOR_S,
- de->d_name, NULL);
- return glob->last_filename;
+ return M_StringJoin(glob->directory, DIR_SEPARATOR_S, de->d_name, NULL);
+}
+
+static void ReadAllFilenames(glob_t *glob)
+{
+ char *name;
+
+ glob->filenames = NULL;
+ glob->filenames_len = 0;
+ glob->next_index = 0;
+
+ for (;;)
+ {
+ name = NextGlob(glob);
+ if (name == NULL)
+ {
+ break;
+ }
+ glob->filenames = realloc(glob->filenames,
+ (glob->filenames_len + 1) * sizeof(char *));
+ glob->filenames[glob->filenames_len] = name;
+ ++glob->filenames_len;
+ }
+}
+
+static void SortFilenames(char **filenames, int len)
+{
+ char *pivot, *tmp;
+ int i, left_len;
+
+ if (len < 2)
+ {
+ return;
+ }
+ pivot = filenames[0];
+ left_len = 0;
+ for (i = 1; i < len; ++i)
+ {
+ if (strcmp(filenames[i], pivot) < 0)
+ {
+ tmp = filenames[i];
+ filenames[i] = filenames[left_len];
+ filenames[left_len] = tmp;
+ ++left_len;
+ }
+ }
+ filenames[len - 1] = filenames[left_len];
+ filenames[left_len] = pivot;
+
+ SortFilenames(filenames, left_len);
+ SortFilenames(&filenames[left_len + 1], len - left_len - 1);
+}
+
+const char *I_NextGlob(glob_t *glob)
+{
+ const char *result;
+
+ // In unsorted mode we just return the filenames as we read
+ // them back from the system API.
+ if ((glob->flags & GLOB_FLAG_SORTED) == 0)
+ {
+ free(glob->last_filename);
+ glob->last_filename = NextGlob(glob);
+ return glob->last_filename;
+ }
+
+ // In sorted mode we read the whole list of filenames into memory,
+ // sort them and return them one at a time.
+ if (glob->next_index < 0)
+ {
+ ReadAllFilenames(glob);
+ SortFilenames(glob->filenames, glob->filenames_len);
+ }
+ if (glob->next_index >= glob->filenames_len)
+ {
+ return NULL;
+ }
+ result = glob->filenames[glob->next_index];
+ ++glob->next_index;
+ return result;
}
#else /* #ifdef NO_DIRENT_IMPLEMENTATION */
--- a/src/i_glob.h
+++ b/src/i_glob.h
@@ -20,6 +20,7 @@
#define __I_GLOB__
#define GLOB_FLAG_NOCASE 0x01
+#define GLOB_FLAG_SORTED 0x02
typedef struct glob_s glob_t;
--- a/src/i_musicpack.c
+++ b/src/i_musicpack.c
@@ -947,7 +947,7 @@
}
// Load all music packs, by searching for .cfg files.
- glob = I_StartGlob(musicdir, "*.cfg", GLOB_FLAG_NOCASE);
+ glob = I_StartGlob(musicdir, "*.cfg", GLOB_FLAG_SORTED|GLOB_FLAG_NOCASE);
for (;;)
{
path = I_NextGlob(glob);