ref: 419776fc7241e8337fe84e8777fad095e4b13945
parent: 7f03c58cbf63a63bb5a105e06f9f675bf60adfc7
author: Simon Howard <fraggle@soulsphere.org>
date: Sat Oct 27 13:50:14 EDT 2018
Add system-specific globbing API. Part of #1051.
--- a/configure.ac
+++ b/configure.ac
@@ -77,7 +77,7 @@
LDFLAGS="$LDFLAGS $SDL_LIBS ${SAMPLERATE_LIBS:-} ${PNG_LIBS:-}"
AC_CHECK_LIB(m, log)
-AC_CHECK_HEADERS([linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h])
+AC_CHECK_HEADERS([dirent.h linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h])
AC_CHECK_FUNCS(mmap ioperm)
AC_CHECK_DECLS([strcasecmp, strncasecmp], [], [], [[#include <strings.h>]])
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -65,6 +65,7 @@
gusconf.c gusconf.h \
i_cdmus.c i_cdmus.h \
i_endoom.c i_endoom.h \
+i_glob.c i_glob.h \
i_input.c i_input.h \
i_joystick.c i_joystick.h \
i_swap.h \
--- /dev/null
+++ b/src/i_glob.c
@@ -1,0 +1,148 @@
+//
+// Copyright(C) 2018 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+//
+// File globbing API. This allows the contents of the filesystem
+// to be interrogated.
+//
+
+// TODO: Merge win_opendir.[ch] into this file for MSVC implementation.
+
+#include <stdlib.h>
+
+#include "i_glob.h"
+#include "m_misc.h"
+#include "config.h"
+
+#ifdef HAVE_DIRENT_H
+#include "dirent.h"
+
+struct glob_s
+{
+ char *glob;
+ DIR *dir;
+ char *directory;
+ char *last_filename;
+};
+
+glob_t *I_StartGlob(const char *directory, const char *glob)
+{
+ glob_t *result;
+
+ result = malloc(sizeof(glob_t));
+ if (result == NULL)
+ {
+ return NULL;
+ }
+
+ result->dir = opendir(directory);
+ if (result->dir == NULL)
+ {
+ free(result);
+ return NULL;
+ }
+
+ result->directory = M_StringDuplicate(directory);
+ result->glob = M_StringDuplicate(glob);
+ result->last_filename = NULL;
+ return result;
+}
+
+void I_EndGlob(glob_t *glob)
+{
+ if (glob == NULL)
+ {
+ return;
+ }
+
+ free(glob->directory);
+ free(glob->last_filename);
+ free(glob->glob);
+ (void) closedir(glob->dir);
+ free(glob);
+}
+
+static boolean MatchesGlob(const char *name, const char *glob)
+{
+ while (*glob != '\0')
+ {
+ if (*glob == '*')
+ {
+ // To handle *-matching we skip past the * and recurse
+ // to check each subsequent character in turn. If none
+ // match then the whole match is a failure.
+ while (*name != '\0')
+ {
+ if (MatchesGlob(name, glob + 1))
+ {
+ return true;
+ }
+ ++name;
+ }
+ return false;
+ }
+ else if (*glob != '?' && *name != *glob)
+ {
+ // For normal characters the name must match the glob,
+ // but for ? we don't care what the character is.
+ return false;
+ }
+
+ ++name;
+ ++glob;
+ }
+
+ // Match successful when glob and name end at the same time.
+ return *name == '\0';
+}
+
+const char *I_NextGlob(glob_t *glob)
+{
+ struct dirent *de;
+
+ do
+ {
+ de = readdir(glob->dir);
+ if (de == NULL)
+ {
+ return NULL;
+ }
+ } while (de->d_type != DT_REG || !MatchesGlob(de->d_name, glob->glob));
+
+ // 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;
+}
+
+#else /* #ifndef HAVE_DIRENT_H */
+
+#warning No native implementation of file globbing.
+
+glob_t *I_StartGlob(const char *directory, const char *glob)
+{
+ return NULL;
+}
+
+void I_EndGlob(glob_t *glob)
+{
+}
+
+const char *I_NextGlob(glob_t *glob)
+{
+ return "";
+}
+
+#endif /* #ifndef HAVE_DIRENT_H */
+
--- /dev/null
+++ b/src/i_glob.h
@@ -1,0 +1,36 @@
+//
+// Copyright(C) 2018 Simon Howard
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// DESCRIPTION:
+// System specific file globbing interface.
+//
+
+
+#ifndef __I_GLOB__
+#define __I_GLOB__
+
+typedef struct glob_s glob_t;
+
+// Start reading a list of file paths from the given directory which match
+// the given glob pattern. I_EndGlob() must be called on completion.
+glob_t *I_StartGlob(const char *directory, const char *glob);
+
+// Finish reading file list.
+void I_EndGlob(glob_t *glob);
+
+// Read the name of the next globbed filename. NULL is returned if there
+// are no more found.
+const char *I_NextGlob(glob_t *glob);
+
+#endif
+