Improved globbing extra.
Fixed FIXMEs, improved documentation, updated for 2.1 API.
--- a/extras/globbing.c Sat Mar 28 17:51:10 2009 -0400
+++ b/extras/globbing.c Sat Mar 28 18:14:16 2009 -0400
@@ -4,8 +4,8 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#include <assert.h>
-#include "physfs.h"
#include "globbing.h"
/**
@@ -22,7 +22,7 @@
* NO WARRANTY.
*
* Unless otherwise stated, the rest of PhysicsFS falls under the zlib license.
- * Please see LICENSE.txt in the source's "docs" directory.
+ * Please see the file LICENSE.txt in the source's root directory.
*
* \author Ryan C. Gordon.
*/
@@ -87,28 +87,108 @@
return(*fnameptr == *wildptr);
} /* matchesPattern */
+typedef struct
+{
+ const PHYSFS_Allocator *allocator;
+ const char *wildcard;
+ int caseSensitive;
+ PHYSFS_EnumFilesCallback callback;
+ void *origData;
+} WildcardCallbackData;
+
+
+/*
+ * This callback sits between the enumerator and the enduser callback,
+ * filtering out files that don't match the wildcard pattern.
+ */
+static void wildcardCallback(void *_d, const char *origdir, const char *fname)
+{
+ const WildcardCallbackData *data = (const WildcardCallbackData *) _d;
+ if (matchesPattern(fname, data->wildcard, data->caseSensitive))
+ data->callback(data->origData, origdir, fname);
+} /* wildcardCallback */
+
+
+void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
+ const char *wildcard,
+ int caseSensitive,
+ PHYSFS_EnumFilesCallback c,
+ void *d)
+{
+ WildcardCallbackData data;
+ data.allocator = PHYSFS_getAllocator();
+ data.wildcard = wildcard;
+ data.caseSensitive = caseSensitive;
+ data.callback = c;
+ data.origData = d;
+ PHYSFS_enumerateFilesCallback(dir, wildcardCallback, &data);
+} /* PHYSFSEXT_enumerateFilesCallbackWildcard */
+
+
+void PHYSFSEXT_freeEnumeration(char **list)
+{
+ const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
+ int i;
+ if (list != NULL)
+ {
+ for (i = 0; list[i] != NULL; i++)
+ allocator->Free(list[i]);
+ allocator->Free(list);
+ } /* if */
+} /* PHYSFSEXT_freeEnumeration */
+
char **PHYSFSEXT_enumerateFilesWildcard(const char *dir, const char *wildcard,
int caseSensitive)
{
- char **rc = PHYSFS_enumerateFiles(dir);
- char **i = rc;
- char **j;
+ const PHYSFS_Allocator *allocator = PHYSFS_getAllocator();
+ char **list = PHYSFS_enumerateFiles(dir);
+ char **retval = NULL;
+ int totalmatches = 0;
+ int matches = 0;
+ char **i;
- while (*i != NULL)
+ for (i = list; *i != NULL; i++)
{
+ #if 0
+ printf("matchesPattern: '%s' vs '%s' (%s) ... %s\n", *i, wildcard,
+ caseSensitive ? "case" : "nocase",
+ matchesPattern(*i, wildcard, caseSensitive) ? "true" : "false");
+ #endif
if (matchesPattern(*i, wildcard, caseSensitive))
- i++;
- else
- {
- /* FIXME: This counts on physfs's allocation method not changing! */
- free(*i);
- for (j = i; *j != NULL; j++)
- j[0] = j[1];
- } /* else */
+ totalmatches++;
} /* for */
- return(rc);
+ retval = (char **) allocator->Malloc(sizeof (char *) * (totalmatches+1));
+ if (retval != NULL)
+ {
+ for (i = list; ((matches < totalmatches) && (*i != NULL)); i++)
+ {
+ if (matchesPattern(*i, wildcard, caseSensitive))
+ {
+ retval[matches] = (char *) allocator->Malloc(strlen(*i) + 1);
+ if (retval[matches] == NULL)
+ {
+ while (matches--)
+ allocator->Free(retval[matches]);
+ allocator->Free(retval);
+ retval = NULL;
+ break;
+ } /* if */
+ strcpy(retval[matches], *i);
+ matches++;
+ } /* if */
+ } /* for */
+
+ if (retval != NULL)
+ {
+ assert(totalmatches == matches);
+ retval[matches] = NULL;
+ } /* if */
+ } /* if */
+
+ PHYSFS_freeList(list);
+ return(retval);
} /* PHYSFSEXT_enumerateFilesWildcard */
@@ -148,7 +228,7 @@
} /* for */
printf("\n total %d files.\n\n", rc);
- PHYSFS_freeList(flist);
+ PHYSFSEXT_freeEnumeration(flist);
PHYSFS_deinit();
return(0);
--- a/extras/globbing.h Sat Mar 28 17:51:10 2009 -0400
+++ b/extras/globbing.h Sat Mar 28 18:14:16 2009 -0400
@@ -1,5 +1,7 @@
/** \file globbing.h */
+#include "physfs.h"
+
/**
* \mainpage PhysicsFS globbing
*
@@ -9,10 +11,10 @@
* locating matching entries.
*
* Usage: Set up PhysicsFS as you normally would, then use
- * PHYSFSEXT_enumerateFilesPattern() when enumerating files. This is just
+ * PHYSFSEXT_enumerateFilesWildcard() when enumerating files. This is just
* like PHYSFS_enumerateFiles(), but it returns a subset that matches your
- * wildcard pattern. You must call PHYSFS_freeList() on the results, just
- * like you would with PHYSFS_enumerateFiles().
+ * wildcard pattern. You must call PHYSFSEXT_freeEnumeration() on the results,
+ * just PHYSFS_enumerateFiles() would do with PHYSFS_freeList().
*
* License: this code is public domain. I make no warranty that it is useful,
* correct, harmless, or environmentally safe.
@@ -33,7 +35,7 @@
/**
* \fn char **PHYSFS_enumerateFilesWildcard(const char *dir, const char *wildcard, int caseSensitive)
- * \brief Get a file listing of a search path's directory.
+ * \brief Get a file listing of a search path's directory, filtered with a wildcard pattern.
*
* Matching directories are interpolated. That is, if "C:\mydir" is in the
* search path and contains a directory "savegames" that contains "x.sav",
@@ -63,15 +65,89 @@
* Wildcard strings can use the '*' and '?' characters, currently.
* Matches can be case-insensitive if you pass a zero for argument 3.
*
- * Don't forget to call PHYSFS_freeList() with the return value from this
- * function when you are done with it.
+ * Don't forget to call PHYSFSEXT_freeEnumerator() with the return value from
+ * this function when you are done with it. As we use PhysicsFS's allocator
+ * for this list, you must free it before calling PHYSFS_deinit().
+ * Do not use PHYSFS_freeList() on the returned value!
*
* \param dir directory in platform-independent notation to enumerate.
+ * \param wildcard Wildcard pattern to use for filtering.
+ * \param caseSensitive Zero for case-insensitive matching,
+ * non-zero for case-sensitive.
* \return Null-terminated array of null-terminated strings.
+ *
+ * \sa PHYSFSEXT_freeEnumeration
*/
__EXPORT__ char **PHYSFSEXT_enumerateFilesWildcard(const char *dir,
const char *wildcard,
int caseSensitive);
+/**
+ * \fn void PHYSFSEXT_freeEnumeration(char **list)
+ * \brief Free data returned by PHYSFSEXT_enumerateFilesWildcard
+ *
+ * Conceptually, this works like PHYSFS_freeList(), but is used with data
+ * returned by PHYSFSEXT_enumerateFilesWildcard() only. Be sure to call this
+ * on any returned data from that function before
+ *
+ * \param list Pointer previously returned by
+ * PHYSFSEXT_enumerateFilesWildcard(). It is safe to pass a
+ * NULL here.
+ *
+ * \sa PHYSFSEXT_enumerateFilesWildcard
+ */
+__EXPORT__ void PHYSFSEXT_freeEnumeration(char **list);
+
+
+/**
+ * \fn void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir, const char *wildcard, int caseSensitive, PHYSFS_EnumFilesCallback c, void *d);
+ * \brief Get a file listing of a search path's directory, filtered with a wildcard pattern, using an application-defined callback.
+ *
+ * This function is equivalent to PHYSFSEXT_enumerateFilesWildcard(). It
+ * reports file listings, filtered by a wildcard pattern.
+ *
+ * Unlike PHYSFS_enumerateFiles(), this function does not return an array.
+ * Rather, it calls a function specified by the application once per
+ * element of the search path:
+ *
+ * \code
+ *
+ * static void printDir(void *data, const char *origdir, const char *fname)
+ * {
+ * printf(" * We've got [%s] in [%s].\n", fname, origdir);
+ * }
+ *
+ * // ...
+ * PHYSFS_enumerateFilesCallbackWildcard("savegames","*.sav",0,printDir,NULL);
+ * \endcode
+ *
+ * Items sent to the callback are not guaranteed to be in any order whatsoever.
+ * There is no sorting done at this level, and if you need that, you should
+ * probably use PHYSFS_enumerateFilesWildcard() instead, which guarantees
+ * alphabetical sorting. This form reports whatever is discovered in each
+ * archive before moving on to the next. Even within one archive, we can't
+ * guarantee what order it will discover data. <em>Any sorting you find in
+ * these callbacks is just pure luck. Do not rely on it.</em> As this walks
+ * the entire list of archives, you may receive duplicate filenames.
+ *
+ * Wildcard strings can use the '*' and '?' characters, currently.
+ * Matches can be case-insensitive if you pass a zero for argument 3.
+ *
+ * \param dir Directory, in platform-independent notation, to enumerate.
+ * \param wildcard Wildcard pattern to use for filtering.
+ * \param caseSensitive Zero for case-insensitive matching,
+ * non-zero for case-sensitive.
+ * \param c Callback function to notify about search path elements.
+ * \param d Application-defined data passed to callback. Can be NULL.
+ *
+ * \sa PHYSFS_EnumFilesCallback
+ * \sa PHYSFS_enumerateFiles
+ */
+__EXPORT__ void PHYSFSEXT_enumerateFilesCallbackWildcard(const char *dir,
+ const char *wildcard,
+ int caseSensitive,
+ PHYSFS_EnumFilesCallback c,
+ void *d);
+
/* end of globbing.h ... */