Added callback APIs and ripped up the internals everywhere to use them.
authorRyan C. Gordon <icculus@icculus.org>
Wed, 29 Sep 2004 06:09:29 +0000
changeset 657 dad3b5c307a9
parent 656 d2c34dbf2c83
child 658 1981818c6170
Added callback APIs and ripped up the internals everywhere to use them.
CHANGELOG
TODO
archivers/dir.c
archivers/grp.c
archivers/hog.c
archivers/mix.c
archivers/mvl.c
archivers/qpak.c
archivers/wad.c
archivers/zip.c
physfs.c
physfs.h
physfs_internal.h
platform/beos.cpp
platform/macclassic.c
platform/os2.c
platform/pocketpc.c
platform/posix.c
platform/skeleton.c
platform/unix.c
platform/win32.c
--- a/CHANGELOG	Wed Sep 29 06:03:44 2004 +0000
+++ b/CHANGELOG	Wed Sep 29 06:09:29 2004 +0000
@@ -2,6 +2,13 @@
  * CHANGELOG.
  */
 
+09292004 - Every API that can return a list of strings can now use a
+           callback mechanism if the application wants to do it's own
+           allocation or handling on a per-item basis. The guts of those
+           APIs that create string lists now use the callbacks themselves to
+           build the lists, too. The callback functionality goes all the way
+           down to the archivers and platform drivers where appropriate, which
+           cleans things up and simplifies some internal tasks very nicely.
 09262004 - Did the same thing to FileHandles than I did to DirHandles, but
            this triggered massive tweaking in physfs.c. A lot of code got
            little cleanups, which was nice. Less malloc pressure, too, since
--- a/TODO	Wed Sep 29 06:03:44 2004 +0000
+++ b/TODO	Wed Sep 29 06:09:29 2004 +0000
@@ -22,7 +22,6 @@
 - Cygwin should use unix/posix and not win32 platform code.
 - Add "mount points"
 - Expose the archiver registration mechanism to the outside world.
-- Set up a mechanism for file enumeration that employs a callback.
 - Allow the application to provide allocation services.
 - Find some way to relax or remove the security model for external tools.
 - Non-blocking I/O
@@ -41,7 +40,6 @@
 - Deprecate PHYSFS_setSaneConfig and move it to extras?
 - (Re)move the profiling code in physfs.c.
 - Why is physfsrwops.c cut-and-pasted into the ruby bindings?
-- Get rid of addToLinkedStringList
 - Replace code from SDL...
 - MIX grabs all archives that no other archivers claim.
 - MIX enumerates files as hash values.
--- a/archivers/dir.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/dir.c	Wed Sep 29 06:09:29 2004 +0000
@@ -29,9 +29,9 @@
 static int DIR_fileClose(fvoid *opaque);
 static int DIR_isArchive(const char *filename, int forWriting);
 static void *DIR_openArchive(const char *name, int forWriting);
-static LinkedStringList *DIR_enumerateFiles(dvoid *opaque,
-                                            const char *dname,
-                                            int omitSymLinks);
+static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int DIR_exists(dvoid *opaque, const char *name);
 static int DIR_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int DIR_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -165,17 +165,16 @@
 } /* DIR_openArchive */
 
 
-static LinkedStringList *DIR_enumerateFiles(dvoid *opaque,
-                                            const char *dname,
-                                            int omitSymLinks)
+static void DIR_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
     char *d = __PHYSFS_platformCvtToDependent((char *)opaque, dname, NULL);
-    LinkedStringList *retval;
-
-    BAIL_IF_MACRO(d == NULL, NULL, NULL);
-    retval = __PHYSFS_platformEnumerateFiles(d, omitSymLinks);
-    free(d);
-    return(retval);
+    if (d != NULL)
+    {
+        __PHYSFS_platformEnumerateFiles(d, omitSymLinks, cb, callbackdata);
+        free(d);
+    } /* if */
 } /* DIR_enumerateFiles */
 
 
--- a/archivers/grp.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/grp.c	Wed Sep 29 06:09:29 2004 +0000
@@ -72,9 +72,9 @@
 static int GRP_fileClose(fvoid *opaque);
 static int GRP_isArchive(const char *filename, int forWriting);
 static void *GRP_openArchive(const char *name, int forWriting);
-static LinkedStringList *GRP_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int GRP_exists(dvoid *opaque, const char *name);
 static int GRP_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int GRP_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -359,23 +359,21 @@
 } /* GRP_openArchive */
 
 
-static LinkedStringList *GRP_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+static void GRP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
-    GRPinfo *info = (GRPinfo *) opaque;
-    GRPentry *entry = info->entries;
-    LinkedStringList *retval = NULL, *p = NULL;
-    PHYSFS_uint32 max = info->entryCount;
-    PHYSFS_uint32 i;
+    /* no directories in GRP files. */
+    if (*dname != '\0')
+    {
+        GRPinfo *info = (GRPinfo *) opaque;
+        GRPentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
 
-    /* no directories in GRP files. */
-    BAIL_IF_MACRO(*dirname != '\0', ERR_NOT_A_DIR, NULL);
-
-    for (i = 0; i < max; i++, entry++)
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, entry->name, -1);
-
-    return(retval);
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, entry->name);
+    } /* if */
 } /* GRP_enumerateFiles */
 
 
--- a/archivers/hog.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/hog.c	Wed Sep 29 06:09:29 2004 +0000
@@ -86,9 +86,9 @@
 static int HOG_fileClose(fvoid *opaque);
 static int HOG_isArchive(const char *filename, int forWriting);
 static void *HOG_openArchive(const char *name, int forWriting);
-static LinkedStringList *HOG_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int HOG_exists(dvoid *opaque, const char *name);
 static int HOG_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int HOG_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -398,23 +398,21 @@
 } /* HOG_openArchive */
 
 
-static LinkedStringList *HOG_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+static void HOG_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
-    HOGinfo *info = ((HOGinfo *) opaque);
-    HOGentry *entry = info->entries;
-    LinkedStringList *retval = NULL, *p = NULL;
-    PHYSFS_uint32 max = info->entryCount;
-    PHYSFS_uint32 i;
+    /* no directories in HOG files. */
+    if (*dname != '\0')
+    {
+        HOGinfo *info = (HOGinfo *) opaque;
+        HOGentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
 
-    /* no directories in HOG files. */
-    BAIL_IF_MACRO(*dirname != '\0', ERR_NOT_A_DIR, NULL);
-
-    for (i = 0; i < max; i++, entry++)
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, entry->name, -1);
-
-    return(retval);
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, entry->name);
+    } /* if */
 } /* HOG_enumerateFiles */
 
 
