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