10 // LordHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such...
12 int matchpattern(const char *in, const char *pattern, int caseinsensitive)
14 return matchpattern_with_separator(in, pattern, caseinsensitive, "/\\:", false);
17 // wildcard_least_one: if true * matches 1 or more characters
18 // if false * matches 0 or more characters
19 int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qboolean wildcard_least_one)
27 return 1; // end of pattern
28 case '?': // match any single character
29 if (*in == 0 || strchr(separators, *in))
34 case '*': // match anything until following string
35 if(wildcard_least_one)
37 if (*in == 0 || strchr(separators, *in))
44 if (strchr(separators, *in))
46 // see if pattern matches at this offset
47 if (matchpattern_with_separator(in, pattern, caseinsensitive, separators, wildcard_least_one))
49 // nope, advance to next offset
59 if (c1 >= 'A' && c1 <= 'Z')
62 if (c2 >= 'A' && c2 <= 'Z')
73 return 0; // reached end of pattern but not end of input
77 // a little strings system
78 void stringlistinit(stringlist_t *list)
80 memset(list, 0, sizeof(*list));
83 void stringlistfreecontents(stringlist_t *list)
86 for (i = 0;i < list->numstrings;i++)
89 Z_Free(list->strings[i]);
90 list->strings[i] = NULL;
95 Z_Free(list->strings);
99 void stringlistappend(stringlist_t *list, const char *text)
104 if (list->numstrings >= list->maxstrings)
106 oldstrings = list->strings;
107 list->maxstrings += 4096;
108 list->strings = (char **) Z_Malloc(list->maxstrings * sizeof(*list->strings));
109 if (list->numstrings)
110 memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings));
114 textlen = strlen(text) + 1;
115 list->strings[list->numstrings] = (char *) Z_Malloc(textlen);
116 memcpy(list->strings[list->numstrings], text, textlen);
120 static int stringlistsort_cmp(const void *a, const void *b)
122 return strcasecmp(*(const char **)a, *(const char **)b);
125 void stringlistsort(stringlist_t *list, qboolean uniq)
128 if(list->numstrings < 1)
130 qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp);
133 // i: the item to read
134 // j: the item last written
135 for (i = 1, j = 0; i < list->numstrings; ++i)
138 if(!strcasecmp(list->strings[i], list->strings[j]))
141 save = list->strings[j];
142 list->strings[j] = list->strings[i];
143 list->strings[i] = save;
145 for(i = j+1; i < list->numstrings; ++i)
147 if (list->strings[i])
148 Z_Free(list->strings[i]);
150 list->numstrings = j+1;
154 // operating system specific code
155 static void adddirentry(stringlist_t *list, const char *path, const char *name)
157 if (strcmp(name, ".") && strcmp(name, ".."))
159 char temp[MAX_OSPATH];
160 dpsnprintf( temp, sizeof( temp ), "%s%s", path, name );
161 stringlistappend(list, temp);
165 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
168 char pattern[4096], *c;
169 WIN32_FIND_DATA n_file;
171 strlcpy (pattern, basepath, sizeof(pattern));
172 strlcat (pattern, path, sizeof (pattern));
173 strlcat (pattern, "*", sizeof (pattern));
174 // ask for the directory listing handle
175 hFile = FindFirstFile(pattern, &n_file);
176 if(hFile == INVALID_HANDLE_VALUE)
179 adddirentry(list, path, n_file.cFileName);
180 } while (FindNextFile(hFile, &n_file) != 0);
183 // convert names to lowercase because windows does not care, but pattern matching code often does
184 for (i = 0;i < list->numstrings;i++)
185 for (c = list->strings[i];*c;c++)
186 if (*c >= 'A' && *c <= 'Z')
190 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
192 char fullpath[MAX_OSPATH];
195 dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, *path ? path : "./");
196 dir = opendir(fullpath);
199 while ((ent = readdir(dir)))
200 adddirentry(list, path, ent->d_name);