rewrote FS_Search, hopefully it will work better now, and it now matches directories...
authorhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 16 Dec 2003 15:26:28 +0000 (15:26 +0000)
committerhavoc <havoc@d7cf8633-e32d-0410-b094-e92efae38249>
Tue, 16 Dec 2003 15:26:28 +0000 (15:26 +0000)
rewrote much of matchpattern, now handles path separators specially, and uses a much better approach to handling the * wildcard (no longer looks for the following character, simply tries multiple matchpattern calls until it hits a path separator or gets a match)

git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3735 d7cf8633-e32d-0410-b094-e92efae38249

common.h
filematch.c
fs.c

index 1ba72a8..818c54b 100644 (file)
--- a/common.h
+++ b/common.h
@@ -192,6 +192,9 @@ typedef struct stringlist_s
 } stringlist_t;
 
 int matchpattern(char *in, char *pattern, int caseinsensitive);
+stringlist_t *stringlistappend(stringlist_t *current, char *text);
+void stringlistfree(stringlist_t *current);
+stringlist_t *stringlistsort(stringlist_t *start);
 stringlist_t *listdirectory(char *path);
 void freedirectory(stringlist_t *list);
 
index e3e35c8..e4a81fd 100644 (file)
@@ -10,8 +10,10 @@ int matchpattern(char *in, char *pattern, int caseinsensitive)
        {
                switch (*pattern)
                {
+               case 0:
+                       return 1; // end of pattern
                case '?': // match any single character
-                       if (!*in)
+                       if (*in == 0 || *in == '/' || *in == '\\' || *in == ':')
                                return 0; // no match
                        in++;
                        pattern++;
@@ -19,23 +21,16 @@ int matchpattern(char *in, char *pattern, int caseinsensitive)
                case '*': // match anything until following string
                        if (!*in)
                                return 1; // match
-                       while (*pattern == '*')
-                               pattern++;
-                       if (*pattern == '?')
-                       {
-                               // *? (weird)
-                               break;
-                       }
-                       else if (*pattern)
-                       {
-                               // *text (typical)
-                               while (*in && *in != *pattern)
-                                       in++;
-                       }
-                       else
+                       pattern++;
+                       while (*in)
                        {
-                               // *null (* at end of pattern)
-                               return 1;
+                               if (*in == '/' || *in == '\\' || *in == ':')
+                                       break;
+                               // see if pattern matches at this offset
+                               if (matchpattern(in, pattern, caseinsensitive))
+                                       return 1;
+                               // nope, advance to next offset
+                               in++;
                        }
                        break;
                default:
diff --git a/fs.c b/fs.c
index 43e7d49..3143e7b 100644 (file)
--- a/fs.c
+++ b/fs.c
@@ -1856,11 +1856,12 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
        fssearch_t *search;
        searchpath_t *searchpath;
        pack_t *pak;
-       int i, basepathlength, numfiles, numchars, step;
-       stringlist_t *dir, *dirfile;
+       int i, basepathlength, numfiles, numchars;
+       stringlist_t *dir, *dirfile, *liststart, *listcurrent, *listtemp;
        const char *slash, *backslash, *colon, *separator;
        char *basepath;
        char netpath[MAX_OSPATH];
+       char temp[MAX_OSPATH];
 
        while(!strncmp(pattern, "./", 2))
                pattern += 2;
@@ -1868,94 +1869,123 @@ fssearch_t *FS_Search(const char *pattern, int caseinsensitive, int quiet)
                pattern += 2;
 
        search = NULL;
-       numfiles = 0;
-       numchars = 0;
+       liststart = NULL;
+       listcurrent = NULL;
+       listtemp = NULL;
        slash = strrchr(pattern, '/');
        backslash = strrchr(pattern, '\\');
        colon = strrchr(pattern, ':');
-       separator = slash;
+       separator = pattern;
+       if (separator < slash)
+               separator = slash;
        if (separator < backslash)
                separator = backslash;
        if (separator < colon)
                separator = colon;
-       if (separator)
-               basepathlength = separator + 1 - pattern;
-       else
-               basepathlength = 0;
+       basepathlength = separator - pattern;
        basepath = Z_Malloc(basepathlength + 1);
        if (basepathlength)
                memcpy(basepath, pattern, basepathlength);
        basepath[basepathlength] = 0;
 
-       for (step = 0;step < 2;step++)
+       // search through the path, one element at a time
+       for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
        {
-               // search through the path, one element at a time
-               for (searchpath = fs_searchpaths;searchpath;searchpath = searchpath->next)
+               // is the element a pak file?
+               if (searchpath->pack)
                {
-                       // is the element a pak file?
-                       if (searchpath->pack)
+                       // look through all the pak file elements
+                       pak = searchpath->pack;
+                       for (i = 0;i < pak->numfiles;i++)
                        {
-                               // look through all the pak file elements
-                               pak = searchpath->pack;
-                               for (i = 0;i < pak->numfiles;i++)
+                               strcpy(temp, pak->files[i].name);
+                               while (temp[0])
                                {
-                                       if (matchpattern(pak->files[i].name, (char *)pattern, caseinsensitive || pak->ignorecase))
+                                       if (matchpattern(temp, (char *)pattern, true))
                                        {
-                                               if (search)
+                                               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+                                                       if (!strcmp(listtemp->text, temp))
+                                                               break;
+                                               if (listtemp == NULL)
                                                {
-                                                       search->filenames[numfiles] = search->filenamesbuffer + numchars;
-                                                       strcpy(search->filenames[numfiles], pak->files[i].name);
+                                                       listcurrent = stringlistappend(listcurrent, temp);
+                                                       if (liststart == NULL)
+                                                               liststart = listcurrent;
+                                                       if (!quiet)
+                                                               Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, temp);
                                                }
-                                               numfiles++;
-                                               numchars += strlen(pak->files[i].name) + 1;
-                                               if (!quiet)
-                                                       Sys_Printf("SearchPackFile: %s : %s\n", pak->filename, pak->files[i].name);
                                        }
+                                       // strip off one path element at a time until empty
+                                       // this way directories are added to the listing if they match the pattern
+                                       slash = strrchr(temp, '/');
+                                       backslash = strrchr(temp, '\\');
+                                       colon = strrchr(temp, ':');
+                                       separator = temp;
+                                       if (separator < slash)
+                                               separator = slash;
+                                       if (separator < backslash)
+                                               separator = backslash;
+                                       if (separator < colon)
+                                               separator = colon;
+                                       *((char *)separator) = 0;
                                }
                        }
-                       else
+               }
+               else
+               {
+                       // get a directory listing and look at each name
+                       snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, basepath);
+                       if ((dir = listdirectory(netpath)))
                        {
-                               // get a directory listing and look at each name
-                               snprintf(netpath, sizeof (netpath), "%s/%s", searchpath->filename, pattern);
-                               if ((dir = listdirectory(netpath)))
+                               for (dirfile = dir;dirfile;dirfile = dirfile->next)
                                {
-                                       for (dirfile = dir;dirfile;dirfile = dirfile->next)
+                                       memcpy(temp, basepath, basepathlength);
+                                       strcpy(temp + basepathlength, dirfile->text);
+                                       if (matchpattern(temp, (char *)pattern, true))
                                        {
-                                               if (matchpattern(dirfile->text, (char *)pattern + basepathlength, caseinsensitive))
+                                               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+                                                       if (!strcmp(listtemp->text, temp))
+                                                               break;
+                                               if (listtemp == NULL)
                                                {
-                                                       if (search)
-                                                       {
-                                                               search->filenames[numfiles] = search->filenamesbuffer + numchars;
-                                                               memcpy(search->filenames[numfiles], basepath, basepathlength);
-                                                               strcpy(search->filenames[numfiles] + basepathlength, dirfile->text);
-                                                       }
-                                                       numfiles++;
-                                                       numchars += basepathlength + strlen(dirfile->text) + 1;
+                                                       listcurrent = stringlistappend(listcurrent, temp);
+                                                       if (liststart == NULL)
+                                                               liststart = listcurrent;
                                                        if (!quiet)
-                                                               Sys_Printf("SearchDirFile: %s\n", dirfile->text);
+                                                               Sys_Printf("SearchDirFile: %s\n", temp);
                                                }
                                        }
-                                       freedirectory(dir);
                                }
+                               freedirectory(dir);
                        }
                }
+       }
 