--- a/archivers/mix.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/mix.c	Wed Sep 29 06:09:29 2004 +0000
@@ -91,9 +91,9 @@
 static int MIX_fileClose(fvoid *opaque);
 static int MIX_isArchive(const char *filename, int forWriting);
 static void *MIX_openArchive(const char *name, int forWriting);
-static LinkedStringList *MIX_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void MIX_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 static int MIX_exists(dvoid *opaque, const char *name);
 static int MIX_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int MIX_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -354,23 +354,24 @@
 } /* MIX_openArchive */
 
 
-static LinkedStringList *MIX_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+static void MIX_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
-    LinkedStringList *retval = NULL, *p = NULL;
-    MIXinfo *info = (MIXinfo*) opaque;
-    MIXentry *entry = info->entry;
-    int i;
-    char buffer[32];
+    /* no directories in MIX files. */
+    if (*dirname != '\0')
+    {
+        MIXinfo *info = (MIXinfo*) opaque;
+        MIXentry *entry = info->entry;
+        int i;
+        char buffer[32];
     
-    for (i = 0; i < info->header.num_files; i++, entry++)
-    {
-        sprintf(buffer, "%X", entry->hash);
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, buffer, -1);
-    } /* for */
-
-    return(retval);
+        for (i = 0; i < info->header.num_files; i++, entry++)
+        {
+            sprintf(buffer, "%X", entry->hash);
+            cb(callbackdata, buffer);
+        } /* for */
+    } /* if */
 } /* MIX_enumerateFiles */
 
 
--- a/archivers/mvl.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/mvl.c	Wed Sep 29 06:09:29 2004 +0000
@@ -75,9 +75,9 @@
 static int MVL_fileClose(fvoid *opaque);
 static int MVL_isArchive(const char *filename, int forWriting);
 static void *MVL_openArchive(const char *name, int forWriting);
-static LinkedStringList *MVL_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int MVL_exists(dvoid *opaque, const char *name);
 static int MVL_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int MVL_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -356,23 +356,21 @@
 } /* MVL_openArchive */
 
 
-static LinkedStringList *MVL_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+static void MVL_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
-    MVLinfo *info = ((MVLinfo *) opaque);
-    MVLentry *entry = info->entries;
-    LinkedStringList *retval = NULL, *p = NULL;
-    PHYSFS_uint32 max = info->entryCount;
-    PHYSFS_uint32 i;
+    /* no directories in MVL files. */
+    if (*dname != '\0')
+    {
+        MVLinfo *info = ((MVLinfo *) opaque);
+        MVLentry *entry = info->entries;
+        PHYSFS_uint32 max = info->entryCount;
+        PHYSFS_uint32 i;
 
-    /* no directories in MVL files. */
-    BAIL_IF_MACRO(*dirname != '\0', ERR_NOT_A_DIR, NULL);
-
-    for (i = 0; i < max; i++, entry++)
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, entry->name, -1);
-
-    return(retval);
+        for (i = 0; i < max; i++, entry++)
+            cb(callbackdata, entry->name);
+    } /* if */
 } /* MVL_enumerateFiles */
 
 
--- a/archivers/qpak.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/qpak.c	Wed Sep 29 06:09:29 2004 +0000
@@ -89,9 +89,9 @@
 static int QPAK_fileClose(fvoid *opaque);
 static int QPAK_isArchive(const char *filename, int forWriting);
 static void *QPAK_openArchive(const char *name, int forWriting);
-static LinkedStringList *QPAK_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_StringCallback cb,
+                                void *callbackdata);
 static int QPAK_exists(dvoid *opaque, const char *name);
 static int QPAK_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int QPAK_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -443,19 +443,36 @@
 } /* qpak_find_start_of_dir */
 
 
-static LinkedStringList *QPAK_enumerateFiles(dvoid *opaque,
-                                             const char *dirname,
-                                             int omitSymLinks)
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_StringCallback cb, void *callbackdata,
+                           const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = alloca(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, newstr);
+} /* doEnumCallback */
+
+
+static void QPAK_enumerateFiles(dvoid *opaque, const char *dname,
+                                int omitSymLinks, PHYSFS_StringCallback cb,
+                                void *callbackdata)
 {
     QPAKinfo *info = ((QPAKinfo *) opaque);
-    LinkedStringList *retval = NULL, *p = NULL;
     PHYSFS_sint32 dlen, dlen_inc, max, i;
 
-    i = qpak_find_start_of_dir(info, dirname, 0);
-    BAIL_IF_MACRO(i == -1, ERR_NO_SUCH_FILE, NULL);
+    i = qpak_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
 
-    dlen = strlen(dirname);
-    if ((dlen > 0) && (dirname[dlen - 1] == '/')) /* ignore trailing slash. */
+    dlen = strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
         dlen--;
 
     dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
@@ -466,13 +483,13 @@
         char *ptr;
         PHYSFS_sint32 ln;
         char *e = info->entries[i].name;
-        if ((dlen) && ((QPAK_strncmp(e, dirname, dlen)) || (e[dlen] != '/')))
+        if ((dlen) && ((QPAK_strncmp(e, dname, dlen)) || (e[dlen] != '/')))
             break;  /* past end of this dir; we're done. */
 
         add = e + dlen_inc;
         ptr = strchr(add, '/');
         ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, add, ln);
+        doEnumCallback(cb, callbackdata, add, ln);
         ln += dlen_inc;  /* point past entry to children... */
 
         /* increment counter and skip children of subdirs... */
@@ -483,8 +500,6 @@
                 break;
         } /* while */
     } /* while */
-
-    return(retval);
 } /* QPAK_enumerateFiles */
 
 
--- a/archivers/wad.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/wad.c	Wed Sep 29 06:09:29 2004 +0000
@@ -91,9 +91,9 @@
 static int WAD_fileClose(fvoid *opaque);
 static int WAD_isArchive(const char *filename, int forWriting);
 static void *WAD_openArchive(const char *name, int forWriting);
-static LinkedStringList *WAD_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int WAD_exists(dvoid *opaque, const char *name);
 static int WAD_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int WAD_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -386,45 +386,39 @@
 } /* WAD_openArchive */
 
 
