upgraded both QuakeC VMs to use a table of negative string indices for all dynamic...
[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(char *in, 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 chained strings system
61 stringlist_t *stringlistappend(stringlist_t *current, char *text)
62 {
63         stringlist_t *newitem;
64         newitem = Z_Malloc(strlen(text) + 1 + sizeof(stringlist_t));
65         newitem->next = NULL;
66         newitem->text = (char *)(newitem + 1);
67         strcpy(newitem->text, text);
68         if (current)
69                 current->next = newitem;
70         return newitem;
71 }
72
73 void stringlistfree(stringlist_t *current)
74 {
75         stringlist_t *next;
76         while (current)
77         {
78                 next = current->next;
79                 Z_Free(current);
80                 current = next;
81         }
82 }
83
84 stringlist_t *stringlistsort(stringlist_t *start)
85 {
86         int notdone;
87         stringlist_t *current, *previous, *temp2, *temp3, *temp4;
88         notdone = 1;
89         while (notdone)
90         {
91                 current = start;
92                 notdone = 0;
93                 previous = NULL;
94                 while (current && current->next)
95                 {
96                         if (strcmp(current->text, current->next->text) > 0)
97                         {
98                                 // current is greater than next
99                                 notdone = 1;
100                                 temp2 = current->next;
101                                 temp3 = current;
102                                 temp4 = current->next->next;
103                                 if (previous)
104                                         previous->next = temp2;
105                                 else
106                                         start = temp2;
107                                 temp2->next = temp3;
108                                 temp3->next = temp4;
109                                 break;
110                         }
111                         previous = current;
112                         current = current->next;
113                 }
114         }
115         return start;
116 }
117
118 // operating system specific code
119 #ifdef WIN32
120 #include <io.h>
121 stringlist_t *listdirectory(const char *path)
122 {
123         char pattern[4096], *c;
124         struct _finddata_t n_file;
125     long hFile;
126         stringlist_t *start, *current;
127         strlcpy (pattern, path, sizeof (pattern));
128         strlcat (pattern, "\\*", sizeof (pattern));
129         // ask for the directory listing handle
130         hFile = _findfirst(pattern, &n_file);
131         if(hFile != -1)
132         {
133                 // start a new chain with the the first name
134                 start = current = stringlistappend(NULL, n_file.name);
135                 // iterate through the directory
136                 while (_findnext(hFile, &n_file) == 0)
137                         current = stringlistappend(current, n_file.name);
138                 _findclose(hFile);
139
140                 // convert names to lowercase because windows does not care, but pattern matching code often does
141                 for (current = start;current;current = current->next)
142                         for (c = current->text;*c;c++)
143                                 if (*c >= 'A' && *c <= 'Z')
144                                         *c += 'a' - 'A';
145
146                 // sort the list alphanumerically
147                 start = stringlistsort(start);
148                 return start;
149         }
150         else
151                 return NULL;
152 }
153 #else
154 #include <dirent.h>
155 stringlist_t *listdirectory(const char *path)
156 {
157         DIR *dir;
158         struct dirent *ent;
159         stringlist_t *start, *current;
160         dir = opendir(path);
161         if (!dir)
162                 return NULL;
163         ent = readdir(dir);
164         if (!ent)
165         {
166                 closedir(dir);
167                 return NULL;
168         }
169         start = current = stringlistappend(NULL, ent->d_name);
170         while((ent = readdir(dir)))
171                 current = stringlistappend(current, ent->d_name);
172         closedir(dir);
173         // sort the list alphanumerically
174         return stringlistsort(start);
175 }
176 #endif
177
178 void freedirectory(stringlist_t *list)
179 {
180         stringlistfree(list);
181 }
182