1 /*
2 scandir.c:
3
4 Replacement scandir() and alphasort() for platforms lacking
5 these functions.
6
7 Brought to tuxmath by David Bruce from the GPLv2 (or later) Hatari project:
8 http://hatari.berlios.de/
9
10 Modified slightly and relicensed under GPLv3 or later.
11
12 Copyright 2007, 2008, 2009, 2010.
13 Authors: Hatari Project.
14 Project email: <tuxmath-devel@lists.sourceforge.net>
15 Project website: http://tux4kids.alioth.debian.org
16
17
18 scandir.c is part of Tux Typing, a.k.a. "tuxtype".
19
20 Tux Typing is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation; either version 3 of the License, or
23 (at your option) any later version.
24
25 Tux Typing is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with this program. If not, see <http://www.gnu.org/licenses/>.
32 */
33
34
35
36 #include "config.h"
37 #ifndef HAVE_SCANDIR
38
39 /*
40 Hatari - scandir.c
41
42 This file is distributed under the GNU Public License, version 2 or at
43 your option any later version. Read the file gpl.txt for details.
44
45 scandir function for BEOS, SunOS etc..
46 */
47 const char ScanDir_rcsid[] = "Hatari $Id: scandir.c,v 1.3 2007/01/16 18:42:59 thothy Exp $";
48
49 #include <stdlib.h>
50 #include <string.h>
51 #include <strings.h>
52 #include <stdio.h>
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <fcntl.h>
56 #include <unistd.h>
57
58 #include "scandir.h"
59
60 /*-----------------------------------------------------------------------
61 * Here come alphasort and scandir for BeOS/Haiku and SunOS
62 *-----------------------------------------------------------------------*/
63 #if defined(__BEOS__) || defined(__HAIKU__) || (defined(__sun) && defined(__SVR4))
64
65 #undef DIRSIZ
66
67 #define DIRSIZ(dp) \
68 ((sizeof(struct dirent) - sizeof(dp)->d_name) + \
69 (((dp)->d_reclen + 1 + 3) &~ 3))
70
71 #if defined(__sun) && defined(__SVR4)
72 # define dirfd(d) ((d)->dd_fd)
73 #elif defined(__BEOS__)
74 #ifndef (__HAIKU__)
75 #else
76 # define dirfd(d) ((d)->fd)
77 #endif
78 #endif
79
80 /
81 /*-----------------------------------------------------------------------*/
82 /**
83 * Alphabetic order comparison routine.
84 */
85 int alphasort(const void *d1, const void *d2)
86 {
87 return strcmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
88 }
89
90
91 /*-----------------------------------------------------------------------*/
92 /**
93 * Scan a directory for all its entries
94 */
scandir(const char * dirname,struct dirent *** namelist,int (* sdfilter)(struct dirent *),int (* dcomp)(const void *,const void *))95 int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *))
96 {
97 struct dirent *d, *p, **names;
98 struct stat stb;
99 size_t nitems;
100 size_t arraysz;
101 DIR *dirp;
102
103 if ((dirp = opendir(dirname)) == NULL)
104 return(-1);
105
106 if (fstat(dirfd(dirp), &stb) < 0)
107 return(-1);
108
109 /*
110 * estimate the array size by taking the size of the directory file
111 * and dividing it by a multiple of the minimum size entry.
112 */
113 arraysz = (stb.st_size / 24);
114
115 names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
116 if (names == NULL)
117 return(-1);
118
119 nitems = 0;
120
121 while ((d = readdir(dirp)) != NULL)
122 {
123
124 if (sdfilter != NULL && !(*sdfilter)(d))
125 continue; /* just selected names */
126
127 /*
128 * Make a minimum size copy of the data
129 */
130
131 p = (struct dirent *)malloc(DIRSIZ(d));
132 if (p == NULL)
133 return(-1);
134
135 p->d_ino = d->d_ino;
136 p->d_reclen = d->d_reclen;
137 /*p->d_namlen = d->d_namlen;*/
138 memcpy(p->d_name, d->d_name, p->d_reclen + 1);
139
140 /*
141 * Check to make sure the array has space left and
142 * realloc the maximum size.
143 */
144
145 if (++nitems >= arraysz)
146 {
147
148 if (fstat(dirfd(dirp), &stb) < 0)
149 return(-1); /* just might have grown */
150
151 arraysz = stb.st_size / 12;
152
153 names = (struct dirent **)realloc((char *)names, arraysz * sizeof(struct dirent *));
154 if (names == NULL)
155 return(-1);
156 }
157
158 names[nitems-1] = p;
159 }
160
161 closedir(dirp);
162
163 if (nitems && dcomp != NULL)
164 qsort(names, nitems, sizeof(struct dirent *), dcomp);
165
166 *namelist = names;
167
168 return nitems;
169 }
170
171
172 #endif /* __BEOS__ || __sun */
173
174
175 /*-----------------------------------------------------------------------
176 * Here come alphasort and scandir for Windows
177 *-----------------------------------------------------------------------*/
178 #if defined(WIN32)
179
180 #undef DATADIR // stupid windows.h defines DATADIR, too
181 #include <windows.h>
182
183 /*-----------------------------------------------------------------------*/
184 /**
185 * Alphabetic order comparison routine.
186 */
alphasort(const void * d1,const void * d2)187 int alphasort(const void *d1, const void *d2)
188 {
189 return stricmp((*(struct dirent * const *)d1)->d_name, (*(struct dirent * const *)d2)->d_name);
190 }
191
192 /*-----------------------------------------------------------------------*/
193 /**
194 * Scan a directory for all its entries
195 */
scandir(const char * dirname,struct dirent *** namelist,int (* sdfilter)(struct dirent *),int (* dcomp)(const void *,const void *))196 int scandir(const char *dirname, struct dirent ***namelist, int (*sdfilter)(struct dirent *), int (*dcomp)(const void *, const void *))
197 {
198 int len;
199 char *findIn, *d;
200 WIN32_FIND_DATA find;
201 HANDLE h;
202 int nDir = 0, NDir = 0;
203 struct dirent **dir = 0, *selectDir;
204 unsigned long ret;
205
206 len = strlen(dirname);
207 findIn = (char *)malloc(len+5);
208 strcpy(findIn, dirname);
209 printf("scandir : findIn orign=%s\n", findIn);
210 for (d = findIn; *d; d++)
211 if (*d=='/')
212 *d='\\';
213 if ((len==0))
214 {
215 strcpy(findIn, ".\\*");
216 }
217 if ((len==1)&& (d[-1]=='.'))
218 {
219 strcpy(findIn, ".\\*");
220 }
221 if ((len>0) && (d[-1]=='\\'))
222 {
223 *d++ = '*';
224 *d = 0;
225 }
226 if ((len>1) && (d[-1]=='.') && (d[-2]=='\\'))
227 {
228 d[-1] = '*';
229 }
230 if ((len>1) && (d[-2]!='\\') && (d[-1]!='*'))
231 {
232 *d++ = '\\';
233 *d++ = '*';
234 *d = 0;
235 }
236
237 printf("scandir : findIn processed=%s\n", findIn);
238 if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE)
239 {
240 printf("scandir : FindFirstFile error\n");
241 ret = GetLastError();
242 if (ret != ERROR_NO_MORE_FILES)
243 {
244 // TODO: return some error code
245 }
246 *namelist = dir;
247 return nDir;
248 }
249 do
250 {
251 printf("scandir : findFile=%s\n", find.cFileName);
252 selectDir=(struct dirent*)malloc(sizeof(struct dirent)+strlen(find.cFileName));
253 strcpy(selectDir->d_name, find.cFileName);
254 if (!sdfilter || (*sdfilter)(selectDir))
255 {
256 if (nDir==NDir)
257 {
258 struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), NDir+33);
259 if (NDir)
260 memcpy(tempDir, dir, sizeof(struct dirent*)*NDir);
261 if (dir)
262 free(dir);
263 dir = tempDir;
264 NDir += 32;
265 }
266 dir[nDir] = selectDir;
267 nDir++;
268 dir[nDir] = 0;
269 }
270 else
271 {
272 free(selectDir);
273 }
274 }
275 while (FindNextFile(h, &find));
276 ret = GetLastError();
277 if (ret != ERROR_NO_MORE_FILES)
278 {
279 // TODO: return some error code
280 }
281 FindClose(h);
282
283 free (findIn);
284
285 if (dcomp)
286 qsort (dir, nDir, sizeof(*dir),dcomp);
287
288 *namelist = dir;
289 return nDir;
290 }
291
292 #endif /* WIN32 */
293 #endif /* HAVE_SCANDIR */
294