-static LinkedStringList *WAD_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+static void WAD_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
     WADinfo *info = ((WADinfo *) opaque);
     WADentry *entry = info->entries;
-    LinkedStringList *retval = NULL, *p = NULL;
     PHYSFS_uint32 max = info->entryCount;
     PHYSFS_uint32 i;
+    const char *name;
     char *sep;
 
-    if (dirname[0] == 0)
+    if (*dname == '\0')  /* root directory enumeration? */
     {
         for (i = 0; i < max; i++, entry++)
         {
-            if (strchr(entry->name, '/') == NULL)
-            {
-                retval = __PHYSFS_addToLinkedStringList(retval, &p,
-                                                        entry->name, -1);
-            } /* if */
+            name = entry->name;
+            if (strchr(name, '/') == NULL)
+                cb(callbackdata, name);
         } /* for */
     } /* if */
     else
     {
         for (i = 0; i < max; i++, entry++)
         {
-            sep = strchr(entry->name, '/');
+            name = entry->name;
+            sep = strchr(name, '/');
             if (sep != NULL)
             {
-                if (strncmp(dirname, entry->name, (sep-entry->name)) == 0)
-                {
-                    retval = __PHYSFS_addToLinkedStringList(retval, &p,
-                                                            sep + 1, -1);
-                } /* if */
+                if (strncmp(dname, name, (sep - name)) == 0)
+                    cb(callbackdata, sep + 1);
             } /* if */
         } /* for */
     } /* else */
-    
-    return(retval);
 } /* WAD_enumerateFiles */
 
 
--- a/archivers/zip.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/archivers/zip.c	Wed Sep 29 06:09:29 2004 +0000
@@ -127,9 +127,9 @@
 static int ZIP_fileClose(fvoid *opaque);
 static int ZIP_isArchive(const char *filename, int forWriting);
 static void *ZIP_openArchive(const char *name, int forWriting);
-static LinkedStringList *ZIP_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks);
+static void ZIP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata);
 static int ZIP_exists(dvoid *opaque, const char *name);
 static int ZIP_isDirectory(dvoid *opaque, const char *name, int *fileExists);
 static int ZIP_isSymLink(dvoid *opaque, const char *name, int *fileExists);
@@ -1235,19 +1235,36 @@
 } /* zip_find_start_of_dir */
 
 
-static LinkedStringList *ZIP_enumerateFiles(dvoid *opaque,
-                                            const char *dirname,
-                                            int omitSymLinks)
+/*
+ * Moved to seperate function so we can use alloca then immediately throw
+ *  away the allocated stack space...
+ */
+static void doEnumCallback(PHYSFS_StringCallback cb, void *callbackdata,
+                           const char *str, PHYSFS_sint32 ln)
+{
+    char *newstr = alloca(ln + 1);
+    if (newstr == NULL)
+        return;
+
+    memcpy(newstr, str, ln);
+    newstr[ln] = '\0';
+    cb(callbackdata, newstr);
+} /* doEnumCallback */
+
+
+static void ZIP_enumerateFiles(dvoid *opaque, const char *dname,
+                               int omitSymLinks, PHYSFS_StringCallback cb,
+                               void *callbackdata)
 {
     ZIPinfo *info = ((ZIPinfo *) opaque);
-    LinkedStringList *retval = NULL, *p = NULL;
     PHYSFS_sint32 dlen, dlen_inc, max, i;
 
-    i = zip_find_start_of_dir(info, dirname, 0);
-    BAIL_IF_MACRO(i == -1, ERR_NO_SUCH_FILE, NULL);
+    i = zip_find_start_of_dir(info, dname, 0);
+    if (i == -1)  /* no such directory. */
+        return;
 
-    dlen = strlen(dirname);
-    if ((dlen > 0) && (dirname[dlen - 1] == '/')) /* ignore trailing slash. */
+    dlen = strlen(dname);
+    if ((dlen > 0) && (dname[dlen - 1] == '/')) /* ignore trailing slash. */
         dlen--;
 
     dlen_inc = ((dlen > 0) ? 1 : 0) + dlen;
@@ -1255,7 +1272,7 @@
     while (i < max)
     {
         char *e = info->entries[i].name;
-        if ((dlen) && ((strncmp(e, dirname, dlen) != 0) || (e[dlen] != '/')))
+        if ((dlen) && ((strncmp(e, dname, dlen) != 0) || (e[dlen] != '/')))
             break;  /* past end of this dir; we're done. */
 
         if ((omitSymLinks) && (zip_entry_is_symlink(&info->entries[i])))
@@ -1265,7 +1282,7 @@
             char *add = e + dlen_inc;
             char *ptr = strchr(add, '/');
             PHYSFS_sint32 ln = (PHYSFS_sint32) ((ptr) ? ptr-add : strlen(add));
-            retval = __PHYSFS_addToLinkedStringList(retval, &p, add, ln);
+            doEnumCallback(cb, callbackdata, add, ln);
             ln += dlen_inc;  /* point past entry to children... */
 
             /* increment counter and skip children of subdirs... */
@@ -1277,8 +1294,6 @@
             } /* while */
         } /* else */
     } /* while */
-
-    return(retval);
 } /* ZIP_enumerateFiles */
 
 
--- a/physfs.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/physfs.c	Wed Sep 29 06:09:29 2004 +0000
@@ -189,6 +189,54 @@
 
 /* functions ... */
 
+typedef struct
+{
+    char **list;
+    PHYSFS_uint32 size;
+    const char *errorstr;
+} EnumStringListCallbackData;
+
+static void enumStringListCallback(void *data, const char *str)
+{
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    if (pecd->errorstr)
+        return;
+
+    ptr = realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+    {
+        pecd->errorstr = ERR_OUT_OF_MEMORY;
+        pecd->list[pecd->size] = NULL;
+        PHYSFS_freeList(pecd->list);
+        return;
+    } /* if */
+
+    strcpy(newstr, str);
+    pecd->list[pecd->size] = newstr;
+    pecd->size++;
+} /* enumStringListCallback */
+
+
+static char **doEnumStringList(void (*func)(PHYSFS_StringCallback, void *))
+{
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) malloc(sizeof (char *));
+    BAIL_IF_MACRO(ecd.list == NULL, ERR_OUT_OF_MEMORY, NULL);
+    func(enumStringListCallback, &ecd);
+    BAIL_IF_MACRO(ecd.errorstr != NULL, ecd.errorstr, NULL);
+    ecd.list[ecd.size] = NULL;
+    return(ecd.list);
+} /* doEnumStringList */
+
+
 static void __PHYSFS_bubble_sort(void *a, PHYSFS_uint32 lo, PHYSFS_uint32 hi,
                          int (*cmpfn)(void *, PHYSFS_uint32, PHYSFS_uint32),
                          void (*swapfn)(void *, PHYSFS_uint32, PHYSFS_uint32))
