Store the data pointer and free it on Font_UnloadFont
[divverent/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 void stringlistsort(stringlist_t *list)
121 {
122         int i, j;
123         char *temp;
124         // this is a selection sort (finds the best entry for each slot)
125         for (i = 0;i < list->numstrings - 1;i++)
126         {
127                 for (j = i + 1;j < list->numstrings;j++)
128                 {
129                         if (strcasecmp(list->strings[i], list->strings[j]) > 0)
130                         {
131                                 temp = list->strings[i];
132                                 list->strings[i] = list->strings[j];
133                                 list->strings[j] = temp;
134                         }
135                 }
136         }
137 }
138
139 // operating system specific code
140 static void adddirentry(stringlist_t *list, const char *path, const char *name)
141 {
142         if (strcmp(name, ".") && strcmp(name, ".."))
143         {
144                 char temp[MAX_OSPATH];
145                 dpsnprintf( temp, sizeof( temp ), "%s%s", path, name );
146                 stringlistappend(list, temp);
147         }
148 }
149 #ifdef WIN32
150 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
151 {
152         int i;
153         char pattern[4096], *c;
154         WIN32_FIND_DATA n_file;
155         HANDLE hFile;
156         strlcpy (pattern, basepath, sizeof(pattern));
157         strlcat (pattern, path, sizeof (pattern));
158         strlcat (pattern, "*", sizeof (pattern));
159         // ask for the directory listing handle
160         hFile = FindFirstFile(pattern, &n_file);
161         if(hFile == INVALID_HANDLE_VALUE)
162                 return;
163         do {
164                 adddirentry(list, path, n_file.cFileName);
165         } while (FindNextFile(hFile, &n_file) != 0);
166         FindClose(hFile);
167
168         // convert names to lowercase because windows does not care, but pattern matching code often does
169         for (i = 0;i < list->numstrings;i++)
170                 for (c = list->strings[i];*c;c++)
171                         if (*c >= 'A' && *c <= 'Z')
172                                 *c += 'a' - 'A';
173 }
174 #else
175 void listdirectory(stringlist_t *list, const char *basepath, const char *path)
176 {
177         char fullpath[MAX_OSPATH];
178         DIR *dir;
179         struct dirent *ent;
180         dpsnprintf(fullpath, sizeof(fullpath), "%s%s", basepath, *path ? path : "./");
181         dir = opendir(fullpath);
182         if (!dir)
183                 return;
184         while ((ent = readdir(dir)))
185                 adddirentry(list, path, ent->d_name);
186         closedir(dir);
187 }
188 #endif
189