1 /* $Id$
2  *  Provides compiler-independent functions like DOS findfirst() and findnext()
3  *
4  * HUSKYLIB: common defines, types and functions for HUSKY
5  *
6  * This is part of The HUSKY Fidonet Software project:
7  * see http://husky.sourceforge.net for details
8  *
9  *
10  * HUSKYLIB is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * HUSKYLIB is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; see file COPYING. If not, write to the
22  * Free Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  *
24  * See also http://www.gnu.org, license may be found here.
25  */
26 
27 /* standard headers */
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 
34 /* huskylib: compiler.h */
35 #include <compiler.h>
36 
37 /* compiler-dependent headers */
38 #if defined(HAS_DIR_H)
39 #  include <dir.h>
40 #endif
41 
42 #if defined(HAS_DOS_H)
43 #  include <dos.h>
44 #endif
45 
46 /* huskylib headers */
47 #define DLLEXPORT
48 #include <huskyext.h>
49 #include <huskylib.h>
50 #include <ffind.h>
51 
52 
53 
54 #ifdef __OS2__
55 #  define INCL_NOPM
56 #  define INCL_DOS
57 #  include <os2.h>
58 #  if defined(__FLAT__)
59 #    undef DosQPathInfo
60 #    define DosQPathInfo(a,b,c,d,e)  DosQueryPathInfo(a,b,c,d)
61 #  endif
62 #endif
63 
64 /*
65  *  FFindOpen;  Use like MSDOS "find first" function,  except be sure to
66  *  release allocated system resources by caling FFindClose() with the
67  *  handle returned by this function.
68  *
69  *  Returns: NULL == File not found.
70  */
71 
FFindOpen(const char * filespec,unsigned short attribute)72 FFIND *_fast FFindOpen(const char *filespec, unsigned short attribute)
73 {
74     FFIND *ff;
75 
76     ff = malloc(sizeof(FFIND));
77 
78     if (ff != NULL)
79     {
80 #if defined(__TURBOC__) || defined(__DJGPP__)
81 
82         if (findfirst(filespec, &(ff->ffbuf), attribute) != 0)
83         {
84             free(ff);
85             ff = NULL;
86         }
87         else
88         {
89             ff->ff_attrib = ff->ffbuf.ff_attrib;
90             ff->ff_ftime  = ff->ffbuf.ff_ftime;
91             ff->ff_fdate  = ff->ffbuf.ff_fdate;
92             ff->ff_fsize  = ff->ffbuf.ff_fsize;
93             memcpy(ff->ff_name, ff->ffbuf.ff_name, sizeof(ff->ff_name));
94             ff->ff_name[sizeof(ff->ff_name) - 1] = '\0';
95         }
96 
97 #elif defined(__MSC__) || defined(__WATCOMC__)
98 
99         if (_dos_findfirst(filespec, attribute, &(ff->ffbuf)) != 0)
100         {
101             free(ff);
102             ff = NULL;
103         }
104         else
105         {
106             ff->ff_attrib = ff->ffbuf.attrib;
107             ff->ff_ftime  = ff->ffbuf.wr_time;
108             ff->ff_fdate  = ff->ffbuf.wr_date;
109             ff->ff_fsize  = ff->ffbuf.size;
110             memcpy(ff->ff_name, ff->ffbuf.name, sizeof(ff->ff_name));
111             ff->ff_name[sizeof(ff->ff_name) - 1] = '\0';
112         }
113 
114 #elif defined(__OS2__)
115 
116 #if defined(__FLAT__)
117         ULONG SearchCount = 1;
118         FILEFINDBUF3 findbuf;
119 #else
120         USHORT SearchCount = 1;
121         FILEFINDBUF findbuf;
122 #endif
123 
124         ff->hdir = HDIR_CREATE;
125 #ifdef __EMX__
126         if (!DosFindFirst((PCSZ) filespec, &ff->hdir, attribute, &findbuf, sizeof(findbuf), &SearchCount, 1L))
127 #else
128         if (!DosFindFirst((PBYTE) filespec, &ff->hdir, attribute, &findbuf, sizeof(findbuf), &SearchCount, 1L))
129 #endif
130         {
131             ff->ff_attrib = (char)findbuf.attrFile;
132             ff->ff_fsize = findbuf.cbFile;
133 
134             ff->ff_ftime = *((USHORT *) & findbuf.ftimeLastWrite);
135             ff->ff_fdate = *((USHORT *) & findbuf.fdateLastWrite);
136 
137             strncpy(ff->ff_name, findbuf.achName, sizeof(ff->ff_name));
138         }
139         else
140         {
141             free(ff);
142             ff = NULL;
143         }
144 
145 #elif defined(__UNIX__)
146 
147         char *p;
148         int fin = 0;
149         struct dirent *de;
150 
151         unused(attribute);
152 
153         p = strrchr(filespec, '/');
154         if (p == NULL)
155         {
156             strcpy(ff->firstbit, ".");
157             strcpy(ff->lastbit, filespec);
158         }
159         else if (p == filespec)
160 	{
161 	    strcpy(ff->firstbit, "/");
162 	    strcpy(ff->lastbit, filespec+1);
163 	}
164 	else
165         {
166             memcpy(ff->firstbit, filespec, p - filespec);
167             ff->firstbit[p - filespec] = '\0';
168             strcpy(ff->lastbit, p + 1);
169         }
170         ff->dir = opendir(ff->firstbit);
171         if (ff->dir != NULL)
172         {
173             while (!fin)
174             {
175                 de = readdir(ff->dir);
176                 if (de == NULL)
177                 {
178                     closedir(ff->dir);
179                     free(ff);
180                     ff = NULL;
181                     fin = 1;
182                 }
183                 else
184                 {
185                     if (patmat(de->d_name, ff->lastbit))
186                     {
187                         strncpy(ff->ff_name, de->d_name, sizeof ff->ff_name);
188 			 ff->ff_fsize = -1L; /* All who wants to know it's size
189 					      * must read it by himself
190 					      */
191                         fin = 1;
192                     }
193                 }
194             }
195         }
196         else
197         {
198             free(ff);
199             ff = NULL;
200         }
201 
202 #elif defined(SASC)
203 
204         char *temp;
205         int error;
206 
207         temp = strrchr(filespec, '/');
208         if (temp == NULL)
209         {
210             temp = strrchr(filespec, '\\');
211         }
212         if (temp == NULL)
213         {
214             temp = strrchr(filespec, ':');
215         }
216         if (temp == NULL)
217         {
218             strcpy(ff->prefix, "");
219         }
220         else
221         {
222             memcpy(ff->prefix, filespec, temp - filespec + 1);
223             *(ff->prefix + (temp - filespec + 1)) = '\0';
224         }
225         error = dfind(&ff->info, filespec, 0);
226         if (error == 0)
227         {
228             strcpy(ff->ff_name, ff->prefix);
229             strcat(ff->ff_name, ff->info.fib_FileName);
230         }
231         else
232         {
233             free(ff);
234             ff = NULL;
235         }
236 
237 #elif defined(__RSXNT__) || defined(__MINGW32__) || defined(__MSVC__)
238 
239         ff->hDirA = FindFirstFile(filespec, &(ff->InfoBuf));
240         ff->attrib_srch = (char)attribute;
241         while (ff->hDirA != INVALID_HANDLE_VALUE)
242         {
243             if (strlen(ff->InfoBuf.cFileName) < sizeof(ff->ff_name))
244             {
245                 if ((!(ff->InfoBuf.dwFileAttributes &
246                        FILE_ATTRIBUTE_DIRECTORY)) ||
247                     (ff->attrib_srch & MSDOS_SUBDIR))
248                 {
249                     break;
250                 }
251             }
252             /* skip file for some reason */
253             if (!FindNextFile(ff->hDirA, &(ff->InfoBuf)))
254             {
255                 if (ff->hDirA != INVALID_HANDLE_VALUE)
256                 {
257                     FindClose(ff->hDirA);
258                 }
259                 ff->hDirA = INVALID_HANDLE_VALUE;
260             }
261         }
262         if (ff->hDirA != INVALID_HANDLE_VALUE)
263         {
264             strcpy(ff->ff_name, ff->InfoBuf.cFileName);
265             ff->ff_fsize = ff->InfoBuf.nFileSizeLow;
266             ff->ff_attrib = 0;
267             if (ff->InfoBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
268             {
269                 ff->ff_attrib |= MSDOS_SUBDIR;
270             }
271             if (ff->InfoBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
272             {
273                 ff->ff_attrib |= _A_HIDDEN;
274             }
275         }
276         else
277         {
278             free(ff);
279             ff = NULL;
280         }
281 
282 #else
283 #error Unable to determine compiler and target operating system!
284 #endif
285 
286     }
287 
288     return ff;
289 }
290 
291 /*
292  *  FFindNext: Returns 0 if next file was found, non-zero if it was not.
293  */
294 
FFindNext(FFIND * ff)295 int _fast FFindNext(FFIND * ff)
296 {
297     int rc = -1;
298 
299     if (ff != NULL)
300     {
301 #if defined(__TURBOC__) || defined(__DJGPP__)
302 
303         rc = findnext(&(ff->ffbuf));
304 
305         ff->ff_attrib = ff->ffbuf.ff_attrib;
306         ff->ff_ftime  = ff->ffbuf.ff_ftime;
307         ff->ff_fdate  = ff->ffbuf.ff_fdate;
308         ff->ff_fsize  = ff->ffbuf.ff_fsize;
309         memcpy(ff->ff_name, ff->ffbuf.ff_name, sizeof(ff->ff_name));
310         ff->ff_name[sizeof(ff->ff_name) - 1] = '\0';
311 
312 #elif defined(__MSC__) || defined(__WATCOMC__)
313 
314         rc = _dos_findnext(&(ff->ffbuf));
315 
316         ff->ff_attrib = ff->ffbuf.attrib;
317         ff->ff_ftime  = ff->ffbuf.wr_time;
318         ff->ff_fdate  = ff->ffbuf.wr_date;
319         ff->ff_fsize  = ff->ffbuf.size;
320         memcpy(ff->ff_name, ff->ffbuf.name, sizeof(ff->ff_name));
321         ff->ff_name[sizeof(ff->ff_name) - 1] = '\0';
322 
323 #elif defined(__OS2__)
324 
325 #if defined(__FLAT__)
326         ULONG SearchCount = 1;
327         FILEFINDBUF3 findbuf;
328 #else
329         USHORT SearchCount = 1;
330         FILEFINDBUF findbuf;
331 #endif
332 
333         if (ff->hdir && !DosFindNext(ff->hdir, &findbuf, sizeof(findbuf),
334           &SearchCount))
335         {
336             ff->ff_attrib = (char)findbuf.attrFile;
337             ff->ff_ftime = *((USHORT *) & findbuf.ftimeLastWrite);
338             ff->ff_fdate = *((USHORT *) & findbuf.fdateLastWrite);
339             ff->ff_fsize = findbuf.cbFile;
340             strncpy(ff->ff_name, findbuf.achName, sizeof(ff->ff_name));
341             rc = 0;
342         }
343 
344 #elif defined(__UNIX__)
345 
346         int fin = 0;
347         struct dirent *de;
348 
349         while (!fin)
350         {
351             de = readdir(ff->dir);
352             if (de == NULL)
353             {
354                closedir(ff->dir);
355                ff->dir = NULL;
356                fin = 1;
357             }
358             else
359             {
360                 if (patmat(de->d_name, ff->lastbit))
361                 {
362                     strncpy(ff->ff_name, de->d_name, sizeof ff->ff_name);
363 		    ff->ff_fsize = -1L; /* All who wants to know it's size
364 					 * must read it by himself
365 					 */
366 		    fin = 1;
367                     rc = 0;
368                 }
369             }
370         }
371 
372 #elif defined(SASC)
373         int error = 0;
374 
375         error = dnext(&ff->info);
376         if (error == 0)
377         {
378             strcpy(ff->ff_name, ff->prefix);
379             strcat(ff->ff_name, ff->info.fib_FileName);
380             rc = 0;
381         }
382 #elif defined(__RSXNT__) || defined(__MINGW32__) || defined(__MSVC__)
383 
384         do
385         {
386             if (!FindNextFile(ff->hDirA, &(ff->InfoBuf)))
387             {
388                 if (ff->hDirA != INVALID_HANDLE_VALUE)
389                 {
390                     FindClose(ff->hDirA);
391                 }
392                 ff->hDirA = INVALID_HANDLE_VALUE;
393             }
394             else
395             {
396 
397                 if (strlen(ff->InfoBuf.cFileName) < sizeof(ff->ff_name))
398                 {
399                     if ((!(ff->InfoBuf.dwFileAttributes &
400                           FILE_ATTRIBUTE_DIRECTORY)) ||
401                         (ff->attrib_srch & MSDOS_SUBDIR))
402                     {
403                         break;
404                     }
405                 }
406             }
407         } while (ff->hDirA != INVALID_HANDLE_VALUE);
408 
409         if (ff->hDirA != INVALID_HANDLE_VALUE)
410         {
411 
412             strcpy(ff->ff_name, ff->InfoBuf.cFileName);
413             ff->ff_fsize = ff->InfoBuf.nFileSizeLow;
414             ff->ff_attrib = 0;
415             if (ff->InfoBuf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
416             {
417                 ff->ff_attrib |= MSDOS_SUBDIR;
418             }
419             if (ff->InfoBuf.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)
420             {
421                 ff->ff_attrib |= _A_HIDDEN;
422             }
423             rc = 0;
424         }
425 
426 #else
427 #error Unable to determine compiler and target operating system!
428 #endif
429     }
430 
431     return rc;
432 }
433 
434 /*
435  *  FFindClose: End a directory search.  Failure to call this function
436  *  will result in unclosed file handles under OS/2, and unreleased
437  *  memory in both DOS and OS/2.
438  */
439 
FFindClose(FFIND * ff)440 void _fast FFindClose(FFIND * ff)
441 {
442     if (ff != NULL)
443     {
444 #if defined(__TURBOC__) || defined(__DJGPP__)
445 #elif (defined(__WATCOMC__NT__)) || (defined(__MSC__) && !defined(__DOS__))
446         _dos_findclose(&(ff->ffbuf));
447 #elif defined(__OS2__)
448         if (ff->hdir)
449         {
450             DosFindClose(ff->hdir);
451         }
452 #elif defined(__UNIX__)
453         if (ff->dir)
454         {
455             closedir(ff->dir);
456         }
457 #elif defined(SASC)
458 #elif defined(__RSXNT__) || defined(__MINGW32__) || defined(__MSVC__)
459         if (ff->hDirA != INVALID_HANDLE_VALUE)
460         {
461             FindClose(ff->hDirA);
462         }
463 #endif
464         free(ff);
465     }
466 }
467 
468 /*
469  *  FFindInfo: This function was added because it is SIGNIFICANTLY faster
470  *  under OS/2 to call DosQPathInfo() rather than DosFindFirst() if all
471  *  you are interested in is getting a specific file's date/time/size.
472  *
473  *  PLF Thu  10-17-1991  18:12:37
474  */
475 
FFindInfo(const char * filespec)476 FFIND *_fast FFindInfo(const char *filespec)
477 {
478 #if !defined(__OS2__)
479     return FFindOpen(filespec, 0);
480 #else
481     FFIND *ff;
482     FILESTATUS fs;
483     const char *f;
484 
485     ff = malloc(sizeof *ff);
486     if (ff == NULL)
487     {
488         return NULL;
489     }
490 
491     memset(ff, 0, sizeof *ff);
492     if (!DosQPathInfo((PBYTE) filespec, FIL_STANDARD, (PBYTE) &fs, sizeof fs, 0L))
493     {
494         ff->ff_attrib = (char)fs.attrFile;
495         ff->ff_ftime = *((USHORT *) & fs.ftimeLastWrite);
496         ff->ff_fdate = *((USHORT *) & fs.fdateLastWrite);
497         ff->ff_fsize = fs.cbFile;
498 
499         /* isolate file name */
500         f = strrchr(filespec, '\\');
501         if (f == NULL)
502         {
503             f = filespec;
504         }
505         else
506         {
507             f++;
508         }
509         strncpy(ff->ff_name, f, sizeof(ff->ff_name));
510     }
511     else
512     {
513         free(ff);
514         return NULL;
515     }
516     return ff;
517 #endif
518 }
519 
520 #ifdef TEST /* Text functions section ======================================*/
521 
522 #ifndef TRUE
523 #define TRUE 1
524 #endif
525 
526 #ifndef FALSE
527 #define FALSE 0
528 #endif
529 
530 /* this simple function assumes the path ALWAYS has an ending backslash */
531 
walk(char * path)532 int walk(char *path)
533 {
534     FFIND *ff;
535     int done = FALSE;
536     char full[127];
537 
538     strcpy(full, path);
539 #ifdef MSDOS
540     strcat(full, "*.*");
541 #else
542     strcat(full, "*");
543 #endif
544 
545     ff = FFindOpen(full, MSDOS_SUBDIR);
546     if (ff != NULL)
547     {
548         done = FALSE;
549         while (done != TRUE)
550         {
551             if (ff->ff_attrib & MSDOS_SUBDIR && ff->ff_name[0] != '.')
552             {
553                 strcpy(full, path);
554                 strcat(full, ff->ff_name);
555                 puts(full);
556 #ifndef __UNIX__
557                 strcat(full, "\\");
558 #else
559                 strcat(full, "/");
560 #endif
561                 if (!walk(full))
562                 {
563                     return FALSE;
564                 }
565             }
566             done = FFindNext(ff) != 0;
567         }
568         FFindClose(ff);
569         return TRUE;
570     }
571     else
572     {
573         puts("FFindOpen() failed!");
574     }
575     return FALSE;
576 }
577 
main(void)578 int main(void)
579 {
580 #ifndef __UNIX__
581     return walk("\\") == TRUE ? EXIT_SUCCESS : EXIT_FAILURE;
582 #else
583     return walk("/") == TRUE ? EXIT_SUCCESS : EXIT_FAILURE;
584 #endif
585 }
586 
587 #endif
588