]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - filematch.c
fix CSQC view entity handling
[xonotic/darkplaces.git] / filematch.c
1
2 #ifdef WIN32
3 #include <windows.h>
4 #else
5 #include <dirent.h>
6 #endif
7
8 #include "quakedef.h"
9
10 // LordHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such...
11
12 int matchpattern(const char *in, const char *pattern, int caseinsensitive)
13 {
14         return matchpattern_with_separator(in, pattern, caseinsensitive, "/\\:", false);
15 }
16
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)
20 {
21         int c1, c2;
22         while (*pattern)
23         {
24                 switch (*pattern)
25                 {
26                 case 0:
27                         return 1; // end of pattern
28                 case '?': // match any single character
29                         if (*in == 0 || strchr(separators, *in))
30                                 return 0; // no match
31                         in++;
32                         pattern++;
33                         break;
34                 case '*': // match anything until following string
35                         if(wildcard_least_one)
36                         {
37                                 if (*in == 0 || strchr(separators, *in))
38                                         return 0; // no match
39                                 in++;
40                         }
41                         pattern++;
42                         while (*in)
43                         {
44                                 if (strchr(separators, *in))
45                                         break;
46                                 // see if pattern matches at this offset
47                                 if (matchpattern_with_separator(in, pattern, caseinsensitive, separators, wildcard_least_one))
48                                         return 1;
49                                 // nope, advance to next offset
50                                 in++;
51                         }
52                         break;
53                 default:
54                         if (*in != *pattern)
55                         {
56                                 if (!caseinsensitive)
57                                         return 0; // no match
58                                 c1 = *in;
59                                 if (c1 >= 'A' && c1 <= 'Z')
60                                         c1 += 'a' - 'A';
61                                 c2 = *pattern;
62                                 if (c2 >= 'A' && c2 <= 'Z')
63                                         c2 += 'a' - 'A';
64                                 if (c1 != c2)
65                                         return 0; // no match
66                         }
67                         in++;
68                         pattern++;
69                         break;
70                 }
71         }
72         if (*in)
73                 return 0; // reached end of pattern but not end of input
74         return 1; // success
75 }
76
77 // a little strings system
78 void stringlistinit(stringlist_t *list)
79 {
80         memset(list, 0, sizeof(*list));
81 }
82
83 void stringlistfreecontents(stringlist_t *list)
84 {
85         int i;
86         for (i = 0;i < list->numstrings;i++)
87         {
88                 if (list->strings[i])
89                         Z_Free(list->strings[i]);
90                 list->strings[i] = NULL;
91         }
92         list->numstrings = 0;
93         list->maxstrings = 0;
94         if (list->strings)
95                 Z_Free(list->strings);
96         list->strings = NULL;
97 }
98
99 void stringlistappend(stringlist_t *list, const char *text)
100 {
101         size_t textlen;
102         char **oldstrings;
103
104         if (list->numstrings >= list->maxstrings)
105         {
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));
111                 if (oldstrings)
112                         Z_Free(oldstrings);
113         }
114         textlen = strlen(text) + 1;
115         list->strings[list->numstrings] = (char *) Z_Malloc(textlen);
116         memcpy(list->strings[list->numstrings], text, textlen);
117         list->numstrings++;
118 }
119
120 static int stringlistsort_cmp(const void *a, const void *b)
121 {
122         return strcasecmp(*(const char **)a, *(const char **)b);
123 }
124
125 void stringlistsort(stringlist_t *list, qboolean uniq)
126 {
127         int i, j;
128         if(list->numstrings < 1)
129                 return;
130         qsort(&list->strings[0], list->numstrings, sizeof(list->strings[0]), stringlistsort_cmp);
131         if(uniq)
132         {
133                 // i: the item to read
134                 // j: the item last written
135                 for (i = 1, j = 0; i < list->numstrings; ++i)
136                 {
137                         char *save;
138                         if(!strcasecmp(list->strings[i], list->strings[j]))
139                                 continue;
140                         ++j;
141                         save = list->strings[j];
142                         list->strings[j] = list->strings[i];
143                         list->strings[i] = save;
144                 }
145                 for(i = j+1; i < list->numstrings; ++i)
146                 {
147                         if (list->strings[i])
148                                 Z_Free(list->strings[i]);
149                 }
150                 list->numstrings = j+1;
151         }
152 }
153
154 // operating system specific code
155 static void adddirentry(stringlist_t *list, const char *path, const char *name)
156 {
157         if (strcmp(name, ".") && strcmp(name, ".."))
158         {
159                 char temp[MAX_OSPATH];
160                 dpsnprintf( temp, sizeof( temp ), "%s%s", path, name );
161                 stringlistappend(list, temp);
162         }
163 }
164 #ifdef WIN32
165 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
166 {
167         int i;
168         char pattern[4096], *c;
169         WIN32_FIND_DATA n_file;
170         HANDLE hFile;
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)
177                 return;
178         do {
179                 adddirentry(list, path, n_file.cFileName);
180         } while (FindNextFile(hFile, &n_file) != 0);
181         FindClose(hFile);
182
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')
187                                 *c += 'a' - 'A';
188 }
189 #else
190 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
191 {
192         char fullpath[MAX_OSPATH];
193         DIR *dir;
194         struct dirent *ent;
195         dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, *path ? path : "./");
196         dir = opendir(fullpath);
197         if (!dir)
198                 return;
199         while ((ent = readdir(dir)))
200                 adddirentry(list, path, ent->d_name);
201         closedir(dir);
202 }
203 #endif
204