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