@@ -838,7 +886,6 @@
 {
     FileHandle *i;
     FileHandle *next = NULL;
-    FileHandle *h;
 
     for (i = *list; i != NULL; i = next)
     {
@@ -937,10 +984,16 @@
 
 char **PHYSFS_getCdRomDirs(void)
 {
-    return(__PHYSFS_platformDetectAvailableCDs());
+    return(doEnumStringList(__PHYSFS_platformDetectAvailableCDs));
 } /* PHYSFS_getCdRomDirs */
 
 
+void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback callback, void *data)
+{
+    __PHYSFS_platformDetectAvailableCDs(callback, data);
+} /* PHYSFS_getCdRomDirsCallback */
+
+
 const char *PHYSFS_getBaseDir(void)
 {
     return(baseDir);   /* this is calculated in PHYSFS_init()... */
@@ -1060,42 +1113,21 @@
 
 char **PHYSFS_getSearchPath(void)
 {
-    int count = 1;
-    int x;
+    return(doEnumStringList(PHYSFS_getSearchPathCallback));
+} /* PHYSFS_getSearchPath */
+
+
+void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback callback, void *data)
+{
     DirHandle *i;
-    char **retval;
 
     __PHYSFS_platformGrabMutex(stateLock);
 
     for (i = searchPath; i != NULL; i = i->next)
-        count++;
-
-    retval = (char **) malloc(sizeof (char *) * count);
-    BAIL_IF_MACRO_MUTEX(!retval, ERR_OUT_OF_MEMORY, stateLock, NULL);
-    count--;
-    retval[count] = NULL;
-
-    for (i = searchPath, x = 0; x < count; i = i->next, x++)
-    {
-        retval[x] = (char *) malloc(strlen(i->dirName) + 1);
-        if (retval[x] == NULL)  /* this is friggin' ugly. */
-        {
-            while (x > 0)
-            {
-                x--;
-                free(retval[x]);
-            } /* while */
-
-            free(retval);
-            BAIL_MACRO_MUTEX(ERR_OUT_OF_MEMORY, stateLock, NULL);
-        } /* if */
-
-        strcpy(retval[x], i->dirName);
-    } /* for */
+        callback(data, i->dirName);
 
     __PHYSFS_platformReleaseMutex(stateLock);
-    return(retval);
-} /* PHYSFS_getSearchPath */
+} /* PHYSFS_getSearchPathCallback */
 
 
 int PHYSFS_setSaneConfig(const char *organization, const char *appName,
@@ -1441,7 +1473,7 @@
     return(retval);
 } /* PHYSFS_getRealDir */
 
-
+#if 0
 static int countList(LinkedStringList *list)
 {
     int retval = 0;
@@ -1529,34 +1561,114 @@
         newList = next;
     } /* while */
 } /* interpolateStringLists */
+#endif
+
+
+static int locateInStringList(const char *str,
+                              char **list,
+                              PHYSFS_uint32 *pos)
+{
+    PHYSFS_uint32 hi = *pos - 1;
+    PHYSFS_uint32 lo = 0;
+    PHYSFS_uint32 i = hi / 2;
+    int cmp;
+
+    while (hi != lo)
+    {
+        cmp = strcmp(list[i], str);
+        if (cmp == 0)  /* it's in the list already. */
+            return(1);
+        else if (cmp < 0)
+            hi = i;
+        else
+            lo = i;
+        i = lo + ((hi - lo) / 2);
+    } /* while */
+
+    /* hi == lo, check it in case it's the match... */
+    cmp = strcmp(list[lo], str);
+    if (cmp == 0)
+        return(1);
+
+    /* not in the list, set insertion point... */
+    *pos = (cmp < 0) ? lo : lo + 1;
+    return(0);
+} /* locateInStringList */
+
+
+static void enumFilesCallback(void *data, const char *str)
+{
+    PHYSFS_uint32 pos;
+    void *ptr;
+    char *newstr;
+    EnumStringListCallbackData *pecd = (EnumStringListCallbackData *) data;
+
+    /*
+     * See if file is in the list already, and if not, insert it in there
+     *  alphabetically...
+     */
+    pos = pecd->size;
+    if (pos > 0)
+    {
+        if (locateInStringList(str, pecd->list, &pos))
+            return;  /* already in the list. */
+    } /* if */
+
+    ptr = realloc(pecd->list, (pecd->size + 2) * sizeof (char *));
+    newstr = malloc(strlen(str) + 1);
+    if (ptr != NULL)
+        pecd->list = (char **) ptr;
+
+    if ((ptr == NULL) || (newstr == NULL))
+        return;  /* better luck next time. */
+
+    strcpy(newstr, str);
+
+    if (pos != pecd->size)
+    {
+        memmove(&pecd->list[pos+1], &pecd->list[pos],
+                 sizeof (char *) * ((pecd->size) - pos));
+    } /* if */
+
+    pecd->list[pos] = newstr;
+    pecd->size++;
+} /* enumFilesCallback */
 
 
 char **PHYSFS_enumerateFiles(const char *path)
 {
+    EnumStringListCallbackData ecd;
+    memset(&ecd, '\0', sizeof (ecd));
+    ecd.list = (char **) malloc(sizeof (char *));
+    BAIL_IF_MACRO(ecd.list == NULL, ERR_OUT_OF_MEMORY, NULL);
+    PHYSFS_enumerateFilesCallback(path, enumFilesCallback, &ecd);
+    ecd.list[ecd.size] = NULL;
+    return(ecd.list);
+} /* PHYSFS_enumerateFiles */
+
+
+void PHYSFS_enumerateFilesCallback(const char *path,
+                                   PHYSFS_StringCallback callback,
+                                   void *data)
+{
     DirHandle *i;
-    char **retval = NULL;
-    LinkedStringList *rc;
-    LinkedStringList *finalList = NULL;
-    int omitSymLinks = !allowSymLinks;
-
-    BAIL_IF_MACRO(path == NULL, ERR_INVALID_ARGUMENT, NULL);
+    int noSyms;
+
+    if ((path == NULL) || (callback == NULL))
+        return;
+
     while (*path == '/')
         path++;
 
     __PHYSFS_platformGrabMutex(stateLock);
+    noSyms = !allowSymLinks;
     for (i = searchPath; i != NULL; i = i->next)
     {
         if (__PHYSFS_verifySecurity(i, path, 0))
-        {
-            rc = i->funcs->enumerateFiles(i->opaque, path, omitSymLinks);
-            interpolateStringLists(&finalList, rc);
-        } /* if */
+            i->funcs->enumerateFiles(i->opaque, path, noSyms, callback, data);
     } /* for */
     __PHYSFS_platformReleaseMutex(stateLock);
-
-    retval = convertStringListToPhysFSList(finalList);
-    return(retval);
-} /* PHYSFS_enumerateFiles */
+} /* PHYSFS_enumerateFilesCallback */
 
 
 int PHYSFS_exists(const char *fname)
