OSDN Git Service

Honour GLOB_CASEMATCH for globbing sets; cf. issue [#2327].
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / glob.c
1 /*
2  * glob.c
3  *
4  * MinGW implementation of (approximately) POSIX conforming glob() and
5  * globfree() API functions.
6  *
7  * $Id$
8  *
9  * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
10  * Copyright (C) 2011-2014, 2017, MinGW.org Project.
11  *
12  *
13  * Permission is hereby granted, free of charge, to any person obtaining a
14  * copy of this software and associated documentation files (the "Software"),
15  * to deal in the Software without restriction, including without limitation
16  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17  * and/or sell copies of the Software, and to permit persons to whom the
18  * Software is furnished to do so, subject to the following conditions:
19  *
20  * The above copyright notice, this permission notice, and the following
21  * disclaimer shall be included in all copies or substantial portions of
22  * the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  *
32  */
33 #include <glob.h>
34 #include <ctype.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <libgen.h>
39 #include <dirent.h>
40 #include <errno.h>
41
42 enum {
43   /* Extend the flags offset enumeration, beyond the user visible
44    * high water mark, to accommodate some additional flags which are
45    * required for private use by the implementation.
46    */
47   __GLOB_DIRONLY_OFFSET = __GLOB_FLAG_OFFSET_HIGH_WATER_MARK,
48   __GLOB_PERIOD_PRIVATE_OFFSET,
49   /*
50    * For congruency, set a new high water mark above the private data
51    * range, (which we don't otherwise use).
52    */
53   __GLOB_PRIVATE_FLAGS_HIGH_WATER_MARK
54 };
55
56 #define GLOB_DIRONLY    __GLOB_FLAG__(DIRONLY)
57 #ifndef GLOB_PERIOD
58 # define GLOB_PERIOD    __GLOB_FLAG__(PERIOD_PRIVATE)
59 #endif
60
61 #ifndef GLOB_INLINE
62 # define GLOB_INLINE    static __inline__ __attribute__((__always_inline__))
63 #endif
64
65 #if defined _WIN32 || defined __MS_DOS__
66 /*
67  * For the Microsoft platforms, we treat '\' and '/' interchangeably
68  * as directory separator characters...
69  */
70 #define GLOB_DIRSEP             ('\\')
71 # define glob_is_dirsep( c )    (((c) == ('/')) || ((c) == GLOB_DIRSEP))
72 /*
73  * ...and we substitute whatever may have been predefined as the
74  * manifest constant __CRT_GLOB_ESCAPE_CHAR__, (nominally ASCII DEL,
75  * a.k.a. RUBOUT), as an alternative escape character.
76  */
77 # ifdef __CRT_GLOB_ESCAPE_CHAR__
78 #  define GLOB_HARD_ESC         __CRT_GLOB_ESCAPE_CHAR__
79 # else
80 #  define GLOB_HARD_ESC         ((char)(127))
81 # endif
82
83 static int glob_escape_char = GLOB_HARD_ESC;
84
85 GLOB_INLINE char *glob_strdup( const char *pattern )
86 {
87   /* An inline wrapper around the standard strdup() function;
88    * this strips instances of the GLOB_HARD_ESC character, which
89    * have not themselves been escaped, from the strdup()ed copy.
90    */
91   char buf[1 + strlen( pattern )];
92   char *copy = buf; const char *origin = pattern;
93   do { if( *origin == GLOB_HARD_ESC ) ++origin;
94        *copy++ = *origin;
95      } while( *origin++ );
96   return strdup( buf );
97 }
98
99 #else
100 /* Otherwise, we assume only the POSIX standard '/'...
101  */
102 #define GLOB_DIRSEP             ('/')
103 # define glob_is_dirsep( c )    ((c) == GLOB_DIRSEP)
104 /*
105  * ...and we interpret '\', as specified by POSIX, as
106  * the escape character.
107  */
108 static int glob_escape_char = '\\';
109
110 #define glob_strdup     strdup
111 #endif
112
113 static int is_glob_pattern( const char *pattern, int flags )
114 {
115   /* Check if "pattern" represents a globbing pattern
116    * with included wild card characters.
117    */
118   register const char *p;
119   register int c;
120
121   /* Proceed only if specified pattern is not NULL...
122    */
123   if( (p = pattern) != NULL )
124   {
125     /* ...initially, with no bracketted character set open;
126      * (none can be, because we haven't yet had any opportunity
127      * to see the opening bracket).
128      */
129     int bracket = 0;
130
131     /* Check each character in "pattern" in turn...
132      */
133     while( (c = *p++) != '\0' )
134     {
135       /* ...proceeding since we have not yet reached the NUL terminator.
136        */
137       if(  ((flags & GLOB_NOESCAPE) == 0)
138       &&  (c == glob_escape_char) && (*p++ == '\0')  )
139         /*
140          * We found an escape character, (and the escape mechanism has
141          * not been disabled), but there is no following character to
142          * escape; it may be malformed, but this certainly doesn't look
143          * like a candidate globbing pattern.
144          */
145         return 0;
146
147       else if( bracket == 0 )
148       {
149         /* Still outside of any bracketted character set...
150          */
151         if( (c == '*') || (c == '?') )
152           /*
153            * ...either of these makes "pattern" an explicit
154            * globbing pattern...
155            */
156           return 1;
157
158         if( c == '[' )
159           /*
160            * ...while this marks the start of a bracketted
161            * character set.
162            */
163           bracket++;
164       }
165
166       else if( (bracket > 1) && (c == ']') )
167         /*
168          * Within a bracketted character set, where it is not
169          * the first character, ']' marks the end of the set,
170          * making "pattern" a globbing pattern.
171          */
172         return 1;
173
174       else if( c != '!' )
175         /*
176          * Also within a bracketted character set, '!' is special
177          * when the first character, and shouldn't be counted; note
178          * that it should be counted when not the first character,
179          * but the short count resulting from ignoring it doesn't
180          * affect our desired outcome.
181          */
182         bracket++;
183     }
184   }
185
186   /* If we get to here, then we ran off the end of "pattern" without
187    * identifying it as a globbing pattern.
188    */
189   return 0;
190 }
191
192 static const char *glob_set_adjusted( const char *pattern, int flags )
193 {
194   /* Adjust the globbing pattern pointer, to make it refer to the
195    * next character (if any) following a character set specification;
196    * this adjustment is required when pattern matching is to resume
197    * after matching a set specification, irrespective of whether the
198    * match was successful or not; (a failed match is the desired
199    * outcome for an excluded character set).
200    */
201   register const char *p = pattern;
202
203   /* We need to move the pointer forward, until we find the ']'
204    * which marks the end of the set specification.
205    */
206   while( *p != ']' )
207   {
208     /* We haven't found it yet; advance by one character...
209      */
210     if( (*p == glob_escape_char) && ((flags & GLOB_NOESCAPE) == 0) )
211       /*
212        * ...or maybe even two, when we identify a need to
213        * step over any character which has been escaped...
214        */
215       p++;
216
217     if( *p++ == '\0' )
218       /*
219        * ...but if we find a NUL on the way, then the pattern
220        * is malformed, so we return NULL to report a bad match.
221        */
222       return NULL;
223   }
224   /* We found the expected ']'; return a pointer to the NEXT
225    * character, (which may be ANYTHING; even NUL is okay).
226    */
227   return ++p;
228 }
229
230 GLOB_INLINE int glob_case_match( int flags, int check, int match )
231 {
232   /* Local helper function, used to facilitate the case insensitive
233    * glob character matching appropriate for MS-Windows systems.
234    */
235   return (flags & GLOB_CASEMATCH) ? check - match
236     : tolower( check ) - tolower( match );
237 }
238
239 static const char *glob_in_set( const char *set, int test, int flags )
240 {
241   /* Check if the single character "test" is present in the set
242    * of characters represented by "set", (a specification of the
243    * form "[SET]", or "[!SET]" in the case of an excluded set).
244    *
245    * On entry, "set" always points to the first character in the
246    * set to be tested, i.e. the character FOLLOWING the '[' which
247    * opens an inclusive set, or FOLLOWING the initial '!' which
248    * marks the set as exclusive.
249    *
250    * Matching is ALWAYS performed as if checking an inclusive set;
251    * return value is a pointer to the globbing pattern character
252    * following the closing ']' of "set", when "test" IS in "set",
253    * or NULL when it is not.  Caller performing an inclusive match
254    * should handle NULL as a failed match, and non-NULL as success.
255    * Caller performing an exclusive match should handle non-NULL as
256    * a failed match, with NULL indicating success, and should call
257    * glob_set_adjusted() before resuming pattern matching in the
258    * case of a successful match.
259    */
260   register int c, lastc;
261   if( ((lastc = *set) == ']') || (lastc == '-') )
262   {
263     /* This is the special case of matching ']' or '-' as the
264      * first character in the set, where it must match literally...
265      */
266     if( lastc == test )
267       /*
268        * ...which it does, so immediately report it so.
269        */
270       return glob_set_adjusted( ++set, flags );
271
272     /* ...otherwise we didn't match this special case of ']' or '-',
273      * so we simply ignore this special set entry, thus handling it
274      * as an implicitly escaped literal which has not been matched.
275      */
276     set++;
277   }
278   while( (c = *set++) != ']' )
279   {
280     /* We are still scanning the set, and have not yet reached the
281      * closing ']' sentinel character.
282      */
283     if( (c == '-') && (*set != ']') && ((c = *set++) != '\0') )
284     {
285       /* Since the current character is a '-', and is not immediately
286        * followed by the set's closing sentinel, nor is it at the end
287        * of the (malformed) pattern, it specifies a character range,
288        * running from the last character scanned...
289        */
290       while( lastc < c )
291       {
292         /* ...in incremental collating sequence order, to the next
293          * character following the '-'...
294          */
295         if( glob_case_match( flags, lastc++, test ) == 0 )
296           /*
297            * ...returning immediately on a successful match...
298            */
299           return glob_set_adjusted( set, flags );
300       }
301       while( lastc > c )
302       {
303         /* ...or failing that, consider the possibility that the
304          * range may have been specified in decrementing collating
305          * sequence order...
306          */
307         if( glob_case_match( flags, lastc--, test ) == 0 )
308           /*
309            * ...once again, return immediately on a successful match.
310            */
311           return glob_set_adjusted( set, flags );
312       }
313     }
314
315     if( (c == '\0')
316       /*
317        * This is a malformed set; (not closed before the end of
318        * the pattern)...
319        */
320     ||  glob_is_dirsep( c )  )
321       /*
322        * ...or it attempts to explicitly match a directory separator,
323        * which is invalid in this context.  We MUST fail it, in either
324        * case, reporting a mismatch.
325        */
326       return NULL;
327
328     if( glob_case_match( flags, c, test ) == 0 )
329       /*
330        * We found the test character within the set; adjust the pattern
331        * reference, to resume after the end of the set, and return the
332        * successful match.
333        */
334       return glob_set_adjusted( set, flags );
335
336     /* If we get to here, we haven't yet found the test character within
337      * this set; remember the character within the set which we just tried
338      * to match, as it may represent the start of a character range, then
339      * continue the scan, until we exhaust the set.
340      */
341     lastc = c;
342   }
343   /* Having exhausted the set, without finding a match, we return NULL
344    * to indicate that the test character was NOT found in the set.
345    */
346   return NULL;
347 }
348
349 static int glob_strcmp( const char *pattern, const char *text, int flags )
350 {
351   /* Compare "text" to a specified globbing "pattern" using semantics
352    * comparable to "strcmp()"; returns zero for a complete match, else
353    * non-zero for a mismatch.
354    *
355    * Within "pattern":
356    *   '?'     matches any one character in "text" (except '\0')
357    *   '*'     matches any sequence of zero or more characters in "text"
358    *   [SET]   matches any one character in "text" which is also in "SET"
359    *   [!SET]  matches any one character in "text" which is NOT in "SET"
360    */
361   register const char *p = pattern, *t = text;
362   register int c;
363
364   if( (*t == '.') && (*p != '.') && ((flags & GLOB_PERIOD) == 0) )
365     /*
366      * The special GNU extension allowing wild cards to match a period
367      * as first character is NOT in effect; "text" DOES have an initial
368      * period character AND "pattern" DOES NOT match it EXPLICITLY, so
369      * this comparison must report a MISMATCH.
370      */
371     return *p - *t;
372
373   /* Attempt to match "pattern", character by character...
374    */
375   while( (c = *p++) != '\0' )
376   {
377     /* ...so long as we haven't exhausted it...
378      */
379     switch( c )
380     {
381       case '?':
382         /* Match any one character...
383          */
384         if( *t++ == '\0' )
385           /* ...but when there isn't one left to be matched,
386            * then we must report a mismatch.
387            */
388           return '?';
389         break;
390
391       case '*':
392         /* Match any sequence of zero or more characters...
393          */
394         while( *p == '*' )
395           /*
396            * ...ignoring any repeated '*' in the pattern...
397            */
398           p++;
399
400         /* ...and if we've exhausted the pattern...
401          */
402         if( *p == '\0' )
403           /*
404            * ...then we simply match all remaining characters,
405            * to the end of "text", so we may return immediately,
406            * reporting a successful match.
407            */
408           return 0;
409
410         /* When we haven't exhausted the pattern, then we may
411          * attempt to recursively match the remainder of the
412          * pattern to some terminal substring of "text"; we do
413          * this iteratively, stepping over as many characters
414          * of "text" as necessary, (and which thus match the '*'
415          * in "pattern"), until we either find the start of this
416          * matching substring, or we exhaust "text" without any
417          * possible match...
418          */
419         do { c = glob_strcmp( p, t, flags | GLOB_PERIOD );
420            } while( (c != 0) && (*t++ != '\0') );
421         /*
422          * ...and ultimately, we return the result of this
423          * recursive attempt to find a match.
424          */
425         return c;
426
427       case '[':
428         /* Here we need to match (or not match) exactly one
429          * character from the candidate text with any one of
430          * a set of characters in the pattern...
431          */
432         if( (c = *t++) == '\0' )
433           /*
434            * ...but, we must return a mismatch if there is no
435            * candidate character left to match.
436            */
437           return '[';
438
439         if( *p == '!' )
440         {
441           /* Match any one character which is NOT in the SET
442            * specified by [!SET].
443            */
444           if( glob_in_set( ++p, c, flags ) == NULL )
445           {
446             if( *p == ']' )
447               p++;
448             p = glob_set_adjusted( p, flags );
449           }
450         }
451         else
452         { /* Match any one character which IS in the SET
453            * specified by [SET].
454            */
455           p = glob_in_set( p, c, flags );
456         }
457         if( p == NULL )
458           /*
459            * The character under test didn't satisfy the SET
460            * matching criterion; return as unmatched.
461            */
462           return ']';
463         break;
464
465       default:
466         /* The escape character cannot be handled as a regular
467          * switch case, because the escape character is specified
468          * as a variable, (to better support Microsoft nuisances).
469          * The escape mechanism may have been disabled within the
470          * glob() call...
471          */
472         if(  ((flags & GLOB_NOESCAPE) == 0)
473           /*
474            * ...but when it is active, and we find an escape
475            * character without exhausting the pattern...
476            */
477         && (c == glob_escape_char) && ((c = *p) != 0)  )
478           /*
479            * ...then we handle the escaped character here, as
480            * a literal, and step over it, within the pattern.
481            */
482           ++p;
483
484         /* When we get to here, a successful match requires that
485          * the current pattern character "c" is an exact literal
486          * match for the next available character "t", if any,
487          * in the candidate text string...
488          */
489         if( (*t == '\0') || (glob_case_match( flags, c, *t ) != 0) )
490           /*
491            * ...otherwise we return a mismatch.
492            */
493           return c - *t;
494
495         /* No mismatch yet; proceed to test the following character
496          * within the candidate text string.
497          */
498         t++;
499     }
500   }
501   /* When we've exhausted the pattern, then this final check will return
502    * a match if we've simultaneously exhausted the candidate text string,
503    * or a mismatch otherwise.
504    */
505   return c - *t;
506 }
507
508 #ifdef DT_DIR
509 /*
510  * When this is defined, we assume that we can safely interrogate
511  * the d_type member of a globbed dirent structure, to determine if
512  * the referenced directory entry is itself a subdirectory entry.
513  */
514 # define GLOB_ISDIR( ent )      ((ent)->d_type == DT_DIR)
515
516 #else
517 /* We can't simply check for (ent)->d_type == DT_DIR, so we must
518  * use stat() to identify subdirectory entries.
519  */
520 # include <sys/stat.h>
521
522   GLOB_INLINE
523   int GLOB_ISDIR( const struct *dirent ent )
524   {
525     struct stat entinfo;
526     if( stat( ent->d_name, &entinfo ) == 0 )
527       return S_ISDIR( entinfo.st_mode );
528     return 0;
529   }
530 #endif
531
532 #if _DIRENT_HAVE_D_NAMLEN
533 /*
534  * Our DIRENT implementation provides a direct indication
535  * of the length of the file system entity name returned by
536  * the last readdir operation...
537  */
538 # define D_NAMLEN( entry )  ((entry)->d_namlen)
539 #else
540 /*
541  * ...otherwise, we have to scan for it.
542  */
543 # define D_NAMLEN( entry )  (strlen( (entry)->d_name ))
544 #endif
545
546 static int glob_initialise( glob_t *gl_data )
547 {
548   /* Helper routine to initialise a glob_t structure
549    * for first time use.
550    */
551   if( gl_data != NULL )
552   {
553     /* Caller gave us a valid pointer to what we assume has been
554      * defined as a glob_t structure; allocate space on the heap,
555      * for storage of the globbed paths vector...
556      */
557     int entries = gl_data->gl_offs + 1;
558     if( (gl_data->gl_pathv = malloc( entries * sizeof( char ** ) )) == NULL )
559       /*
560        * ...bailing out, if insufficient free heap memory.
561        */
562       return GLOB_NOSPACE;
563
564     /* On successful allocation, clear the initial path count...
565      */
566     gl_data->gl_pathc = 0;
567     while( entries > 0 )
568       /*
569        * ...and place a NULL pointer in each allocated slot...
570        */
571       gl_data->gl_pathv[--entries] = NULL;
572   }
573   /* ...ultimately returning a successful initialisation status.
574    */
575   return GLOB_SUCCESS;
576 }
577
578 GLOB_INLINE int glob_expand( glob_t *gl_buf )
579 {
580   /* Inline helper to compute the new size allocation required
581    * for buf->gl_pathv, prior to adding a new glob result.
582    */
583   return ((2 + gl_buf->gl_pathc + gl_buf->gl_offs) * sizeof( char ** ));
584 }
585
586 static int glob_store_entry( char *path, glob_t *gl_buf )
587 {
588   /* Local helper routine to add a single path name entity
589    * to the globbed path vector, after first expanding the
590    * allocated memory space to accommodate it.
591    */
592   char **pathv;
593   if(  (path != NULL)  &&  (gl_buf != NULL)
594   &&  ((pathv = realloc( gl_buf->gl_pathv, glob_expand( gl_buf ))) != NULL)  )
595   {
596     /* Memory expansion was successful; store the new path name
597      * in place of the former NULL pointer at the end of the old
598      * vector...
599      */
600     gl_buf->gl_pathv = pathv;
601     gl_buf->gl_pathv[gl_buf->gl_offs + gl_buf->gl_pathc++] = path;
602     /*
603      * ...then place a further NULL pointer into the newly allocated
604      * slot, to mark the new end of the vector...
605      */
606     gl_buf->gl_pathv[gl_buf->gl_offs + gl_buf->gl_pathc] = NULL;
607     /*
608      * ...before returning a successful completion status.
609      */
610     return GLOB_SUCCESS;
611   }
612   /* If we get to here, then we were unsuccessful.
613    */
614   return GLOB_ABORTED;
615 }
616
617 struct glob_collator
618 {
619   /* A private data structure, used to keep an ordered collection
620    * of globbed path names in collated sequence within a (possibly
621    * unbalanced) binary tree.
622    */
623   struct glob_collator  *prev;
624   struct glob_collator  *next;
625   char                  *entry;
626 };
627
628 GLOB_INLINE struct glob_collator
629 *glob_collate_entry( struct glob_collator *collator, char *entry, int flags )
630 {
631   /* Inline helper function to construct a binary tree representation
632    * of a collated collection of globbed path name entities.
633    */
634   int seq = 0;
635   struct glob_collator *ref = collator;
636   struct glob_collator *lastref = collator;
637   while( ref != NULL )
638   {
639     /* Walk the tree, to find the leaf node representing the insertion
640      * point, in correctly collated sequence order, for the new entry,
641      * noting whether we must insert the new entry before or after the
642      * original entry at that leaf.
643      */
644     lastref = ref;
645     if( flags & GLOB_CASEMATCH )
646       seq = strcoll( entry, ref->entry );
647     else
648       seq = stricoll( entry, ref->entry );
649     ref = (seq > 0) ? ref->next : ref->prev;
650   }
651   /* Allocate storage for a new leaf node, and if successful...
652    */
653   if( (ref = malloc( sizeof( struct glob_collator ))) != NULL )
654   {
655     /* ...place the new entry on this new leaf...
656      */
657     ref->entry = entry;
658     ref->prev = ref->next = NULL;
659
660     /* ...and attach it to the tree...
661      */
662     if( lastref != NULL )
663     {
664       /* ...either...
665        */
666       if( seq > 0 )
667         /*
668          * ...after...
669          */
670         lastref->next = ref;
671
672       else
673         /* ...or before...
674          */
675         lastref->prev = ref;
676
677       /* ...the original leaf,as appropriate. */
678     }
679   }
680   /* When done, return a pointer to the root node of the resultant tree.
681    */
682   return (collator == NULL) ? ref : collator;
683 }
684
685 static void
686 glob_store_collated_entries( struct glob_collator *collator, glob_t *gl_buf )
687 {
688   /* A local helper routine to store a collated collection of globbed
689    * path name entities into the path vector within a glob_t structure;
690    * it performs a recursive inorder traversal of a glob_collator tree,
691    * deleting it leaf by leaf, branch by branch, as it stores the path
692    * data contained thereon.
693    */
694   if( collator->prev != NULL )
695     /*
696      * Recurse into the sub-tree of entries which collate before the
697      * root of the current (sub-)tree.
698      */
699     glob_store_collated_entries( collator->prev, gl_buf );
700
701   /* Store the path name entry at the root of the current (sub-)tree.
702    */
703   glob_store_entry( collator->entry, gl_buf );
704
705   if( collator->next != NULL )
706     /*
707      * Recurse into the sub-tree of entries which collate after the
708      * root of the current (sub-)tree.
709      */
710     glob_store_collated_entries( collator->next, gl_buf );
711
712   /* Finally, delete the root node of the current (sub-)tree; since
713    * recursion visits every node of the tree, ultimately considering
714    * each leaf as a sub-tree of only one node, unwinding recursion
715    * will cause this to delete the entire tree.
716    */
717   free( collator );
718 }
719
720 GLOB_INLINE int
721 accept_glob_nocheck_match( const char *pattern, int flags )
722 {
723   /* Helper to check whether a pattern may be stored into gl_pathv as is,
724    * without attempting to find any file system match; (this is permitted
725    * only when the caller has set the GLOB_NOCHECK flag, and the pattern
726    * is devoid of any globbing token).
727    */
728   return (flags & GLOB_NOCHECK) && (is_glob_pattern( pattern, flags ) == 0);
729 }
730
731 static int
732 glob_match( const char *pattern, int flags, int (*errfn)(), glob_t *gl_buf )
733 {
734   /* Local helper function; it provides the backbone of the glob()
735    * implementation, recursively decomposing the pattern into separate
736    * globbable path components, to collect the union of all possible
737    * matches to the pattern, in all possible matching directories.
738    */
739   glob_t local_gl_buf;
740   int status = GLOB_SUCCESS;
741
742   /* Begin by separating out any path prefix from the glob pattern.
743    */
744   char dirbuf[1 + strlen( pattern )];
745   const char *dir = dirname( memcpy( dirbuf, pattern, sizeof( dirbuf )) );
746   char **dirp, preferred_dirsep = GLOB_DIRSEP;
747
748   /* Initialise a temporary local glob_t structure, to capture the
749    * intermediate results at the current level of recursion...
750    */
751   local_gl_buf.gl_offs = 0;
752   if( (status = glob_initialise( &local_gl_buf )) != GLOB_SUCCESS )
753     /*
754      * ...bailing out if unsuccessful.
755      */
756     return status;
757
758   /* Check if there are any globbing tokens in the path prefix...
759    */
760   if( is_glob_pattern( dir, flags ) )
761     /*
762      * ...and recurse to identify all possible matching prefixes,
763      * as may be necessary...
764      */
765     status = glob_match( dir, flags | GLOB_DIRONLY, errfn, &local_gl_buf );
766
767   else
768     /* ...or simply store the current prefix, if not.
769      */
770     status = glob_store_entry( glob_strdup( dir ), &local_gl_buf );
771
772   /* Check nothing has gone wrong, so far...
773    */
774   if( status != GLOB_SUCCESS )
775     /*
776      * ...and bail out if necessary.
777      */
778     return status;
779
780   /* The original "pattern" argument may have included a path name
781    * prefix, which we used "dirname()" to isolate.  If there was no
782    * such prefix, then "dirname()" would have reported an effective
783    * prefix which is identically equal to "."; however, this would
784    * also be the case if the prefix was "./" (or ".\\" in the case
785    * of a WIN32 host).  Thus, we may deduce that...
786    */
787   if( glob_is_dirsep( pattern[1] ) || (strcmp( dir, "." ) != 0) )
788   {
789     /* ...when the prefix is not reported as ".", or even if it is
790      * but the original pattern had "./" (or ".\\") as the prefix,
791      * then we must adjust to identify the effective pattern with
792      * its original prefix stripped away...
793      */
794     const char *tail = pattern + strlen( dir );
795     while( (tail > pattern) && ! glob_is_dirsep( *tail ) )
796       --tail;
797     while( glob_is_dirsep( *tail ) )
798       preferred_dirsep = *tail++;
799     pattern = tail;
800   }
801
802   else
803     /* ...otherwise, we simply note that there was no prefix.
804      */
805     dir = NULL;
806
807   /* We now have a globbed list of prefix directories, returned from
808    * recursive processing, in local_gl_buf.gl_pathv, and we also have
809    * a separate pattern which we may attempt to match in each of them;
810    * at the outset, we have yet to match this pattern to anything.
811    */
812   status = GLOB_NOMATCH;
813
814   /* When the caller has enabled the GLOB_NOCHECK option, then in the
815    * case of any pattern with no prefix, and which contains no explicit
816    * globbing token...
817    */
818   if( (dir == NULL) && accept_glob_nocheck_match( pattern, flags ) )
819   {
820     /* ...we prefer to store it as is, without any attempt to find
821      * a glob match, (which could also induce a case transliteration
822      * on MS-Windows' case-insensitive file system)...
823      */
824     glob_store_entry( glob_strdup( pattern ), gl_buf );
825     status = GLOB_SUCCESS;
826   }
827   /* ...otherwise we initiate glob matching, to find all possible
828    * file system matches for the designated pattern, within each of
829    * the identified prefix directory paths.
830    */
831   else for( dirp = local_gl_buf.gl_pathv; *dirp != NULL; free( *dirp++ ) )
832   {
833     /* Provided an earlier cycle hasn't scheduled an abort...
834      */
835     if( status != GLOB_ABORTED )
836     {
837       /* ...take each candidate directory in turn, and prepare
838        * to collate any matched entities within it...
839        */
840       struct glob_collator *collator = NULL;
841
842       /* ...attempt to open the current candidate directory...
843        */
844       DIR *dp;
845       if( (dp = opendir( *dirp )) != NULL )
846       {
847         /* ...and when successful, instantiate a dirent structure...
848          */
849         struct dirent *entry;
850         size_t dirlen = (dir == NULL) ? 0 : strlen( *dirp );
851         while( (entry = readdir( dp )) != NULL )
852         {
853           /* ...into which we read each entry from the candidate
854            * directory, in turn, then...
855            */ 
856           if( (((flags & GLOB_DIRONLY) == 0) || GLOB_ISDIR( entry ))
857             /*
858              * ...provided we don't require it to be a subdirectory,
859              * or it actually is one...
860              */
861           && (glob_strcmp( pattern, entry->d_name, flags ) == 0)   )
862           {
863             /* ...and it is a globbed match for the pattern, then
864              * we allocate a temporary local buffer of sufficient
865              * size to assemble the matching path name...
866              */
867             char *found;
868             size_t prefix;
869             size_t matchlen = D_NAMLEN( entry );
870             char matchpath[2 + dirlen + matchlen];
871             if( (prefix = dirlen) > 0 )
872             {
873               /* ...first copying the prefix, if any,
874                * followed by a directory name separator...
875                */
876               memcpy( matchpath, *dirp, dirlen );
877               if( ! glob_is_dirsep( matchpath[prefix - 1] ) )
878                 matchpath[prefix++] = preferred_dirsep;
879             }
880             /* ...and append the matching dirent entry.
881              */
882             memcpy( matchpath + prefix, entry->d_name, matchlen + 1 );
883
884             /* Duplicate the content of the temporary buffer to
885              * the heap, for assignment into gl_buf->gl_pathv...
886              */
887             if( (found = glob_strdup( matchpath )) == NULL )
888               /*
889                * ...setting the appropriate error code, in the
890                * event that the heap memory has been exhausted.
891                */
892               status = GLOB_NOSPACE;
893
894             else
895             { /* This glob match has been successfully recorded on
896                * the heap, ready for assignment to gl_buf->gl_pathv;
897                * if this is the first match assigned to this gl_buf,
898                * and we haven't trapped any prior error...
899                */
900               if( status == GLOB_NOMATCH )
901                 /*
902                  * ...then record this successful match.
903                  */
904                 status = GLOB_SUCCESS;
905
906               if( (flags & GLOB_NOSORT) == 0 )
907               {
908                 /* The results of this glob are to be sorted in
909                  * collating sequence order; divert the current
910                  * match into the collator.
911                  */
912                 collator = glob_collate_entry( collator, found, flags );
913               }
914               else
915               { /* Sorting has been suppressed for this glob;
916                  * just add the current match directly into the
917                  * result vector at gl_buf->gl_pathv.
918                  */
919                 glob_store_entry( found, gl_buf );
920               }
921             }
922           }
923         }
924         /* When we've processed all of the entries in the current
925          * prefix directory, we may close it.
926          */
927         closedir( dp );
928       }
929       /* In the event of failure to open the candidate prefix directory...
930        */
931       else if( (flags & GLOB_ERR) || ((errfn != NULL) && errfn( *dirp, errno )) )
932         /*
933          * ...and when the caller has set the GLOB_ERR flag, or has provided
934          * an error handler which returns non-zero for the failure condition,
935          * then we schedule an abort.
936          */
937         status = GLOB_ABORTED;
938
939       /* When we diverted the glob results for collation...
940        */
941       if( collator != NULL )
942         /*
943          * ...then we redirect them to gl_buf->gl_pathv now, before we
944          * begin a new cycle, to process any further prefix directories
945          * which may have been identified; note that we do this even if
946          * we scheduled an abort, so that we may return any results we
947          * may have already collected before the error occurred.
948          */
949         glob_store_collated_entries( collator, gl_buf );
950     }
951   }
952   /* Finally, free the memory block allocated for the results vector
953    * in the internal glob buffer, to avoid leaking memory, before we
954    * return the resultant status code.
955    */
956   free( local_gl_buf.gl_pathv );
957   return status;
958 }
959
960 #define GLOB_INIT       (0x100 << 0)
961 #define GLOB_FREE       (0x100 << 1)
962
963 GLOB_INLINE int glob_signed( const char *check, const char *magic )
964 {
965   /* Inline helper function, used exclusively by the glob_registry()
966    * function, to confirm that the gl_magic field within a glob_t data
967    * structure has been set, to indicate a properly initialised state.
968    *
969    * FIXME: we'd like to be able to verify the content at "check"
970    * against the signature at "magic", but "check" is likely to be
971    * an uninitialised pointer, and MS-Windows lamely crashes when the
972    * memory it might appear to address cannot be read.  There may be a
973    * way we could trap, and effectively handle, the resulting access
974    * violation, (likely restricted to WinXP and later); in the absence
975    * of a suitable handler, we must restrict our check to require that
976    * "check" is a strict alias for "magic".  This will lose, if we have
977    * multiple copies of "glob" loaded via distinct DLLs, and we pass a
978    * "glob_t" entity which has been initialised in one DLL across the
979    * boundary of another; for now, however, checking for strict pointer
980    * aliasing seems to be the only reliably safe option available.
981    */
982   return (check == magic) ? 0 : 1;
983 }
984
985 static glob_t *glob_registry( int request, glob_t *gl_data )
986 {
987   /* Helper function to verify proper registration (initialisation)
988    * of a glob_t data structure, prior to first use; it also provides
989    * the core implementation for the globfree() function.
990    */
991   static const char *glob_magic = "glob-1.0-mingw32";
992
993   /* We must be prepared to handle either of...
994    */
995   switch( request )
996   {
997     /* ...a registration (initialisation) request...
998      */
999     case GLOB_INIT:
1000       if( glob_signed( gl_data->gl_magic, glob_magic ) != 0 )
1001       {
1002         /* The gl_magic field doesn't (yet) indicate that the
1003          * data structure has been initialised; assume that this
1004          * is first use, and initialise it now.
1005          */
1006         glob_initialise( gl_data );
1007         gl_data->gl_magic = (void *)(glob_magic);
1008       }
1009       break;
1010
1011     /* ...or a de-registration (globfree()) request; here we
1012      * perform a sanity check, to ensure that the passed glob_t
1013      * structure is a valid, previously initialised structure,
1014      * before we attempt to free it.
1015      */
1016     case GLOB_FREE:
1017       if( glob_signed( gl_data->gl_magic, glob_magic ) == 0 )
1018       {
1019         /* On passing the sanity check, we may proceed to free
1020          * all dynamically (strdup) allocated string buffers in
1021          * the gl_pathv list, and the reference pointer table
1022          * itself, thus completing the globfree() activity.
1023          */
1024         int base = gl_data->gl_offs;
1025         int argc = gl_data->gl_pathc;
1026         while( argc-- > 0 )
1027           free( gl_data->gl_pathv[base++] );
1028         free( gl_data->gl_pathv );
1029       }
1030   }
1031   /* In either case, we return the original glob_t data pointer.
1032    */
1033   return gl_data;
1034 }
1035
1036 int
1037 __mingw_glob( const char *pattern, int flags, int (*errfn)(), glob_t *gl_data )
1038 {
1039   /* Module entry point for the glob() function.
1040    */
1041   int status;
1042
1043   /* First, consult the glob "registry", to ensure that the
1044    * glob data structure passed by the caller, has been properly
1045    * initialised.  (Note that this implementation gratuitously uses
1046    * gl_data->gl_offs, irrespective of specification of GLOB_DOOFFS
1047    * in the flags; while the user must accept responsibility for the
1048    * initialisation of gl_data->gl_offs when specifying GLOB_DOOFFS,
1049    * this is not the case when GLOB_DOOFFS is not specified; in the
1050    * latter case, WE must assume the responsibility, ensuring that
1051    * the required zero value is assigned BEFORE registration).
1052    */
1053   if( (gl_data != NULL) && ((flags & GLOB_DOOFFS) == 0) )
1054     gl_data->gl_offs = 0;
1055
1056   /* With this pre-registration requirement satisfied, we may now
1057    * proceed to register the provided gl_data structure.
1058    */
1059   gl_data = glob_registry( GLOB_INIT, gl_data );
1060
1061   /* The actual globbing function is performed by glob_match()...
1062    */
1063   status = glob_match( pattern, flags, errfn, gl_data );
1064   if( (status == GLOB_NOMATCH) && ((flags & GLOB_NOCHECK) != 0) )
1065     /*
1066      * ...ultimately delegating to glob_strdup() and glob_store_entry()
1067      * to handle any unmatched globbing pattern which the user specified
1068      * options may require to be stored anyway.
1069      */
1070     glob_store_entry( glob_strdup( pattern ), gl_data );
1071
1072   /* We always return the status reported by glob_match().
1073    */
1074   return status;
1075 }
1076
1077 void
1078 __mingw_globfree( glob_t *gl_data )
1079 {
1080   /* Module entry point for globfree() function; the activity is
1081    * entirely delegated to the glob "registry" helper function.
1082    */
1083   glob_registry( GLOB_FREE, gl_data );
1084 }
1085
1086 /* $RCSfile$: end of file */