1 /*
2 Copyright (C) 2003 Tenebrae Team
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21 /*
22 Sys_Find* implementation for UNIX like systems
23 system conformance :
24
25 system not having the glob system call :
26
27 ISO/IEC 9945-2 (fnmatch)
28 BSD 4.3 (dirent syscalls)
29
30 OTHER :
31
32 POSIX.2 (glob)
33
34 */
35
36 #include "quakedef.h"
37 #include <errno.h>
38
39 #if !defined(__GLIBC__) && !defined(__FreeBSD__)
40
41 #include <dirent.h>
42 #include <fnmatch.h>
43
44 #define UXDATA_GRANULARITY 10
45
46 typedef struct {
47 int pathlen;
48 size_t count;
49 size_t lsize;
50 DIR *dir;
51 struct dirent **list;
52 } uxdirdata_t;
53
uxdata_free(uxdirdata_t * ud)54 int uxdata_free (uxdirdata_t *ud)
55 {
56 int i;
57 closedir (ud->dir);
58 Z_Free (ud->list);
59 }
60
61
direntp_compare(struct dirent ** p1,struct dirent ** p2)62 int direntp_compare (struct dirent **p1, struct dirent **p2)
63 {
64 return strncmp ((*p1)->d_name, (*p2)->d_name, sizeof ((*p1)->d_name));
65 }
66
Sys_Findfirst(char * dirname,char * filter,dirdata_t * dirdata)67 dirdata_t *Sys_Findfirst (char *dirname, char *filter, dirdata_t *dirdata)
68 {
69 uxdirdata_t *uxdata;
70 DIR *dir;
71 struct dirent *entry;
72 struct dirent **list;
73 int pathlen;
74
75 if (dirdata && filter){
76 pathlen = strlen (dirname);
77 if (pathlen >= MAX_OSPATH-1)
78 return NULL;
79 strncpy (dirdata->entry, dirname, sizeof(dirdata->entry));
80 dir = opendir (dirdata->entry);
81 if (dir == NULL) {
82 return NULL;
83 }
84 uxdata = Z_Malloc (sizeof(uxdirdata_t));
85 uxdata->count = 0;
86 uxdata->pathlen = pathlen;
87 uxdata->lsize = 10;
88 uxdata->list = Z_Malloc (sizeof(struct dirent *) * (uxdata->lsize));
89
90 while (entry = readdir (dir)){
91 int code;
92
93 // realloc entry list
94 if (uxdata->lsize == uxdata->count) {
95 list = Z_Malloc (sizeof(struct dirent *) * (uxdata->lsize += UXDATA_GRANULARITY));
96 memcpy (list, uxdata->list, uxdata->count);
97 Z_Free (uxdata->list);
98 uxdata->list = list;
99 }
100 // check name matching filter
101 code = fnmatch (filter, entry->d_name, 0);
102 switch (code){
103 case 0: /* match */
104 uxdata->list[uxdata->count] = entry;
105 uxdata->count++;
106 break;
107 case FNM_NOMATCH:
108 break;
109 default:
110 Sys_Error ("Sys_Glob_select : fnmatch call (%d)\n",errno);
111 }
112 }
113 if (uxdata->count) {
114 uxdata->lsize = uxdata->count;
115 uxdata->count = 0;
116 // sort the entry list
117 qsort(uxdata->list, uxdata->lsize, sizeof(struct dirent *),direntp_compare);
118 if (dirname[pathlen-1] != '/') {
119 dirdata->entry[pathlen]='/';
120 uxdata->pathlen++;
121 dirdata->entry[uxdata->pathlen]=0;
122 }
123 strncpy (dirdata->entry+uxdata->pathlen, uxdata->list[0]->d_name, sizeof(dirdata->entry)-uxdata->pathlen);
124 uxdata->dir = dir;
125 dirdata->internal = uxdata;
126 return dirdata;
127 }
128 else uxdata_free (uxdata);
129 }
130 return NULL;
131 }
132
Sys_Findnext(dirdata_t * dirdata)133 dirdata_t *Sys_Findnext (dirdata_t *dirdata)
134 {
135 uxdirdata_t *uxdata;
136 if (dirdata){
137 uxdata=dirdata->internal;
138 if (uxdata) {
139 uxdata->count++;
140 // next entry ?
141 if (uxdata->count<uxdata->lsize){
142 strncpy (dirdata->entry+uxdata->pathlen, uxdata->list[0]->d_name, sizeof(dirdata->entry)-uxdata->pathlen);
143 return dirdata;
144 }
145 // no -> close (just in case Findclose isn't called)
146 uxdata_free (dirdata->internal);
147 dirdata->internal=NULL;
148 }
149 }
150 return NULL;
151 }
152
Sys_Findclose(dirdata_t * dirdata)153 void Sys_Findclose (dirdata_t *dirdata)
154 {
155 uxdirdata_t *uxdata;
156 if (dirdata){
157 uxdata=dirdata->internal;
158 if (uxdata){
159 uxdata_free (uxdata);
160 dirdata->internal=NULL;
161 }
162 }
163 }
164
165 #else
166
167 #include <glob.h>
168
169 typedef struct {
170 glob_t globbuf;
171 size_t count;
172 } uxdirdata_t;
173
174
Sys_Findfirst(char * dir,char * filter,dirdata_t * dirdata)175 dirdata_t *Sys_Findfirst (char *dir, char *filter, dirdata_t *dirdata)
176 {
177 uxdirdata_t *uxdata;
178 if (dirdata && filter){
179 char dirfilter[MAX_OSPATH];
180 uxdata=Z_Malloc (sizeof(uxdirdata_t));
181 sprintf (dirfilter,"%s/%s", dir, filter);
182 glob (dirfilter,0,NULL,&uxdata->globbuf);
183 if (uxdata->globbuf.gl_pathc){
184 dirdata->internal=uxdata;
185 strncpy (dirdata->entry,uxdata->globbuf.gl_pathv[0],sizeof(dirdata->entry));
186 uxdata->count=0;
187 return dirdata;
188 }
189 }
190 return NULL;
191 }
192
Sys_Findnext(dirdata_t * dirdata)193 dirdata_t *Sys_Findnext (dirdata_t *dirdata)
194 {
195 uxdirdata_t *uxdata;
196 if (dirdata){
197 uxdata=dirdata->internal;
198 if (uxdata) {
199 uxdata->count++;
200 // next entry ?
201 if (uxdata->count<uxdata->globbuf.gl_pathc){
202 strncpy (dirdata->entry,uxdata->globbuf.gl_pathv[uxdata->count],sizeof(dirdata->entry));
203 return dirdata;
204 }
205 // no -> close (just in case Findclose isn't called)
206 globfree (&uxdata->globbuf);
207 Z_Free (dirdata->internal);
208 dirdata->internal=NULL;
209 }
210 }
211 return NULL;
212 }
213
Sys_Findclose(dirdata_t * dirdata)214 void Sys_Findclose (dirdata_t *dirdata)
215 {
216 uxdirdata_t *uxdata;
217 if (dirdata){
218 uxdata=dirdata->internal;
219 if (uxdata){
220 globfree (&uxdata->globbuf);
221 Z_Free (uxdata);
222 dirdata->internal=NULL;
223 }
224 }
225 }
226
227 #endif
228
229