From 4d4b99bc56915c31fdd88790ac329d125a75a308 Mon Sep 17 00:00:00 2001 From: havoc Date: Tue, 16 Dec 2003 15:26:28 +0000 Subject: [PATCH] rewrote FS_Search, hopefully it will work better now, and it now matches directories inside paks (in other words: listing sound/* will tell you about sound/plats and sound/whatever.wav, this is mainly to be consistent with filesystem directories), it is also no longer two-pass (although simple the two-pass approach was dangerous if the two listings came out different), and it now sorts the listing 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 | 3 + filematch.c | 29 ++++----- fs.c | 167 ++++++++++++++++++++++++++++------------------------ 3 files changed, 105 insertions(+), 94 deletions(-) diff --git a/common.h b/common.h index 1ba72a8a..818c54ba 100644 --- 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); diff --git a/filematch.c b/filematch.c index e3e35c80..e4a81fdb 100644 --- a/filematch.c +++ b/filematch.c @@ -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 43e7d499..3143e7ba 100644 --- 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); } -- 2.39.2