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