@@ -2077,6 +2189,5 @@
     return(&allocator);
 } /* __PHYFS_getAllocator */
 
-
 /* end of physfs.c ... */
 
--- a/physfs.h	Wed Sep 29 06:03:44 2004 +0000
+++ b/physfs.h	Wed Sep 29 06:09:29 2004 +0000
@@ -1874,6 +1874,22 @@
 __EXPORT__ int PHYSFS_setAllocator(PHYSFS_Allocator *allocator);
 
 
+/*
+ * it is not safe to call physfs functions in these callbacks, as they may
+ *  be holding non recursive mutexes.
+ */
+/* !!! FIXME: comment! */
+typedef void (*PHYSFS_StringCallback)(void *data, const char *);
+
+__EXPORT__ void PHYSFS_getCdRomDirsCallback(PHYSFS_StringCallback c, void *d);
+
+__EXPORT__ void PHYSFS_getSearchPathCallback(PHYSFS_StringCallback c, void *d);
+
+__EXPORT__ void PHYSFS_enumerateFilesCallback(const char *dir,
+                                              PHYSFS_StringCallback c,
+                                              void *d);
+
+
 /* Everything above this line is part of the PhysicsFS 2.0 API. */
 
 
--- a/physfs_internal.h	Wed Sep 29 06:03:44 2004 +0000
+++ b/physfs_internal.h	Wed Sep 29 06:09:29 2004 +0000
@@ -979,17 +979,18 @@
     void *(*openArchive)(const char *name, int forWriting);
 
         /*
-         * Returns a list of all files in dirname. Each element of this list
-         *  (and its "str" field) will be deallocated with the system's free()
-         *  function by the caller, so be sure to explicitly malloc() each
-         *  chunk. Omit symlinks if (omitSymLinks) is non-zero.
-         * If you have a memory failure, return as much as you can.
-         *  This dirname is in platform-independent notation.
+         * List all files in (dirname). Each file is passed to (callback),
+         *  where a copy is made if appropriate, so you should dispose of
+         *  it properly upon return from the callback.
+         * You should omit symlinks if (omitSymLinks) is non-zero.
+         * If you have a failure, report as much as you can.
+         *  (dirname) is in platform-independent notation.
          */
-    LinkedStringList *(*enumerateFiles)(dvoid *opaque,
-                                        const char *dirname,
-                                        int omitSymLinks);
-
+    void (*enumerateFiles)(dvoid *opaque,
+                            const char *dirname,
+                            int omitSymLinks,
+                            PHYSFS_StringCallback callback,
+                            void *callbackdata);
 
         /*
          * Returns non-zero if filename can be opened for reading.
@@ -1445,10 +1446,13 @@
 int __PHYSFS_platformClose(void *opaque);
 
 /*
- * Platform implementation of PHYSFS_getCdRomDirs()...
- *  See physfs.h. The retval should be freeable via PHYSFS_freeList().
+ * Platform implementation of PHYSFS_getCdRomDirsCallback()...
+ *  CD directories are discovered and reported to the callback one at a time.
+ *  Pointers passed to the callback are assumed to be invalid to the
+ *  application after the callback returns, so you can free them or whatever.
+ *  Callback does not assume results will be sorted in any meaningful way.
  */
-char **__PHYSFS_platformDetectAvailableCDs(void);
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data);
 
 /*
  * Calculate the base dir, if your platform needs special consideration.
@@ -1559,8 +1563,10 @@
  *  uses platform-independent notation. Note that ".", "..", and other
  *  metaentries should always be ignored.
  */
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks);
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata);
 
 
 /*
--- a/platform/beos.cpp	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/beos.cpp	Wed Sep 29 06:09:29 2004 +0000
@@ -47,20 +47,6 @@
 } /* __PHYSFS_platformDeinit */
 
 
-
-/* caller needs to malloc() mntpnt, and expect us to free() it. */
-static void addDisc(char *mntpnt, char ***discs, int *disccount)
-{
-    char **tmp = (char **) realloc(*discs, sizeof (char *) * (*disccount + 1));
-    if (tmp)
-    {
-        tmp[*disccount - 1] = mntpnt;
-        *discs = tmp;
-        (*disccount)++;
-    } /* if */
-} /* addDisc */
-
-
 static char *getMountPoint(const char *devname)
 {
     BVolumeRoster mounts;
@@ -101,10 +87,10 @@
      * This function is lifted from Simple Directmedia Layer (SDL):
      *  http://www.libsdl.org/
      */
-static void tryDir(const char *dirname, char ***discs, int *disccount)
+static void tryDir(const char *d, PHYSFS_StringCallback callback, void *data)
 {
     BDirectory dir;
-    dir.SetTo(dirname);
+    dir.SetTo(d);
     if (dir.InitCheck() != B_NO_ERROR)
         return;
 
@@ -127,7 +113,7 @@
         if (entry.IsDirectory())
         {
             if (strcmp(e.name, "floppy") != 0)
-                tryDir(name, discs, disccount);
+                tryDir(name, callback, data);
         } /* if */
 
         else
@@ -147,7 +133,10 @@
                         {
                             char *mntpnt = getMountPoint(name);
                             if (mntpnt != NULL)
-                                addDisc(mntpnt, discs, disccount);
+                            {
+                                callback(data, mntpnt);
+                                free(mntpnt);  /* !!! FIXME: lose this malloc! */
+                            } /* if */
                         } /* if */
                     } /* if */
                 } /* if */
