]> git.xonotic.org Git - xonotic/darkplaces.git/blob - filematch.c
physics: fix and refactor unsticking
[xonotic/darkplaces.git] / filematch.c
1
2 #ifdef WIN32
3 #include <windows.h>
4 #else
5 #include <dirent.h>
6 #endif
7
8 #include "darkplaces.h"
9
10 #ifdef WIN32
11 #include "utf8lib.h"
12 #endif
13
14 // LadyHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such...
15
16 int matchpattern(const char *in, const char *pattern, int caseinsensitive)
17 {
18         return matchpattern_with_separator(in, pattern, caseinsensitive, "/\\:", false);
19 }
20
21 // wildcard_least_one: if true * matches 1 or more characters
22 //                     if false * matches 0 or more characters
23 int matchpattern_with_separator(const char *in, const char *pattern, int caseinsensitive, const char *separators, qbool wildcard_least_one)
24 {
25         int c1, c2;
26         while (*pattern)
27         {
28                 switch (*pattern)
29                 {
30                 case 0:
31                         return 1; // end of pattern
32                 case '?': // match any single character
33                         if (*in == 0 || strchr(separators, *in))
34                                 return 0; // no match
35                         in++;
36                         pattern++;
37                         break;
38                 case '*': // match anything until following string
39                         if(wildcard_least_one)
40                         {
41                                 if (*in == 0 || strchr(separators, *in))
42                                         return 0; // no match
43                                 in++;
44                         }
45                         pattern++;
46                         while (*in)
47                         {
48                                 if (strchr(separators, *in))
49                                         break;
50                                 // see if pattern matches at this offset
51                                 if (matchpattern_with_separator(in, pattern, caseinsensitive, separators, wildcard_least_one))
52                                         return 1;
53                                 // nope, advance to next offset
54                                 in++;
55                         }
56                         break;
57                 default:
58                         if (*in != *pattern)
59                         {
60                                 if (!caseinsensitive)
61                                         return 0; // no match
62                                 c1 = *in;
63                                 if (c1 >= 'A' && c1 <= 'Z')
64                                         c1 += 'a' - 'A';
65                                 c2 = *pattern;
66                                 if (c2 >= 'A' && c2 <= 'Z')
67                                         c2 += 'a' - 'A';
68                                 if (c1 != c2)
69                                         return 0; // no match
70                         }
71                         in++;
72                         pattern++;
73                         break;
74                 }
75         }
76         if (*in)
77                 return 0; // reached end of pattern but not end of input
78         return 1; // success
79 }
80
81 // a little strings system
82 void stringlistinit(stringlist_t *list)
83 {
84         memset(list, 0, sizeof(*list));
85 }
86
87 void stringlistfreecontents(stringlist_t *list)
88 {
89         int i;
90         for (i = 0;i < list->numstrings;i++)
91         {
92                 if (list->strings[i])
93                         Z_Free(list->strings[i]);
94                 list->strings[i] = NULL;
95         }
96         list->numstrings = 0;
97         list->maxstrings = 0;
98         if (list->strings)
99                 Z_Free(list->strings);
100         list->strings = NULL;
101 }
102
103 void stringlistappend(stringlist_t *list, const char *text)
104 {
105         size_t textlen;
106         char **oldstrings;
107
108         if (list->numstrings >= list->maxstrings)
109         {
110                 oldstrings = list->strings;
111                 list->maxstrings += 4096;
112                 list->strings = (char **) Z_Malloc(list->maxstrings * sizeof(*list->strings));
113                 if (list->numstrings)
114                         memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings));
115                 if (oldstrings)
116                         Z_Free(oldstrings);
117         }
118         textlen = strlen(text) + 1;
119         list->strings[list->numstrings] = (char *) Z_Malloc(textlen);
120         memcpy(list->strings[list->numstrings], text, textlen);
121         list->numstrings++;
122 }
123
124 static int stringlistsort_cmp(const void *a, const void *b)
125 {
126         return strcasecmp(*(const char **)a, *(const char **)b);
127 }
128
129 void stringlistsort(stringlist_t *list, qbool uniq)
130 {
131         int i, j;
132         if(list->numstrings < 1)
133                 return;
134         qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp);
135         if(uniq)
136         {
137                 // i: the item to read
138                 // j: the item last written
139                 for (i = 1, j = 0; i < list->numstrings; ++i)
140                 {
141                         char *save;
142                         if(!strcasecmp(list->strings[i], list->strings[j]))
143                                 continue;
144                         ++j;
145                         save = list->strings[j];
146                         list->strings[j] = list->strings[i];
147                         list->strings[i] = save;
148                 }
149                 for(i = j+1; i < list->numstrings; ++i)
150                 {
151                         if (list->strings[i])
152                                 Z_Free(list->strings[i]);
153                 }
154                 list->numstrings = j+1;
155         }
156 }
157
158 // operating system specific code
159 static void adddirentry(stringlist_t *list, const char *path, const char *name)
160 {
161         if (strcmp(name, ".") && strcmp(name, ".."))
162         {
163                 char temp[MAX_OSPATH];
164                 dpsnprintf( temp, sizeof( temp ), "%s%s", path, name );
165                 stringlistappend(list, temp);
166         }
167 }
168 #ifdef WIN32
169 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
170 {
171         #define BUFSIZE 4096
172         char pattern[BUFSIZE] = {0};
173         wchar patternw[BUFSIZE] = {0};
174         char filename[BUFSIZE] = {0};
175         wchar *filenamew;
176         int lenw = 0;
177         WIN32_FIND_DATAW n_file;
178         HANDLE hFile;
179         dp_strlcpy(pattern, basepath, sizeof(pattern));
180         dp_strlcat(pattern, path, sizeof (pattern));
181         dp_strlcat(pattern, "*", sizeof (pattern));
182         fromwtf8(pattern, strlen(pattern), patternw, BUFSIZE);
183         // ask for the directory listing handle
184         hFile = FindFirstFileW(patternw, &n_file);
185         if(hFile == INVALID_HANDLE_VALUE)
186                 return;
187         do {
188                 filenamew = n_file.cFileName;
189                 lenw = 0;
190                 while(filenamew[lenw] != 0) ++lenw;
191                 towtf8(filenamew, lenw, filename, BUFSIZE);
192                 adddirentry(list, path, filename);
193         } while (FindNextFileW(hFile, &n_file) != 0);
194         FindClose(hFile);
195         #undef BUFSIZE
196 }
197 #else
198 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
199 {
200         char fullpath[MAX_OSPATH];
201         DIR *dir;
202         struct dirent *ent;
203         dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, path);
204 #ifdef __ANDROID__
205         // SDL currently does not support listing assets, so we have to emulate
206         // it. We're using relative paths for assets, so that will do.
207         if (basepath[0] != '/')
208         {
209                 char listpath[MAX_OSPATH];
210                 qfile_t *listfile;
211                 dpsnprintf(listpath, sizeof(listpath), "%sls.txt", fullpath);
212                 char *buf = (char *) FS_SysLoadFile(listpath, tempmempool, true, NULL);
213                 if (!buf)
214                         return;
215                 char *p = buf;
216                 for (;;)
217                 {
218                         char *q = strchr(p, '\n');
219                         if (q == NULL)
220                                 break;
221                         *q = 0;
222                         adddirentry(list, path, p);
223                         p = q + 1;
224                 }
225                 Mem_Free(buf);
226                 return;
227         }
228 #endif
229         dir = opendir(fullpath);
230         if (!dir)
231                 return;
232
233         while ((ent = readdir(dir)))
234                 adddirentry(list, path, ent->d_name);
235         closedir(dir);
236 }
237 #endif
238