vary r_drawparticles_drawdistance and r_drawdecals_drawdistance for
[divverent/darkplaces.git] / filematch.c
1
2 #include "quakedef.h"
3
4 // LordHavoc: some portable directory listing code I wrote for lmp2pcx, now used in darkplaces to load id1/*.pak and such...
5
6 int matchpattern(const char *in, const char *pattern, int caseinsensitive)
7 {
8         int c1, c2;
9         while (*pattern)
10         {
11                 switch (*pattern)
12                 {
13                 case 0:
14                         return 1; // end of pattern
15                 case '?': // match any single character
16                         if (*in == 0 || *in == '/' || *in == '\\' || *in == ':')
17                                 return 0; // no match
18                         in++;
19                         pattern++;
20                         break;
21                 case '*': // match anything until following string
22                         if (!*in)
23                                 return 1; // match
24                         pattern++;
25                         while (*in)
26                         {
27                                 if (*in == '/' || *in == '\\' || *in == ':')
28                                         break;
29                                 // see if pattern matches at this offset
30                                 if (matchpattern(in, pattern, caseinsensitive))
31                                         return 1;
32                                 // nope, advance to next offset
33                                 in++;
34                         }
35                         break;
36                 default:
37                         if (*in != *pattern)
38                         {
39                                 if (!caseinsensitive)
40                                         return 0; // no match
41                                 c1 = *in;
42                                 if (c1 >= 'A' && c1 <= 'Z')
43                                         c1 += 'a' - 'A';
44                                 c2 = *pattern;
45                                 if (c2 >= 'A' && c2 <= 'Z')
46                                         c2 += 'a' - 'A';
47                                 if (c1 != c2)
48                                         return 0; // no match
49                         }
50                         in++;
51                         pattern++;
52                         break;
53                 }
54         }
55         if (*in)
56                 return 0; // reached end of pattern but not end of input
57         return 1; // success
58 }
59
60 // a little strings system
61 void stringlistinit(stringlist_t *list)
62 {
63         memset(list, 0, sizeof(*list));
64 }
65
66 void stringlistfreecontents(stringlist_t *list)
67 {
68         int i;
69         for (i = 0;i < list->numstrings;i++)
70         {
71                 if (list->strings[i])
72                         Z_Free(list->strings[i]);
73                 list->strings[i] = NULL;
74         }
75         list->numstrings = 0;
76         list->maxstrings = 0;
77         if (list->strings)
78                 Z_Free(list->strings);
79 }
80
81 void stringlistappend(stringlist_t *list, char *text)
82 {
83         size_t textlen;
84         char **oldstrings;
85
86         if (list->numstrings >= list->maxstrings)
87         {
88                 oldstrings = list->strings;
89                 list->maxstrings += 4096;
90                 list->strings = Z_Malloc(list->maxstrings * sizeof(*list->strings));
91                 if (list->numstrings)
92                         memcpy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings));
93                 if (oldstrings)
94                         Z_Free(oldstrings);
95         }
96         textlen = strlen(text) + 1;
97         list->strings[list->numstrings] = Z_Malloc(textlen);
98         memcpy(list->strings[list->numstrings], text, textlen);
99         list->numstrings++;
100 }
101
102 void stringlistsort(stringlist_t *list)
103 {
104         int i, j;
105         char *temp;
106         // this is a selection sort (finds the best entry for each slot)
107         for (i = 0;i < list->numstrings - 1;i++)
108         {
109                 for (j = i + 1;j < list->numstrings;j++)
110                 {
111                         if (strcasecmp(list->strings[i], list->strings[j]) > 0)
112                         {
113                                 temp = list->strings[i];
114                                 list->strings[i] = list->strings[j];
115                                 list->strings[j] = temp;
116                         }
117                 }
118         }
119 }
120
121 // operating system specific code
122 #ifdef WIN32
123 #include <io.h>
124 void listdirectory(stringlist_t *list, const char *path)
125 {
126         int i;
127         char pattern[4096], *c;
128         struct _finddata_t n_file;
129         long hFile;
130         strlcpy (pattern, path, sizeof (pattern));
131         strlcat (pattern, "*", sizeof (pattern));
132         // ask for the directory listing handle
133         hFile = _findfirst(pattern, &n_file);
134         if(hFile == -1)
135                 return;
136         // start a new chain with the the first name
137         stringlistappend(list, n_file.name);
138         // iterate through the directory
139         while (_findnext(hFile, &n_file) == 0)
140                 stringlistappend(list, n_file.name);
141         _findclose(hFile);
142
143         // convert names to lowercase because windows does not care, but pattern matching code often does
144         for (i = 0;i < list->numstrings;i++)
145                 for (c = list->strings[i];*c;c++)
146                         if (*c >= 'A' && *c <= 'Z')
147                                 *c += 'a' - 'A';
148 }
149 #else
150 #include <dirent.h>
151 void listdirectory(stringlist_t *list, const char *path)
152 {
153         DIR *dir;
154         struct dirent *ent;
155         dir = opendir(path);
156         if (!dir)
157                 return;
158         while ((ent = readdir(dir)))
159                 if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
160                         stringlistappend(list, ent->d_name);
161         closedir(dir);
162 }
163 #endif
164