@@ -159,14 +148,9 @@
 } /* tryDir */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;  /* We count the NULL entry. */
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-    tryDir("/dev/disk", &retval, &cd_count);
-    retval[cd_count - 1] = NULL;
-    return(retval);
+    tryDir("/dev/disk", cb, data);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
--- a/platform/macclassic.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/macclassic.c	Wed Sep 29 06:09:29 2004 +0000
@@ -177,17 +177,12 @@
  * CD detection code is borrowed from Apple Technical Q&A DV18.
  *  http://developer.apple.com/qa/dv/dv18.html
  */
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
+    
     DriverGestaltParam pb;
     DrvQEl *dqp;
     OSErr status;
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;
-
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-
-    *retval = NULL;
 
     pb.csCode = kDriverGestaltCode;
     pb.driverGestaltSelector = kdgDeviceType;
@@ -201,6 +196,7 @@
         if ((status == noErr) && (pb.driverGestaltResponse == kdgCDType))
         {
             Str63 volName;
+            size_t size;
             HParamBlockRec hpbr;
             memset(&hpbr, '\0', sizeof (HParamBlockRec));
             hpbr.volumeParam.ioNamePtr = volName;
@@ -208,27 +204,15 @@
             hpbr.volumeParam.ioVolIndex = 0;
             if (PBHGetVInfoSync(&hpbr) == noErr)
             {
-                char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-                if (tmp)
-                {
-                    char *str = (char *) malloc(volName[0] + 1);
-                    retval = tmp;
-                    if (str != NULL)
-                    {
-                        memcpy(str, &volName[1], volName[0]);
-                        str[volName[0]] = '\0';
-                        retval[cd_count-1] = str;
-                        cd_count++;
-                    } /* if */
-                } /* if */
+                size = (size_t) volName[0];  /* convert to ASCIZ string... */
+                memmove(&volName[0], &volName[1], size);
+                volName[size] = '\0';
+                cb(data, volName);
             } /* if */
         } /* if */
 
         dqp = (DrvQEl *) dqp->qLink;
     } /* while */
-
-    retval[cd_count - 1] = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
@@ -577,10 +561,12 @@
 } /* __PHYSFS_platformTimeslice */
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+/* returns int so we can use BAIL*MACRO... */
+static int macClassicEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
-    LinkedStringList *ret = NULL, *p = NULL;
     UInt16 i;
     UInt16 max;
     FSSpec spec;
@@ -606,6 +592,7 @@
 
     for (i = 1; i <= max; i++)
     {
+        size_t size;
         FSSpec aliasspec;
         Boolean alias = 0;
         Boolean folder = 0;
@@ -629,10 +616,20 @@
             continue;
 
         /* still here? Add it to the list. */
-        ret = __PHYSFS_addToLinkedStringList(ret, &p, (const char *) &str255[1], str255[0]);
+        size = (size_t) str255[0];  /* (convert to ASCIZ string...) */
+        memmove(&str255[0], &str255[1], size);
+        str255[size] = '\0';
+        callback(callbackdata, str255);
     } /* for */
+} /* macClassicEnumerateFiles */
 
-    return(ret);
+
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
+{
+    macClassicEnumerateFiles(dirname, omitSymLinks, callback, callbackdata);
 } /* __PHYSFS_platformEnumerateFiles */
 
 
--- a/platform/os2.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/os2.c	Wed Sep 29 06:09:29 2004 +0000
@@ -254,20 +254,12 @@
 } /* is_cdrom_drive */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    ULONG dummy;
-    ULONG drivemap;
+    ULONG dummy = 0;
+    ULONG drivemap = 0;
     ULONG i, bit;
-    APIRET rc;
-    char **retval;
-    PHYSFS_uint32 cd_count = 1;   /* we count the NULL entry. */
-
-    retval = (char **) malloc(sizeof (char *));
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-    *retval = NULL;
-
-    rc = DosQueryCurrentDisk(&dummy, &drivemap);
+    APIRET rc = DosQueryCurrentDisk(&dummy, &drivemap);
     BAIL_IF_MACRO(os2err(rc) != NO_ERROR, NULL, retval);
 
     for (i = 0, bit = 1; i < 26; i++, bit <<= 1)
@@ -276,27 +268,12 @@
         {
             if ((is_cdrom_drive(i)) && (disc_is_inserted(i)))
             {
-                char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-                if (tmp)
-                {
-                    char *str = (char *) malloc(4);
-                    retval = tmp;
-                    retval[cd_count - 1] = str;
-                    if (str)
-                    {
-                        str[0] = ('A' + i);
-                        str[1] = ':';
-                        str[2] = '\\';
-                        str[3] = '\0';
-                        cd_count++;
-                    } /* if */
-                } /* if */
+                char drive[4] = "x:\\";
+                drive[0] = ('A' + i);
+                cb(data, drive);
             } /* if */
         } /* if */
     } /* for */
-
-    retval[cd_count - 1] = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
@@ -417,11 +394,12 @@
 } /* __PHYSFS_platformCvtToDependent */
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
     char spec[CCHMAXPATH];
-    LinkedStringList *ret = NULL, *p = NULL;
     FILEFINDBUF3 fb;
     HDIR hdir = HDIR_CREATE;
     ULONG count = 1;
@@ -439,13 +417,12 @@
     while (count == 1)
     {
         if ((strcmp(fb.achName, ".") != 0) && (strcmp(fb.achName, "..") != 0))
-            ret = __PHYSFS_addToLinkedStringList(ret, &p, fb.achName, -1);
+            callback(callbackdata, fb.achName);
 
         DosFindNext(hdir, &fb, sizeof (fb), &count);
     } /* while */
 
     DosFindClose(hdir);
-    return(ret);
 } /* __PHYSFS_platformEnumerateFiles */
 
 
