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