-               if (step == 0)
+       if (liststart)
+       {
+               liststart = stringlistsort(liststart);
+               numfiles = 0;
+               numchars = 0;
+               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
                {
-                       if (!numfiles || !numchars)
-                       {
-                               Z_Free(basepath);
-                               return NULL;
-                       }
-                       // prepare for second pass (allocate the memory to fill in)
-                       search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
-                       search->filenames = (char **)((char *)search + sizeof(fssearch_t));
-                       search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
-                       search->numfilenames = numfiles;
-                       // these are used for tracking as the buffers are written on the second pass
-                       numfiles = 0;
-                       numchars = 0;
+                       numfiles++;
+                       numchars += strlen(listtemp->text) + 1;
                }
+               search = Z_Malloc(sizeof(fssearch_t) + numchars + numfiles * sizeof(char *));
+               search->filenames = (char **)((char *)search + sizeof(fssearch_t));
+               search->filenamesbuffer = (char *)((char *)search + sizeof(fssearch_t) + numfiles * sizeof(char *));
+               search->numfilenames = numfiles;
+               numfiles = 0;
+               numchars = 0;
+               for (listtemp = liststart;listtemp;listtemp = listtemp->next)
+               {
+                       search->filenames[numfiles] = search->filenamesbuffer + numchars;
+                       strcpy(search->filenames[numfiles], listtemp->text);
+                       numfiles++;
+                       numchars += strlen(listtemp->text) + 1;
+               }
+               if (liststart)
+                       stringlistfree(liststart);
        }
 
        Z_Free(basepath);
@@ -2044,21 +2074,11 @@ void FS_Dir_f(void)
                Con_Printf("usage:\ndir [path/pattern]\n");
                return;
        }
+       strcpy(pattern, "*");
        if (Cmd_Argc() == 2)
-       {
                snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
-               if (!FS_ListDirectory(pattern, true))
-               {
-                       snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
-                       if (!FS_ListDirectory(pattern, true))
-                               Con_Printf("No files found.\n");
-               }
-       }
-       else
-       {
-               if (!FS_ListDirectory("*", true))
-                       Con_Printf("No files found.\n");
-       }
+       if (!FS_ListDirectory(pattern, true))
+               Con_Printf("No files found.\n");
 }
 
 void FS_Ls_f(void)
@@ -2069,16 +2089,9 @@ void FS_Ls_f(void)
                Con_Printf("usage:\nls [path/pattern]\n");
                return;
        }
+       strcpy(pattern, "*");
        if (Cmd_Argc() == 2)
-       {
                snprintf(pattern, sizeof(pattern), "%s", Cmd_Argv(1));
-               if (!FS_ListDirectory(pattern, false))
-               {
-                       snprintf(pattern, sizeof(pattern), "%s/*", Cmd_Argv(1));
-                       FS_ListDirectory(pattern, false);
-               }
-       }
-       else
-               FS_ListDirectory("*", false);
+       FS_ListDirectory(pattern, false);
 }