--- a/platform/pocketpc.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/pocketpc.c	Wed Sep 29 06:09:29 2004 +0000
@@ -67,52 +67,53 @@
 
 static char *UnicodeToAsc(const wchar_t *w_str)
 {
-    char *str=NULL;
+    char *str = NULL;
 
-    if(w_str!=NULL)
+    if (w_str != NULL)
     {
-    int len=wcslen(w_str)+1;
-    str=(char *)malloc(len);
+        int len = wcslen(w_str) + 1;
+        str = (char *) malloc(len);
 
-    if(WideCharToMultiByte(CP_ACP,0,w_str,-1,str,len,NULL,NULL)==0)
-    {    //Conversion failed
-        free(str);
+        if (WideCharToMultiByte(CP_ACP,0,w_str,-1,str,len,NULL,NULL) == 0)
+        {    /*Conversion failed */
+            free(str);
+            return(NULL);
+        } /* if */
+        else
+        {    /* Conversion successful */
+            return(str);
+        } /* else */
+    } /* if */
+
+    else
+    {    /* Given NULL string */
         return NULL;
     }
-    else
-    {    //Conversion successful
-        return(str);
-    }
+} /* UnicodeToAsc */
 
-    }
-    else
-    {    //Given NULL string
-    return NULL;
-    }
-}
 
 static wchar_t *AscToUnicode(const char *str)
 {
-    wchar_t *w_str=NULL;
-    if(str!=NULL)
+    wchar_t *w_str = NULL;
+    if (str != NULL)
     {
-    int len=strlen(str)+1;
-    w_str=(wchar_t *)malloc(sizeof(wchar_t)*len);
-    if(MultiByteToWideChar(CP_ACP,0,str,-1,w_str,len)==0)
-    {
-        free(w_str);
-        return NULL;
-    }
+        int len = strlen(str) + 1;
+        w_str = (wchar_t *) malloc(sizeof (wchar_t) * len);
+        if (MultiByteToWideChar(CP_ACP,0,str,-1,w_str,len) == 0)
+        {
+            free(w_str);
+            return(NULL);
+        } /* if */
+        else
+        {
+            return(w_str);
+        } /* else */
+    } /* if */
     else
     {
-        return(w_str);
-    }
-    }
-    else
-    {
-    return NULL;
-    }
-}
+        return(NULL);
+    } /* else */
+} /* AscToUnicode */
 
 
 static char *getExePath()
@@ -177,9 +178,9 @@
 } /* __PHYSFS_platformDeinit */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
+    /* no-op on this platform. */
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
@@ -293,12 +294,11 @@
 } /* __PHYSFS_platformTimeslice */
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
-    LinkedStringList *retval = NULL;
-    LinkedStringList *l = NULL;
-    LinkedStringList *prev = NULL;
     HANDLE dir;
     WIN32_FIND_DATA ent;
     char *SearchPath;
@@ -328,43 +328,29 @@
     free(w_SearchPath);
     free(SearchPath);
 
-    if(dir == INVALID_HANDLE_VALUE)
-    {
-    return NULL;
-    }
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
 
     do
     {
+        const char *str;
+
         if (wcscmp(ent.cFileName, L".") == 0)
             continue;
 
         if (wcscmp(ent.cFileName, L"..") == 0)
             continue;
 
-        l = (LinkedStringList *) malloc(sizeof (LinkedStringList));
-        if (l == NULL)
+        /* !!! FIXME: avoid malloc in UnicodeToAsc? */
+        str = UnicodeToAsc(ent.cFileName);
+        if (str == NULL)
             break;
 
-    l->str=UnicodeToAsc(ent.cFileName);
-
-        if (l->str == NULL)
-        {
-            free(l);
-            break;
-        }
-
-
-        if (retval == NULL)
-            retval = l;
-        else
-            prev->next = l;
-
-        prev = l;
-        l->next = NULL;
+        callback(callbackdata, str);
+        free(str);
     } while (FindNextFile(dir, &ent) != 0);
 
     FindClose(dir);
-    return(retval);
 } /* __PHYSFS_platformEnumerateFiles */
 
 
@@ -381,7 +367,6 @@
     strcpy(retval,path);
 
     return(retval);
-
 } /* __PHYSFS_platformRealPath */
 
 
--- a/platform/posix.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/posix.c	Wed Sep 29 06:09:29 2004 +0000
@@ -225,22 +225,24 @@
 
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
-    LinkedStringList *retval = NULL, *p = NULL;
     DIR *dir;
     struct dirent *ent;
     int bufsize = 0;
     char *buf = NULL;
     int dlen = 0;
 
-    if (omitSymLinks)
+    if (omitSymLinks)  /* !!! FIXME: this malloc sucks. */
     {
         dlen = strlen(dirname);
         bufsize = dlen + 256;
         buf = (char *) malloc(bufsize);
-        BAIL_IF_MACRO(buf == NULL, ERR_OUT_OF_MEMORY, NULL);
+        if (buf == NULL)
+            return;
         strcpy(buf, dirname);
         if (buf[dlen - 1] != '/')
         {
@@ -255,7 +257,7 @@
     {
         if (buf != NULL)
             free(buf);
-        BAIL_IF_MACRO(1, strerror(errno), NULL);
+        return;
     } /* if */
 
     while ((ent = readdir(dir)) != NULL)
@@ -284,14 +286,13 @@
                 continue;
         } /* if */
 
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, ent->d_name, -1);
+        callback(callbackdata, ent->d_name);
     } /* while */
 
     if (buf != NULL)
         free(buf);
 
     closedir(dir);
-    return(retval);
 } /* __PHYSFS_platformEnumerateFiles */
 
 
--- a/platform/skeleton.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/skeleton.c	Wed Sep 29 06:09:29 2004 +0000
@@ -32,9 +32,8 @@
 } /* __PHYSFS_platformDeinit */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
@@ -105,10 +104,11 @@
 } /* __PHYSFS_platformTimeslice */
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
-    BAIL_MACRO(ERR_NOT_IMPLEMENTED, NULL);
 } /* __PHYSFS_platformEnumerateFiles */
 
 
--- a/platform/unix.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/unix.c	Wed Sep 29 06:09:29 2004 +0000
@@ -76,12 +76,8 @@
 #ifdef PHYSFS_NO_CDROM_SUPPORT
 
 /* Stub version for platforms without CD-ROM support. */
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    char **retval = (char **) malloc(sizeof (char *));
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-    *retval = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 
@@ -166,13 +162,11 @@
 } /* darwinIsMountedDisc */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
     const char *devPrefix = "/dev/";
     int prefixLen = strlen(devPrefix);
     mach_port_t masterPort = 0;
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;  /* We count the NULL entry. */
     struct statfs *mntbufp;
     int i, mounts;
 
@@ -191,38 +185,17 @@
 
         dev += prefixLen;
         if (darwinIsMountedDisc(dev, masterPort))
