1 /*
2 * This file is part of the XForms library package.
3 *
4 * XForms is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as
6 * published by the Free Software Foundation; either version 2.1, or
7 * (at your option) any later version.
8 *
9 * XForms is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with XForms. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18
19 /**
20 * \file listdir.c
21 *
22 * This file is part of the XForms library package.
23 * Copyright (c) 1996-2002 T.C. Zhao
24 * All rights reserved.
25 *
26 * Read a directory. Hightly system dependent.
27 * Seems opendir/readdir/closedir is the most portable.
28 *
29 * Original BSD scandir is emulated using the opendir stuff.
30 *
31 * This file has no xforms dependencies
32 */
33
34 #ifdef HAVE_CONFIG_H
35 #include "config.h"
36 #endif
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <limits.h>
42 #include <ctype.h>
43 #include <sys/types.h>
44
45 #ifndef _WIN32
46 #include <unistd.h>
47 #else
48 #include <io.h>
49 #include <time.h>
50 #include <direct.h>
51 #define FL_WIN32
52 #endif
53
54 /* vms 7.0 has dirent.h */
55
56 #if defined(__VMS) && __VMS_VER < 70000000
57 #include "dirent_vms.h"
58 #endif
59
60 /* Work around the bugs in various cpp */
61
62 #if defined Lynx && ! defined __VMS
63 #include <dir.h>
64 #include <dirent.h>
65 #endif
66
67 #if ! defined __VMS && ! defined Lynx && ! defined FL_WIN32
68 #include <dirent.h>
69 #endif
70
71 #include <sys/stat.h>
72 #include "include/forms.h" /* for definitation of FL_EXPORT */
73 #include "flinternal.h"
74 #include "local.h"
75 #include "ulib.h"
76
77
78
79 /******** limits and macros *********/
80
81 #ifndef S_ISREG
82 #define S_ISREG( m ) ( ( ( m ) & S_IFREG ) == S_IFREG )
83 #define S_ISDIR( m ) ( ( ( m ) & S_IFDIR ) == S_IFDIR )
84 #endif
85
86 #if defined (__EMX__) || defined (FL_WIN32) || defined (opennt)
87 #define S_ISLNK( m ) 0 /* no links in OS/2 */
88 #define S_ISBLB( m ) 0 /* no blk devices in OS2 */
89 #else
90 #ifndef S_ISLNK
91 #define S_ISLNK( m ) ( ( ( m ) & S_IFLNK ) == S_IFLNK )
92 #endif
93 #ifndef S_ISBLK
94 #define S_ISBLK( m ) ( ( ( m ) & S_IFBLK ) == S_IFBLK )
95 #endif
96 #endif /* __EMX__ */
97
98 #ifndef S_ISCHR
99 #define S_ISCHR( m ) ( ( ( m ) & S_IFCHR ) == S_IFCHR )
100 #endif
101
102 #ifndef S_ISSOCK
103 # if defined( S_IFSOCK )
104 # ifdef S_IFMT
105 # define S_ISSOCK( m ) ( ( ( m ) & S_IFMT ) == S_IFSOCK )
106 # else
107 # define S_ISSOCK( m ) ( ( m ) & S_IFSOCK )
108 # endif /* S_IFMT */
109 # elif defined( S_ISNAM )
110 /* SCO OpenServer 5.0.7 */
111 # define S_ISSOCK S_ISNAM
112 # endif /* !S_IFSOCK && S_ISNAM */
113 #endif /* !S_ISSOCK */
114
115 #define MAXCACHE 10 /* upto MAXCACHE dir will be cached */
116 #define MAXFL ( FL_PATH_MAX + FL_FLEN )/* maximum file length */
117
118 #ifndef StrReDup
119 #define StrReDup( a, b ) do \
120 { \
121 if( a ) \
122 fl_free( a ); \
123 a = fl_strdup( b ); \
124 } while( 0 )
125 #endif
126
127 #if defined NEED_DIRECT
128 #define DIRENT direct
129 #else
130 #define DIRENT dirent
131 #endif
132
133 #if defined NEED_GETCWD
134 #if defined Lynx
135
136 /***************************************
137 ***************************************/
138
139 char *
getcwd(char * a,int b)140 getcwd( char * a,
141 int b )
142 {
143 return getwd( a );
144 }
145
146 #endif
147 #if defined __VMS
148 #define getcwd( a, b ) getcwd( a, b, 0 ) /* use unix file/path syntax */
149 #endif
150 #endif
151
152 #ifdef FL_WIN32
153
154 /***************************************
155 * Convert the backslash to slash
156 ***************************************/
157
158 static char *
fl_b2f_slash(char * dir)159 fl_b2f_slash( char *dir )
160 {
161 char *p = dir;
162
163 while ( ( p = strchr( p, '\\' ) ) )
164 *p = '/';
165
166 return dir;
167 }
168
169 #else
170 #define fl_b2f_slash( a )
171 #endif
172
173 /************* local variables ****************/
174
175 static const char *cpat; /* current pattern */
176 static const char *cdir; /* current working directory */
177 static char fname[ MAXFL + 2 ];
178
179 #define FL_NONE 0
180
181 /******* local function forward dec **********/
182
183 static int fli_wildmat( const char *,
184 const char * );
185 static int tc_sort( const void *,
186 const void * );
187 static int tc_scandir( const char *,
188 struct DIRENT *** );
189
190 static int default_filter( const char *,
191 int );
192
193 /* default filter and sort method */
194
195 int fli_sort_method = FL_ALPHASORT;
196 static FL_DIRLIST_FILTER ffilter = default_filter;
197 static int filter_directory = 0; /* true to filter directory entries */
198
199 /*
200 * convert native file types to FL
201 */
202
203 #ifndef FL_WIN32 /* [ */
204
205
206 /***************************************
207 ***************************************/
208
209 static void
mode2type(unsigned int mode,int * type)210 mode2type( unsigned int mode,
211 int * type )
212 {
213 if ( S_ISDIR( mode ) )
214 *type = FT_DIR;
215 else if ( S_ISREG( mode ) )
216 *type = FT_FILE;
217 else if ( S_ISLNK( mode ) )
218 *type = FT_LINK;
219 else if ( S_ISSOCK(mode ) )
220 *type = FT_SOCK;
221 else if ( S_ISFIFO( mode ) )
222 *type = FT_FIFO;
223 else if ( S_ISCHR( mode ) )
224 *type = FT_CHR;
225 #if !defined __EMX__
226 else if ( S_ISBLK( mode ) )
227 *type = FT_BLK;
228 #endif
229 else
230 *type = FT_OTHER;
231 }
232
233
234 /******************************************************************
235 * Filter the filename before handing it over to the "file is here"
236 * list. Per default only files (including links) are shown.
237 ******************************************************************/
238
239 static int
fselect(const char * d_name,struct stat * ffstat,int * type)240 fselect( const char * d_name,
241 struct stat * ffstat,
242 int * type )
243 {
244 int ret = 0;
245 unsigned int mode;
246
247 strcat( strcpy( fname, cdir), d_name );
248 stat( fname, ffstat );
249 mode = ffstat->st_mode;
250 mode2type( mode, type );
251
252 if ( ! ffilter )
253 ret = 1;
254 else if ( ffilter == default_filter )
255 {
256 /* Always keep directory and links */
257
258 ret = S_ISDIR(mode)
259 || ( ( S_ISREG( mode ) || S_ISLNK( mode ) )
260 && fli_wildmat( d_name, cpat ) );
261 }
262 else
263 {
264 /* We don't filter directories unless requested */
265
266 if ( ! filter_directory )
267 ret = *type == FT_DIR
268 || ( fli_wildmat( d_name, cpat ) && ffilter( fname, *type ) );
269 else
270 ret = ( *type == FT_DIR || fli_wildmat( d_name, cpat ) )
271 && ffilter( fname, *type );
272 }
273
274 return ret;
275 }
276
277 #else /* WIN 32 ][ */
278
279 /***************************************
280 ***************************************/
281
282 static int
fselect(struct _finddata_t * c_file,FL_Dirlist * dl)283 fselect( struct _finddata_t * c_file,
284 FL_Dirlist * dl )
285 {
286 int type,
287 ret = 0;
288
289 if ( c_file->attrib & _A_SUBDIR )
290 type = FT_DIR;
291 else
292 type = FT_FILE;
293
294 if ( ! ffilter )
295 ret = 1;
296 else if ( ffilter == default_filter ) /* always keep directory and links */
297 ret = type == FT_DIR || fli_wildmat( c_file->name, cpat );
298 else
299 {
300 strcat( strcpy( fname, cdir ), c_file->name );
301 ret = type == FT_DIR
302 || ( flo_wildmat( c_file->name, cpat )
303 && ffilter( fname, type ) );
304 }
305
306 if ( ret )
307 {
308 dl->name = fl_strdup( c_file->name );
309 dl->type = type;
310 dl->dl_mtime = c_file->time_write;
311 dl->dl_size = c_file->size;
312 }
313 return ret;
314 }
315
316 #endif /* FL_WIN32 ] */
317
318
319 /***************************************
320 * Sort the directory entries according to the sort method
321 ***************************************/
322
323 static int
tc_sort(const void * a,const void * b)324 tc_sort( const void * a,
325 const void * b )
326 {
327 FL_Dirlist *da = ( FL_Dirlist * ) a;
328 FL_Dirlist *db = ( FL_Dirlist * ) b;
329
330 switch ( fli_sort_method )
331 {
332 case FL_RALPHASORT:
333 return strcmp( db->name, da->name );
334
335 case FL_RCASEALPHASORT:
336 return strcasecmp( db->name, da->name );
337
338 case FL_MTIMESORT:
339 return da->dl_mtime - db->dl_mtime;
340
341 case FL_RMTIMESORT:
342 return db->dl_mtime - da->dl_mtime;
343
344 case FL_SIZESORT:
345 return da->dl_size > db->dl_size ?
346 1 : ( da->dl_size == db->dl_size ? 0 : -1 );
347
348 case FL_RSIZESORT:
349 return da->dl_size < db->dl_size ?
350 1 : ( da->dl_size == db->dl_size ? 0 : -1 );
351
352 case FL_CASEALPHASORT:
353 return strcasecmp( da->name, db->name );
354
355 case FL_ALPHASORT:
356 default:
357 return strcmp( da->name, db->name );
358 }
359 }
360
361
362 /*******************************************************************
363 * On entry, dir must be no zero and be terminated properly, i.e.,
364 * ends with /
365 *******************************************************************/
366
367 #ifndef FL_WIN32
368
369 static int
scandir_get_entries(const char * dir,const char * pat,FL_Dirlist ** dirlist)370 scandir_get_entries( const char * dir,
371 const char * pat,
372 FL_Dirlist ** dirlist )
373 {
374 static struct DIRENT **dlist;
375 FL_Dirlist *dl;
376 static int lastn;
377 static struct stat ffstat;
378 int n = 0;
379
380 cpat = pat;
381 cdir = dir;
382
383 /* Free all memory used last time we were here */
384
385 if ( dlist )
386 {
387 while ( --lastn >= 0 )
388 if ( dlist[ lastn ] )
389 fl_free( dlist[ lastn ]);
390 fl_free( dlist );
391 dlist = NULL;
392 }
393
394 if ( ( lastn = tc_scandir( dir, &dlist ) ) > 0 )
395 {
396 int i;
397
398 dl = *dirlist = fl_malloc( ( lastn + 1 ) * sizeof **dirlist );
399
400 for ( i = n = 0; i < lastn; i++ )
401 {
402 if ( fselect( dlist[ i ]->d_name, &ffstat, &dl->type ) )
403 {
404 dl->name = fl_strdup( dlist[ i ]->d_name );
405 dl->dl_mtime = ffstat.st_mtime;
406 dl->dl_size = ffstat.st_size;
407 dl++;
408 n++;
409 }
410 }
411
412 dl->name = NULL; /* sentinel */
413
414 if ( fli_sort_method != FL_NONE )
415 qsort( *dirlist, n, sizeof **dirlist, tc_sort );
416 }
417
418 return n;
419 }
420
421 #else /* FL_WIN32 */
422
423 /***************************************
424 ***************************************/
425
426 static int
scandir_get_entries(const char * dir,const char * pat,FL_Dirlist ** dirlist)427 scandir_get_entries( const char * dir,
428 const char * pat,
429 FL_Dirlist ** dirlist )
430 {
431 FL_Dirlist *dl;
432 char cwd[ FL_PATH_MAX ];
433 struct _finddata_t c_file;
434 long hFile;
435 int n, lastn;
436
437 cpat = pat;
438 cdir = dir;
439 n = 0;
440
441 /* Save the working directory */
442
443 getcwd( cwd, FL_PATH_MAX );
444 if ( chdir( dir ) != 0 ) /* invalid directory */
445 return 0;
446
447 /* Find all files matched the pattern in current directory */
448
449 if ( ( hFile = _findfirst( "*", &c_file ) ) == -1L )
450 {
451 /* Directory is empty, nothing to do */
452
453 chdir( cwd );
454 return 0;
455 }
456
457 lastn = 10;
458 dl = *dirlist = fl_malloc( ( lastn + 1 ) * sizeof **dirlist );
459
460 if ( fselect( &c_file, dl ) )
461 {
462 dl++;
463 n++;
464 }
465
466 /* Find the rest of the files */
467
468 while ( _findnext( hFile, &c_file ) == 0 )
469 {
470 if ( fselect( &c_file, dl ) )
471 {
472 dl++;
473 n++;
474 if ( n > lastn )
475 {
476 lastn += 10;
477 *dirlist = fl_realloc( *dirlist,
478 ( lastn + 1 ) * sizeof **dirlist );
479 dl = *dirlist + n;
480 }
481 }
482 }
483
484 _findclose( hFile );
485 chdir( cwd );
486
487 dl->name = NULL; /* sentinel */
488
489 if ( fli_sort_method != FL_NONE )
490 qsort( *dirlist, n, sizeof **dirlist, tc_sort );
491
492 return n;
493 }
494
495 #endif /* FL_WIN32 */
496
497
498 /********************************************************************
499 * The user routine.
500 *
501 * Get a list of files in directory, subject to pattern matching,
502 * and return the file list. Rescan will force a read even the requested
503 * directory is cached.
504 *
505 ********************************************************************/
506
507 static char *lastdir[ MAXCACHE ],
508 *lastpat[ MAXCACHE ];
509 static int lastn[ MAXCACHE ],
510 last_sort[ MAXCACHE ];
511 static FL_Dirlist *dirlist[ MAXCACHE ];
512
513
514 /********************************************************************
515 * Check if a particular directory is cached
516 ********************************************************************/
517
518 static int
is_cached(const char * dir,const char * pat,int * c)519 is_cached( const char * dir,
520 const char * pat,
521 int * c )
522 {
523 int cached = 0,
524 i = 0;
525 static int lastcache;
526
527 do
528 {
529 cached = lastpat[ i ]
530 && lastdir[ i ]
531 && strcmp( lastdir[ i ], dir ) == 0
532 && strcmp( lastpat[ i ], pat ) == 0
533 && dirlist[ i ]
534 && dirlist[ i ]->name;
535 *c = i++;
536 }
537 while ( ! cached && i < MAXCACHE );
538
539 /* search for the least used slot if not cached */
540
541 if ( ! cached )
542 *c = ++lastcache % MAXCACHE;
543
544 lastcache = *c;
545 M_info( "is_cached", "%s is %s cached", dir, cached ? "" : "not" );
546 return cached;
547 }
548
549
550 /***************************************
551 ***************************************/
552
553 void
fl_free_dirlist(FL_Dirlist * dl)554 fl_free_dirlist( FL_Dirlist * dl )
555 {
556 size_t i;
557
558 for ( i = 0; i < MAXCACHE; i++ )
559 if ( dl == dirlist[ i ] )
560 break;
561
562 if ( i >= MAXCACHE )
563 {
564 M_err( "fl_free_dirlist", "Bad list" );
565 return;
566 }
567
568 while ( dl && dl->name )
569 {
570 fl_free( dl->name );
571 dl->name = NULL; /* important: signifies empty list */
572 dl++;
573 }
574
575 if ( dirlist[ i ] )
576 {
577 fl_free( dirlist[ i ] );
578 dirlist[ i ] = NULL;
579 }
580 }
581
582
583 /**********************************************************************
584 * The user callable routine to read a directory
585 *********************************************************************/
586
587 const FL_Dirlist *
fl_get_dirlist(const char * dir,const char * pattern,int * n,int rescan)588 fl_get_dirlist( const char * dir,
589 const char * pattern,
590 int * n,
591 int rescan )
592 {
593 int i,
594 c;
595 const char *pat = pattern;
596 char okdir[ FL_PATH_MAX + 1 ];
597
598 if ( ! dir || ! *dir )
599 return NULL;
600
601 if ( ! pat || ! *pat )
602 pat = "*";
603
604 /* Fix the directory on the fly */
605
606 i = strlen( strcpy( okdir, dir ) );
607 if ( okdir[ i - 1 ] != '/' )
608 {
609 okdir[ i ] = '/';
610 okdir[ ++i ] = '\0';
611 }
612
613 /* is_cached must go first to get correct cache location */
614
615 if ( ! is_cached( okdir, pat, &c ) || rescan )
616 {
617 fl_free_dirlist( dirlist[ c ] );
618 lastn[ c ] = scandir_get_entries( okdir, pat, dirlist + c );
619 last_sort[ c ] = fli_sort_method;
620 StrReDup( lastpat[ c ], pat );
621 StrReDup( lastdir[ c ], okdir );
622 }
623
624 *n = lastn[ c ];
625 if ( last_sort[ c ] != fli_sort_method )
626 {
627 qsort( dirlist[ c ], *n, sizeof **dirlist, tc_sort );
628 last_sort[ c ] = fli_sort_method;
629 }
630
631 return dirlist[ c ];
632 }
633
634
635 /***********************************************************************
636 * Misc. routines related to directory handling
637 **********************************************************************/
638
639 int
fli_is_valid_dir(const char * name)640 fli_is_valid_dir( const char *name )
641 {
642 struct stat stbuf;
643
644 #ifdef __EMX__
645 if ( name
646 && isalpha( ( unsigned char ) name[ 0 ] )
647 && name[ 1 ] == ':'
648 && name[ 2 ] == '0' )
649 return 1;
650 #endif
651
652 /* On some machines name should be a plain char * (why? JTT) */
653
654 return name
655 && *name
656 && ! stat( ( char * ) name, &stbuf )
657 && S_ISDIR( stbuf.st_mode );
658 }
659
660
661 /***************************************
662 * Fix directory names such as ../../a/b etc
663 ***************************************/
664
665 static void add_one( char *,
666 char * );
667
668 char *
fli_fix_dirname(char * dir)669 fli_fix_dirname( char * dir )
670 {
671 static char ldir[ FL_PATH_MAX ],
672 one[ FL_PATH_MAX ];
673 char *p = ldir,
674 *q = one;
675
676 fl_b2f_slash( dir );
677
678 if ( ! *dir ) /* Here's some bullshit going one, what's ldir set to ? */
679 return fli_getcwd( dir ? dir : ldir, FL_PATH_MAX - 2 );
680 else if ( dir[ 0 ] == '.' && dir[ 1 ] == '.' && dir[ 2 ] == '\0' )
681 {
682 fli_getcwd( dir ? dir : ldir, FL_PATH_MAX - 2 );
683 if ( ( p = strrchr( dir ? dir : ldir, '/' ) ) )
684 *p = '\0';
685 return dir ? dir : ldir;
686 }
687 else if ( *dir == '/')
688 {
689 if ( dir[ 1 ] == '\0'
690 || ( dir[ 1 ] == '.' && dir[ 2 ] == '.'
691 && ( dir[ 3 ] == '/' || dir[ 3 ] == '\0' ) ) )
692 return strcpy( dir, "/" );
693 }
694 strcpy( ldir, dir );
695 p = ldir;
696
697 #if defined __EMX__ || defined FL_WIN32
698 if ( isalpha( ( unsigned char ) ldir[ 0 ] )
699 && ldir[ 1 ] == ':' )
700 { /* drive letter */
701 dir[ 0 ] = ldir[ 0 ];
702 dir[ 1 ] = ldir[ 1 ];
703 dir[ 2 ] = '\0';
704 p = ldir + 2;
705 }
706 else
707 #elif defined opennt
708 if ( ldir[ 0 ] == '/' && ldir[ 1 ] == '/'
709 && isalpha( ( unsigned char ) ldir[ 2 ] ) )
710 { /* //E is E dirver */
711 dir[ 0 ] = ldir[ 0 ];
712 dir[ 1 ] = ldir[ 1 ];
713 dir[ 2 ] = ldir[ 2 ];
714 dir[ 3 ] = '\0';
715 p = ldir + 3;
716 }
717 else
718 #endif
719 if ( ldir[ 0 ] != '/' && ldir[ 0 ] != '~' )
720 fli_getcwd( dir, FL_PATH_MAX - 2 );
721 else
722 dir[ 0 ] = '\0';
723
724 while ( *p )
725 {
726 #ifdef __EMX__
727 if ( *p == '/' || *p == '\\' )
728 {
729 #else
730 if ( *p == '/' )
731 {
732 #endif
733 *q = '\0';
734 if ( q > one )
735 add_one( dir, q = one );
736 }
737 else
738 *q++ = *p;
739 p++;
740 }
741
742 *q = '\0';
743 if ( q > one )
744 add_one( dir, one );
745
746 #if defined __EMX__ || defined FL_WIN32
747 if ( strlen( dir ) == 2 && dir[ 1 ] == ':' )
748 { /* fix a single "C:" */
749 dir[ 2 ] = '/';
750 dir[ 3 ] = '\0';
751 }
752 #endif
753
754 #if defined opennt
755 if ( strlen( dir ) == 3
756 && dir[ 0 ] == '/'
757 && dir[ 1 ] == '/'
758 && isalpha( ( unsigned char ) ldir[ 2 ] ) )
759 { /* fix "//C" */
760 dir[ 3 ] = '/';
761 dir[ 4 ] = '\0';
762 }
763 #endif
764
765 fl_b2f_slash( dir );
766
767 return dir;
768 }
769
770
771 #ifndef FL_WIN32
772 #include <pwd.h>
773 #endif
774
775 /***************************************
776 ***************************************/
777
778 static void
779 add_one( char * dir,
780 char * one )
781 {
782 char *q;
783
784 if ( one[ 0 ] == '.' && one[ 1] == '.' && one[ 2 ] == '\0' )
785 {
786 if ( ( q = strrchr( dir, '/' ) ) )
787 *( q + ( q == dir ) ) = '\0';
788 #ifndef FL_WIN32
789 }
790 else if ( one[ 0 ] == '~' )
791 {
792 if ( one[ 1 ] == '\0' )
793 { /* must be ~/ ... */
794 strcat( dir, ( q = getenv( "HOME" ) ) ? q : "/" );
795 }
796 else
797 { /* must be ~name */
798 /* Mathod: vms <7.0 has no getpwnam(). Ignore ~name */
799 #if !defined __VMS || __VMS_VER >= 70000000
800 struct passwd *p = getpwnam( one + 1 );
801
802 strcat( dir, p ? p->pw_dir : "/" );
803 #ifndef opennt
804 endpwent( );
805 #endif
806 #endif
807 }
808 #endif /* FL_WIN32 */
809 }
810 else if ( ! ( one[0] == '.' && one[ 1 ] == '\0' ) )
811 {
812 strcat( strcat( dir, "/" ), one );
813 }
814
815 #ifdef __VMS
816 /* VMS has directory extensions, strip it */
817 {
818 int n = strlen( dir );
819 char *p;
820
821 if ( n > 4 )
822 {
823 for ( p = dir + n - 4; *p; p++ )
824 *p = toupper( *p );
825 if ( strcmp( ( p = dir + n - 4 ), ".DIR" ) == 0 )
826 *p = '\0';
827 }
828 }
829 #endif
830 }
831
832
833 /* String matching routine is adapted from Rick Salz */
834
835 static int match_star( const char * s,
836 const char * p );
837
838
839 /***************************************
840 * Match string "s" to pattern "p"
841 ***************************************/
842
843 static int
844 do_matching( const char * s,
845 const char * p )
846 {
847 int last,
848 matched,
849 reverse;
850
851 for ( ; *p; s++, p++ )
852 {
853 if ( *s == '\0' )
854 return *p == '*' && *++p == '\0' ? 1 : -1;
855
856 switch ( *p ) /* parse pattern */
857 {
858 case '\\': /* Literal match with following character. */
859 if ( *s != *++p )
860 return 0;
861 continue;
862
863 default: /* literal match */
864 #ifdef __VMS /* vms filenames are not case sensitive */
865 if ( toupper( *s ) != toupper( *p ) )
866 #else
867 if ( *s != *p )
868 #endif
869 return 0;
870 continue;
871
872 case '?': /* Match anything. */
873 continue;
874
875 case '*': /* Trailing star matches everything. */
876 return *++p ? match_star( s, p ) : 1;
877
878 case '[': /* [!....] means inverse character class. */
879 if ( ( reverse = ( p[ 1 ] == '!' ) ) )
880 p++;
881 for ( last = 0400, matched = 0; *++p && *p != ']'; last = *p )
882 if ( ( *p == '-' && *s <= *++p && *s >= last )
883 || ( *p != '-' && *s == *p ) )
884 matched = 1;
885 if ( matched == reverse )
886 return 0;
887 continue;
888 }
889 }
890
891 return *s == '\0';
892 }
893
894
895 /***************************************
896 ***************************************/
897
898 static int
899 match_star( const char * s,
900 const char * p )
901 {
902 int result;
903
904 while ( ( result = do_matching( s, p ) ) == 0 ) /* gobble up * match */
905 if ( *++s == '\0' )
906 return -1;
907
908 return result;
909 }
910
911
912
913 /***************************************
914 * check if s matches pattern p
915 ***************************************/
916
917 static int
918 fli_wildmat( const char * s,
919 const char * p )
920 {
921 if ( *p == '\0' && *s != '.' )
922 return 1;
923 else if ( *p == '\0' )
924 return 0;
925 else if ( ( *p == '?' || *p == '*' ) && *s == '.' )
926 return 0;
927 else
928 return do_matching( s, p ) == 1;
929 }
930
931
932 /***************************************
933 * scandir emulation
934 ***************************************/
935
936 #ifndef FL_WIN32
937
938 static int
939 tc_scandir( const char * dirname,
940 struct DIRENT *** namelist )
941 {
942 DIR *dir;
943 struct DIRENT *dentry,
944 **head = NULL;
945 int n = 0,
946 total;
947 static int dname_is_1;
948
949 if ( ! ( dir = opendir( dirname ) ) )
950 return -1;
951
952 if ( sizeof( struct DIRENT ) < 100 && ! dname_is_1 )
953 {
954 M_warn("tc_scandir", "Bad dirent -- will fix it on the fly" );
955 dname_is_1 = 1;
956 }
957
958 /* Start reading the darn thing */
959
960 for ( n = 0; ( dentry = readdir( dir ) ) != NULL; n++ )
961 {
962 head = fl_realloc( head, ( n + 1 ) * sizeof *head );
963
964 /* Here it is even weirder: some systems have d_reclen =
965 sizeof(struct dirent) + strlen(d_name) and some have it as
966 d_reclen = strlen(d_name) */
967
968 /* Mathog, VMS<7.0, at least has no d_reclen *at all */
969
970 #if defined __VMS && __VMS_VER < 70000000 || defined opennt || defined __CYGWIN__
971 total = dname_is_1 ? strlen( dentry->d_name ) : sizeof *dentry;
972 #else
973 # ifdef __DragonFly__
974 total = dname_is_1 ? _DIRENT_RECLEN(dentry->d_namlen) : sizeof *dentry;
975 # else
976 total = dname_is_1 ? dentry->d_reclen : sizeof *dentry;
977 # endif
978 #endif
979 memcpy( head[ n ] = fl_malloc( total ), dentry, total );
980 }
981
982 closedir( dir );
983 *namelist = head;
984
985 return n;
986 }
987
988 #endif /* ! FL_WIN32 */
989
990
991 /***************************************
992 ***************************************/
993
994 FL_DIRLIST_FILTER
995 fl_set_dirlist_filter( FL_DIRLIST_FILTER filter )
996 {
997 FL_DIRLIST_FILTER old = ffilter;
998
999 ffilter = filter;
1000 return old;
1001 }
1002
1003
1004 /***************************************
1005 ***************************************/
1006
1007 int
1008 fl_set_dirlist_filterdir( int yes )
1009 {
1010 int old = filter_directory;
1011
1012 filter_directory = yes;
1013 return old;
1014 }
1015
1016
1017 /***************************************
1018 * for application's benifit
1019 ***************************************/
1020
1021 static int
1022 default_filter( const char * name FL_UNUSED_ARG,
1023 int type )
1024 {
1025 return type == FT_FILE || type == FT_DIR || type == FT_LINK;
1026 }
1027
1028
1029 /***************************************
1030 ***************************************/
1031
1032 int
1033 fl_set_dirlist_sort( int method )
1034 {
1035 int old = fli_sort_method;
1036
1037 fli_sort_method = method;
1038 return old;
1039 }
1040
1041 #ifdef __VMS
1042 #include "vms_readdir.c"
1043 #endif
1044
1045
1046 /***************************************
1047 ***************************************/
1048
1049 char *
1050 fli_getcwd( char * buf,
1051 int len )
1052 {
1053 #ifdef FL_WIN32
1054 return fl_b2f_slash( getcwd( buf, len ) );
1055 #else
1056 return getcwd( buf, len );
1057 #endif
1058
1059
1060 }
1061
1062
1063 /*
1064 * Local variables:
1065 * tab-width: 4
1066 * indent-tabs-mode: nil
1067 * End:
1068 */
1069