made darkplaces compile successfully with g++ to test for errors C doesn't care about...
[xonotic/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 = (stringlist_t *)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         // exit early if there's nothing to sort
89         if (start == NULL || start->next == NULL)
90                 return start;
91         notdone = 1;
92         while (notdone)
93         {
94                 current = start;
95                 notdone = 0;
96                 previous = NULL;
97                 while (current && current->next)
98                 {
99                         if (strcmp(current->text, current->next->text) > 0)
100                         {
101                                 // current is greater than next
102                                 notdone = 1;
103                                 temp2 = current->next;
104                                 temp3 = current;
105                                 temp4 = current->next->next;
106                                 if (previous)
107                                         previous->next = temp2;
108                                 else
109                                         start = temp2;
110                                 temp2->next = temp3;
111                                 temp3->next = temp4;
112                                 break;
113                         }
114                         previous = current;
115                         current = current->next;
116                 }
117         }
118         return start;
119 }
120
121 // operating system specific code
122 #ifdef WIN32
123 #include <io.h>
124 stringlist_t *listdirectory(const char *path)
125 {
126         char pattern[4096], *c;
127         struct _finddata_t n_file;
128         long hFile;
129         stringlist_t *start, *current;
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 NULL;
136         // start a new chain with the the first name
137         start = current = stringlistappend(NULL, n_file.name);
138         // iterate through the directory
139         while (_findnext(hFile, &n_file) == 0)
140                 current = stringlistappend(current, 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 (current = start;current;current = current->next)
145                 for (c = current->text;*c;c++)
146                         if (*c >= 'A' && *c <= 'Z')
147                                 *c += 'a' - 'A';
148
149         // sort the list alphanumerically
150         return stringlistsort(start);
151 }
152 #else
153 #include <dirent.h>
154 stringlist_t *listdirectory(const char *path)
155 {
156         DIR *dir;
157         struct dirent *ent;
158         stringlist_t *start, *current;
159         dir = opendir(path);
160         if (!dir)
161                 return NULL;
162         start = current = NULL;
163         while ((ent = readdir(dir)))
164         {
165                 if (strcmp(ent->d_name, ".") && strcmp(ent->d_name, ".."))
166                 {
167                         current = stringlistappend(current, ent->d_name);
168                         if (!start)
169                                 start = current;
170                 }
171         }
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