-        {
-            char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-            if (tmp)
-            {
-                retval = tmp;
-                retval[cd_count - 1] = (char *) malloc(strlen(mnt) + 1);
-                if (retval[cd_count - 1])
-                {
-                    strcpy(retval[cd_count - 1], mnt);
-                    cd_count++;
-                } /* if */
-            } /* if */
-        } /* if */
+            cb(data, mnt);
     } /* for */
-
-    retval[cd_count - 1] = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 #elif (defined PHYSFS_HAVE_SYS_UCRED_H)
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;  /* We count the NULL entry. */
+    int i;
     struct statfs *mntbufp = NULL;
-    int mounts;
-    int i;
-
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-
-    mounts = getmntinfo(&mntbufp, MNT_WAIT);
+    int mounts = getmntinfo(&mntbufp, MNT_WAIT);
 
     for (i = 0; i < mounts; i++)
     {
@@ -236,40 +209,23 @@
         /* add other mount types here */
 
         if (add_it)
-        {
-            char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-            if (tmp)
-            {
-                retval = tmp;
-                retval[cd_count - 1] = (char *)
-                                malloc(strlen(mntbufp[i].f_mntonname) + 1);
-                if (retval[cd_count - 1])
-                {
-                    strcpy(retval[cd_count - 1], mntbufp[i].f_mntonname);
-                    cd_count++;
-                } /* if */
-            } /* if */
-        } /* if */
+            cb(data, mntbufp[i].f_mntonname);
     } /* for */
-
-    retval[cd_count - 1] = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 #elif (defined PHYSFS_HAVE_MNTENT_H)
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;  /* We count the NULL entry. */
     FILE *mounts = NULL;
     struct mntent *ent = NULL;
 
-    BAIL_IF_MACRO(retval == NULL, ERR_OUT_OF_MEMORY, NULL);
-
-    *retval = NULL;
     mounts = setmntent("/etc/mtab", "r");
-    BAIL_IF_MACRO(mounts == NULL, ERR_IO_ERROR, retval);
+    if (mounts == NULL)
+    {
+        __PHYSFS_setError(ERR_IO_ERROR);
+        return;
+    } /* if */
 
     while ( (ent = getmntent(mounts)) != NULL )
     {
@@ -280,25 +236,11 @@
         /* add other mount types here */
 
         if (add_it)
-        {
-            char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-            if (tmp)
-            {
-                retval = tmp;
-                retval[cd_count-1] = (char *) malloc(strlen(ent->mnt_dir) + 1);
-                if (retval[cd_count - 1])
-                {
-                    strcpy(retval[cd_count - 1], ent->mnt_dir);
-                    cd_count++;
-                } /* if */
-            } /* if */
-        } /* if */
+            cb(data, ent->mnt_dir);
     } /* while */
 
     endmntent(mounts);
 
-    retval[cd_count - 1] = NULL;
-    return(retval);
 } /* __PHYSFS_platformDetectAvailableCDs */
 
 #endif
--- a/platform/win32.c	Wed Sep 29 06:03:44 2004 +0000
+++ b/platform/win32.c	Wed Sep 29 06:09:29 2004 +0000
@@ -268,33 +268,17 @@
 } /* mediaInDrive */
 
 
-char **__PHYSFS_platformDetectAvailableCDs(void)
+void __PHYSFS_platformDetectAvailableCDs(PHYSFS_StringCallback cb, void *data)
 {
-    char **retval = (char **) malloc(sizeof (char *));
-    int cd_count = 1;  /* We count the NULL entry. */
     char drive_str[4] = "x:\\";
-
-    for (drive_str[0] = 'A'; drive_str[0] <= 'Z'; drive_str[0]++)
+    char ch;
+    for (ch = 'A'; ch <= 'Z'; ch++)
     {
+        drive_str[0] = ch;
         if (GetDriveType(drive_str) == DRIVE_CDROM && mediaInDrive(drive_str))
-        {
-            char **tmp = realloc(retval, sizeof (char *) * (cd_count + 1));
-            if (tmp)
-            {
-                retval = tmp;
-                retval[cd_count - 1] = (char *) malloc(4);
-                if (retval[cd_count - 1])
-                {
-                    strcpy(retval[cd_count - 1], drive_str);
-                    cd_count++;
-                } /* if */
-            } /* if */
-        } /* if */
+            cb(data, drive_str);
     } /* for */
-
-    retval[cd_count - 1] = NULL;
-    return(retval);
-} /* __PHYSFS_detectAvailableCDs */
+} /* __PHYSFS_platformDetectAvailableCDs */
 
 
 char *__PHYSFS_platformCalcBaseDir(const char *argv0)
@@ -454,18 +438,20 @@
 } /* __PHYSFS_platformTimeslice */
 
 
-LinkedStringList *__PHYSFS_platformEnumerateFiles(const char *dirname,
-                                                  int omitSymLinks)
+void __PHYSFS_platformEnumerateFiles(const char *dirname,
+                                     int omitSymLinks,
+                                     PHYSFS_StringCallback callback,
+                                     void *callbackdata)
 {
-    LinkedStringList *retval = NULL, *p = NULL;
     HANDLE dir;
     WIN32_FIND_DATA ent;
+    size_t len = strlen(dirname);
     char *SearchPath;
-    size_t len = strlen(dirname);
 
     /* Allocate a new string for path, maybe '\\', "*", and NULL terminator */
     SearchPath = (char *) alloca(len + 3);
-    BAIL_IF_MACRO(SearchPath == NULL, ERR_OUT_OF_MEMORY, NULL);
+    if (SearchPath == NULL)
+        return;
 
     /* Copy current dirname */
     strcpy(SearchPath, dirname);
@@ -481,11 +467,8 @@
     strcat(SearchPath, "*");
 
     dir = FindFirstFile(SearchPath, &ent);
-    BAIL_IF_MACRO
-    (
-        dir == INVALID_HANDLE_VALUE,
-        win32strerror(), NULL
-    );
+    if (dir == INVALID_HANDLE_VALUE)
+        return;
 
     do
     {
@@ -495,11 +478,10 @@
         if (strcmp(ent.cFileName, "..") == 0)
             continue;
 
-        retval = __PHYSFS_addToLinkedStringList(retval, &p, ent.cFileName, -1);
+        callback(callbackdata, ent.cFileName);
     } while (FindNextFile(dir, &ent) != 0);
 
     FindClose(dir);
-    return(retval);
 } /* __PHYSFS_platformEnumerateFiles */