X-Git-Url: http://git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=filematch.c;h=e06439614c2174927168128adf5b1fcbe8fa268d;hp=9ac649134b57beb5d40dce1eb8b2185ba787e3fe;hb=f847004b9818defbfd4bf15fe7b891fee2706079;hpb=65c62180df611f0010ad6da4ed294904c0acdecd diff --git a/filematch.c b/filematch.c index 9ac64913..e0643961 100644 --- a/filematch.c +++ b/filematch.c @@ -1,45 +1,69 @@ -#include "quakedef.h" +#ifdef WIN32 +#include +#else +#include +#endif + +#include "darkplaces.h" + +// LadyHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such... -// LordHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such... +int matchpattern(const char *in, const char *pattern, int caseinsensitive) +{ + return matchpattern_with_separator(in, pattern, caseinsensitive, "/\\:", false); +} -int matchpattern(char *in, char *pattern) +// wildcard_least_one: if true * matches 1 or more characters +// if false * matches 0 or more characters +int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qbool wildcard_least_one) { + int c1, c2; while (*pattern) { switch (*pattern) { + case 0: + return 1; // end of pattern case '?': // match any single character - if (!*in) + if (*in == 0 || strchr(separators, *in)) return 0; // no match in++; pattern++; break; case '*': // match anything until following string - if (!*in) - return 1; // match - while (*pattern == '*') - pattern++; - if (*pattern == '?') - { - // *? (weird) - break; - } - else if (*pattern) + if(wildcard_least_one) { - // *text (typical) - while (*in && *in != *pattern) - in++; + if (*in == 0 || strchr(separators, *in)) + return 0; // no match + in++; } - else + pattern++; + while (*in) { - // *null (* at end of pattern) - return 1; + if (strchr(separators, *in)) + break; + // see if pattern matches at this offset + if (matchpattern_with_separator(in, pattern, caseinsensitive, separators, wildcard_least_one)) + return 1; + // nope, advance to next offset + in++; } break; default: if (*in != *pattern) - return 0; // no match + { + if (!caseinsensitive) + return 0; // no match + c1 = *in; + if (c1 >= 'A' && c1 <= 'Z') + c1 += 'a' - 'A'; + c2 = *pattern; + if (c2 >= 'A' && c2 <= 'Z') + c2 += 'a' - 'A'; + if (c1 != c2) + return 0; // no match + } in++; pattern++; break; @@ -50,118 +74,150 @@ int matchpattern(char *in, char *pattern) return 1; // success } -// a little chained strings system -stringlist_t *stringlistappend(stringlist_t *current, char *text) +// a little strings system +void stringlistinit(stringlist_t *list) { - stringlist_t *newitem; - newitem = Z_Malloc(strlen(text) + 1 + sizeof(stringlist_t)); - newitem->next = NULL; - newitem->text = (char *)(newitem + 1); - strcpy(newitem->text, text); - if (current) - current->next = newitem; - return newitem; + memset(list, 0, sizeof(*list)); } -void stringlistfree(stringlist_t *current) +void stringlistfreecontents(stringlist_t *list) { - stringlist_t *next; - while (current) + int i; + for (i = 0;i < list->numstrings;i++) { - next = current->next; - Z_Free(current); - current = next; + if (list->strings[i]) + Z_Free(list->strings[i]); + list->strings[i] = NULL; } + list->numstrings = 0; + list->maxstrings = 0; + if (list->strings) + Z_Free(list->strings); + list->strings = NULL; +} + +void stringlistappend(stringlist_t *list, const char *text) +{ + size_t textlen; + char **oldstrings; + + if (list->numstrings >= list->maxstrings) + { + oldstrings = list->strings; + list->maxstrings += 4096; + list->strings = (char **) Z_Malloc(list->maxstrings * sizeof(*list->strings)); + if (list->numstrings) + memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings)); + if (oldstrings) + Z_Free(oldstrings); + } + textlen = strlen(text) + 1; + list->strings[list->numstrings] = (char *) Z_Malloc(textlen); + memcpy(list->strings[list->numstrings], text, textlen); + list->numstrings++; +} + +static int stringlistsort_cmp(const void *a, const void *b) +{ + return strcasecmp(*(const char **)a, *(const char **)b); } -stringlist_t *stringlistsort(stringlist_t *start) +void stringlistsort(stringlist_t *list, qbool uniq) { - int notdone; - stringlist_t *current, *previous, *temp2, *temp3, *temp4; - notdone = 1; - while (notdone) + int i, j; + if(list->numstrings < 1) + return; + qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp); + if(uniq) { - current = start; - notdone = 0; - previous = NULL; - while (current && current->next) + // i: the item to read + // j: the item last written + for (i = 1, j = 0; i < list->numstrings; ++i) { - if (strcmp(current->text, current->next->text) > 0) - { - // current is greater than next - notdone = 1; - temp2 = current->next; - temp3 = current; - temp4 = current->next->next; - if (previous) - previous->next = temp2; - else - start = temp2; - temp2->next = temp3; - temp3->next = temp4; - break; - } - previous = current; - current = current->next; + char *save; + if(!strcasecmp(list->strings[i], list->strings[j])) + continue; + ++j; + save = list->strings[j]; + list->strings[j] = list->strings[i]; + list->strings[i] = save; + } + for(i = j+1; i < list->numstrings; ++i) + { + if (list->strings[i]) + Z_Free(list->strings[i]); } + list->numstrings = j+1; } - return start; } // operating system specific code +static void adddirentry(stringlist_t *list, const char *path, const char *name) +{ + if (strcmp(name, ".") && strcmp(name, "..")) + { + char temp[MAX_OSPATH]; + dpsnprintf( temp, sizeof( temp ), "%s%s", path, name ); + stringlistappend(list, temp); + } +} #ifdef WIN32 -#include -stringlist_t *listdirectory(char *path) +void listdirectory(stringlist_t *list, const char *basepath, const char *path) { char pattern[4096]; - struct _finddata_t n_file; - long hFile; - stringlist_t *start, *current; - strcpy(pattern, path); - strcat(pattern, "\\*"); + WIN32_FIND_DATA n_file; + HANDLE hFile; + strlcpy (pattern, basepath, sizeof(pattern)); + strlcat (pattern, path, sizeof (pattern)); + strlcat (pattern, "*", sizeof (pattern)); // ask for the directory listing handle - hFile = _findfirst(pattern, &n_file); - if(hFile != -1) - { - // start a new chain with the the first name - start = current = stringlistappend(NULL, n_file.name); - // iterate through the directory - while (_findnext(hFile, &n_file) == 0) - current = stringlistappend(current, n_file.name); - _findclose(hFile); - // sort the list alphanumerically - return stringlistsort(start); - } - else - return NULL; + hFile = FindFirstFile(pattern, &n_file); + if(hFile == INVALID_HANDLE_VALUE) + return; + do { + adddirentry(list, path, n_file.cFileName); + } while (FindNextFile(hFile, &n_file) != 0); + FindClose(hFile); } #else -#include -stringlist_t *listdirectory(char *path) +void listdirectory(stringlist_t *list, const char *basepath, const char *path) { + char fullpath[MAX_OSPATH]; DIR *dir; struct dirent *ent; - stringlist_t *start, *current; - dir = opendir(path); - if (!dir) - return NULL; - ent = readdir(dir); - if (!ent) + dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, path); +#ifdef __ANDROID__ + // SDL currently does not support listing assets, so we have to emulate + // it. We're using relative paths for assets, so that will do. + if (basepath[0] != '/') { - closedir(dir); - return NULL; + char listpath[MAX_OSPATH]; + qfile_t *listfile; + dpsnprintf(listpath, sizeof(listpath), "%sls.txt", fullpath); + char *buf = (char *) FS_SysLoadFile(listpath, tempmempool, true, NULL); + if (!buf) + return; + char *p = buf; + for (;;) + { + char *q = strchr(p, '\n'); + if (q == NULL) + break; + *q = 0; + adddirentry(list, path, p); + p = q + 1; + } + Mem_Free(buf); + return; } - start = current = stringlistappend(NULL, ent->d_name); - while((ent = readdir(dir))) - current = stringlistappend(current, ent->d_name); - closedir(dir); - // sort the list alphanumerically - return stringlistsort(start); -} #endif + dir = opendir(fullpath); + if (!dir) + return; -void freedirectory(stringlist_t *list) -{ - stringlistfree(list); + while ((ent = readdir(dir))) + adddirentry(list, path, ent->d_name); + closedir(dir); } +#endif