The MinGW.org Windows System Libraries
リビジョン | 1559fe3708515b7c61a0e7d2672102ec5ea1f1fa (tree) |
---|---|
日時 | 2017-02-12 19:12:06 |
作者 | Keith Marshall <keithmarshall@user...> |
コミッター | Keith Marshall |
Support brace expansion in globbing patterns.
@@ -1,3 +1,23 @@ | ||
1 | +2017-02-12 Keith Marshall <keithmarshall@users.sourceforge.net> | |
2 | + | |
3 | + Support brace expansion in globbing patterns. | |
4 | + | |
5 | + * include/glob.h (GLOB_BRACE): New manifest constant; define it... | |
6 | + (__GLOB_FLAG__): ...in terms of this macro. | |
7 | + | |
8 | + * mingwex/glob.c (glob_match): Reindent, with preamble invoking... | |
9 | + (glob_brace_expand): ...this new static inline function; implement it. | |
10 | + (GLOB_INIT, GLOB_FREE): Redefine them, relating them to... | |
11 | + (__GLOB_FLAG_OFFSET_HIGH_WATER_MARK): ...this. | |
12 | + | |
13 | + * setargv.c (__mingw32_setargv) [_CRT_glob]: Check if it includes... | |
14 | + [GLOB_CASEMATCH | GLOB_BRACE]: either of these; remove check for... | |
15 | + [__CRT_GLOB_CASE_SENSITIVE__]: ...this defunct option. | |
16 | + | |
17 | + * include/_mingw.h.in (GLOB_BRACE): Note its use in _CRT_glob. | |
18 | + (GLOB_CASEMATCH): Likewise; this replaces all former usage of... | |
19 | + (__CRT_GLOB_CASE_SENSITIVE__): ...this; delete definition. | |
20 | + | |
1 | 21 | 2017-02-11 Keith Marshall <keithmarshall@users.sourceforge.net> |
2 | 22 | |
3 | 23 | Refactor <getopt.h> and <unistd.h> shared declarations. |
@@ -132,7 +132,10 @@ | ||
132 | 132 | * character which is either included |
133 | 133 | * in, or excluded from the group. |
134 | 134 | * |
135 | - * __CRT_GLOB_CASE_SENSITIVE__ enable case sensitive matching for | |
135 | + * The following options, which may also be specified within _CRT_glob, | |
136 | + * are specified in terms of their glob() flags, as defined in <glob.h> | |
137 | + * | |
138 | + * GLOB_CASEMATCH enable case sensitive matching for | |
136 | 139 | * globbing patterns; this is default |
137 | 140 | * behaviour for POSIX, but because of |
138 | 141 | * the case insensitive nature of the |
@@ -140,10 +143,13 @@ | ||
140 | 143 | * appropriate to use case insensitive |
141 | 144 | * globbing as the MinGW default. |
142 | 145 | * |
146 | + * GLOB_BRACE enable expansion of GNU style brace | |
147 | + * delimited expression groups within | |
148 | + * the globbing pattern. | |
149 | + * | |
143 | 150 | */ |
144 | 151 | #define __CRT_GLOB_USE_SINGLE_QUOTE__ 0x0010 |
145 | 152 | #define __CRT_GLOB_BRACKET_GROUPS__ 0x0020 |
146 | -#define __CRT_GLOB_CASE_SENSITIVE__ 0x0040 | |
147 | 153 | |
148 | 154 | /* The MinGW globbing algorithm uses the ASCII DEL control code as a marker |
149 | 155 | * for globbing characters which were embedded within quoted arguments; (the |
@@ -32,12 +32,15 @@ | ||
32 | 32 | * |
33 | 33 | */ |
34 | 34 | #define _GLOB_H 1 |
35 | -#include <_mingw.h> | |
36 | 35 | #pragma GCC system_header |
37 | 36 | |
37 | +/* All MinGW.org system headers are required to include <_mingw.h>. | |
38 | + */ | |
39 | +#include <_mingw.h> | |
40 | + | |
38 | 41 | #ifndef RC_INVOKED |
39 | 42 | /* POSIX requires glob.h to define the size_t type; we need to |
40 | - * get this from GCC, just as sys/types.h does. | |
43 | + * get this from GCC's <stddef.h>, just as <sys/types.h> does. | |
41 | 44 | */ |
42 | 45 | #define __need_size_t |
43 | 46 | #include <stddef.h> |
@@ -73,8 +76,8 @@ enum { | ||
73 | 76 | * GNU's implementation of glob() supports a supplementary set of |
74 | 77 | * options, none of which are required by POSIX. We include these |
75 | 78 | * for reference, and to reserve the flag identities for a possible |
76 | - * future implementation; the current MinGW implementation does not | |
77 | - * support them. | |
79 | + * future implementation; of these extensions, the current MinGW | |
80 | + * implementation supports only GLOB_BRACE. | |
78 | 81 | */ |
79 | 82 | __GLOB_TILDE_OFFSET, |
80 | 83 | __GLOB_TILDE_CHECK_OFFSET, |
@@ -115,6 +118,11 @@ enum { | ||
115 | 118 | #define GLOB_NOESCAPE __GLOB_FLAG__(NOESCAPE) |
116 | 119 | #define GLOB_NOSORT __GLOB_FLAG__(NOSORT) |
117 | 120 | |
121 | +/* Flag definitions for those GNU extensions, as listed above, for which | |
122 | + * we provide support; (i.e. GLOB_BRACE only, at present). | |
123 | + */ | |
124 | +#define GLOB_BRACE __GLOB_FLAG__(BRACE) | |
125 | + | |
118 | 126 | /* Additional flags definitions, for MinGW specific extensions. |
119 | 127 | */ |
120 | 128 | #define GLOB_CASEMATCH __GLOB_FLAG__(CASEMATCH) |
@@ -155,4 +163,4 @@ _END_C_DECLS | ||
155 | 163 | #define GLOB_NOSPACE (3) |
156 | 164 | |
157 | 165 | #endif /* ! RC_INVOKED */ |
158 | -#endif /* ! defined _GLOB_H */ | |
166 | +#endif /* !_GLOB_H: $RCSfile$: end of file */ |
@@ -728,6 +728,132 @@ accept_glob_nocheck_match( const char *pattern, int flags ) | ||
728 | 728 | return (flags & GLOB_NOCHECK) && (is_glob_pattern( pattern, flags ) == 0); |
729 | 729 | } |
730 | 730 | |
731 | +GLOB_INLINE int | |
732 | +glob_brace_expand( char *dest, const char *src, const char **resume ) | |
733 | +{ | |
734 | + /* Helper to iteratively expand the first substitution field within | |
735 | + * a glob brace expression, while recursively collecting the set of | |
736 | + * individual globbing patterns to be processed by glob_match(), when | |
737 | + * GLOB_BRACE is specified, and the original pattern includes a brace | |
738 | + * expression. (Notice that this does not guarantee to fully expand | |
739 | + * the pattern in a single pass; recursion within glob_match() will | |
740 | + * ensure that this is achieved, before attempting to match each | |
741 | + * possible expansion of the original pattern). | |
742 | + * | |
743 | + * Returns zero on a successful (possibly partial) expansion; > zero | |
744 | + * indicates unmatched opening braces, (an error condition). | |
745 | + */ | |
746 | + char c; int level = 1; | |
747 | + do { /* Copy characters one by one, from the start of the current | |
748 | + * substitution field within the original glob pattern, to the | |
749 | + * appropriate location in the pattern which will be presented | |
750 | + * to glob_match(). The initial part of this copy represents | |
751 | + * the substitution for the outermost level of brace bounded | |
752 | + * expression, terminating at either the closing brace or at | |
753 | + * any intervening comma at this level; however... | |
754 | + */ | |
755 | + if( (c = *++src) == glob_escape_char ) | |
756 | + { /* ...any escaped character must be copied verbatim, without | |
757 | + * being considered as a possible substitution terminator... | |
758 | + */ | |
759 | + *dest++ = c; *dest++ = c = *++src; | |
760 | + /* ...while taking care not to overrun the ultimate string | |
761 | + * terminator of the original pattern. | |
762 | + */ | |
763 | + if( c != '\0' ) c = *++src; | |
764 | + } | |
765 | + /* Provided it has not been escaped, any closing brace, or a | |
766 | + * comma separator at the outer level only, results in closure | |
767 | + * of a brace nesting level... | |
768 | + */ | |
769 | + if( (c == '}') || ((c == ',') && (level == 1)) ) --level; | |
770 | + /* | |
771 | + * ...while an opening brace creates a new (inner) level. | |
772 | + */ | |
773 | + else if( c == '{' ) ++level; | |
774 | + | |
775 | + /* Provided we have not closed the outermost brace expression | |
776 | + * level, complete the copy of the current character within | |
777 | + * the substitution... | |
778 | + */ | |
779 | + if( level > 0 ) *dest++ = c; | |
780 | + /* ...continuing to the next character, until the outermost | |
781 | + * level has been reached, or the original pattern string | |
782 | + * has been exhausted. | |
783 | + */ | |
784 | + } while( (level > 0) && (c != '\0') ); | |
785 | + | |
786 | + /* Save a reference to the point, within the original pattern, | |
787 | + * where the current substitution ended, and thus where the next | |
788 | + * iteration (if any) is to begin. | |
789 | + */ | |
790 | + *resume = src; | |
791 | + | |
792 | + /* Complete construction of a candidate pattern, to be passed | |
793 | + * to glob_match(), by copying any characters which follow the | |
794 | + * closing brace of the initial brace bounded expression within | |
795 | + * the original pattern; thus... | |
796 | + */ | |
797 | + if( c != '\0' ) | |
798 | + { /* ...when any characters are present, beyond the current | |
799 | + * resume point... | |
800 | + */ | |
801 | + if( c == ',' ) | |
802 | + { /* ...and when any of these represent a substitution which | |
803 | + * is to be made in a subsequent iteration... | |
804 | + */ | |
805 | + level = 1; | |
806 | + do { /* ...we simply skip over all characters, up to and | |
807 | + * including the closing brace at the outermost level | |
808 | + * of expression, (while once again taking care not | |
809 | + * to overrun the string terminator)... | |
810 | + */ | |
811 | + if( c != '\0' ) ++src; | |
812 | + /* ...and once again, honouring escapes which may be | |
813 | + * intended to force literal interpretation of '{'... | |
814 | + */ | |
815 | + while( (*src == glob_escape_char) && (*++src != '\0') ) ++src; | |
816 | + /* | |
817 | + * ...and simply ignoring any nested (inner) brace | |
818 | + * bounded expression... | |
819 | + */ | |
820 | + if( *src == '{' ) ++level; else if( *src == '}' ) --level; | |
821 | + /* | |
822 | + * ...we continue skipping, until we find the closing | |
823 | + * brace at the outermost level of the expression, or | |
824 | + * we have have exhausted the original pattern. | |
825 | + */ | |
826 | + } while( ((c = *src) != '\0') && (level > 0) ); | |
827 | + } | |
828 | + /* Finally... | |
829 | + */ | |
830 | + if( level == 0 ) | |
831 | + { /* ...when we've skipped to the closing brace ... (checking | |
832 | + * that we didn't exhaust the original pattern is belt and | |
833 | + * braces here, because *src should be '}') ... we now skip | |
834 | + * past it... | |
835 | + */ | |
836 | + if( c != '\0' ) ++src; | |
837 | + /* ...we simply copy all further characters from the original | |
838 | + * pattern, without consideration that there may be any further | |
839 | + * possible expansion; (this will be picked up by recursion). | |
840 | + */ | |
841 | + do { *dest++ = *src; } while( *src++ != '\0' ); | |
842 | + } | |
843 | + else | |
844 | + /* Alternatively, when the closing brace has not been found, | |
845 | + * (which implies exhaustion of the original pattern), we | |
846 | + * must ensure that the expanded copy is terminated. | |
847 | + */ | |
848 | + *dest = '\0'; | |
849 | + } | |
850 | + /* Regardless, we return the residual brace expansion level; zero | |
851 | + * indicates successful expansion; > zero is an error, indicating | |
852 | + * one (or more) unmatched opening braces. | |
853 | + */ | |
854 | + return level; | |
855 | +} | |
856 | + | |
731 | 857 | static int |
732 | 858 | glob_match( const char *pattern, int flags, int (*errfn)(), glob_t *gl_buf ) |
733 | 859 | { |
@@ -735,230 +861,339 @@ glob_match( const char *pattern, int flags, int (*errfn)(), glob_t *gl_buf ) | ||
735 | 861 | * implementation, recursively decomposing the pattern into separate |
736 | 862 | * globbable path components, to collect the union of all possible |
737 | 863 | * matches to the pattern, in all possible matching directories. |
864 | + * | |
865 | + * At the outset, assume that this will succeed. | |
738 | 866 | */ |
739 | - glob_t local_gl_buf; | |
740 | 867 | int status = GLOB_SUCCESS; |
741 | 868 | |
742 | - /* Begin by separating out any path prefix from the glob pattern. | |
869 | + /* To handle the GNU specific GLOB_BRACE option, we need a | |
870 | + * recursive preamble to the bare glob_match() strategy; when | |
871 | + * GLOB_BRACE expansion is specified... | |
743 | 872 | */ |
744 | - char dirbuf[1 + strlen( pattern )]; | |
745 | - const char *dir = dirname( memcpy( dirbuf, pattern, sizeof( dirbuf )) ); | |
746 | - char **dirp, preferred_dirsep = GLOB_DIRSEP; | |
873 | + int brace_option; | |
874 | + if( (brace_option = flags & GLOB_BRACE) == GLOB_BRACE ) | |
875 | + { | |
876 | + /* ...we recursively parse the original pattern, so as to | |
877 | + * decompose it into a series of substitute patterns, each | |
878 | + * of which represents one pattern expansion to which glob | |
879 | + * matching is applied in turn, such that the aggregate of | |
880 | + * matches for the series represents all possible matches | |
881 | + * for all possible expansions of the original pattern. | |
882 | + */ | |
883 | + const char *src = pattern; | |
884 | + char c, sub_pattern[1 + strlen( pattern )], *dest = sub_pattern; | |
747 | 885 | |
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. | |
886 | + /* We begin by initialising the prefix portion which is | |
887 | + * common to all substitute patterns... | |
888 | + */ | |
889 | + do { /* ...by copying characters one at a time, from the | |
890 | + * original pattern to the substitute pattern buffer... | |
891 | + */ | |
892 | + while( *src == glob_escape_char ) | |
893 | + { | |
894 | + /* ...ensuring that all escaped characters are | |
895 | + * copied verbatim, without consideration as a | |
896 | + * possible brace expression initiator... | |
897 | + */ | |
898 | + *dest++ = *src++; | |
899 | + /* | |
900 | + * ...but taking care that we don't overrun the | |
901 | + * original pattern's string terminator... | |
902 | + */ | |
903 | + if( *src != '\0') *dest++ = *src++; | |
904 | + } | |
905 | + /* ...copying every character up to but excluding the | |
906 | + * opening brace of the first brace bounded expression | |
907 | + * (if any), or up to and including the NUL terminator | |
908 | + * otherwise... | |
909 | + */ | |
910 | + if( (c = *src) != '{' ) *dest++ = *src++; | |
911 | + /* | |
912 | + * ...repeating until we either exhaust the original | |
913 | + * pattern, or we find an opening brace. | |
914 | + */ | |
915 | + } while( (c != '\0') && (c != '{') ); | |
916 | + | |
917 | + /* After copying the prefix, (which may represent the entire | |
918 | + * pattern)... | |
755 | 919 | */ |
756 | - return status; | |
920 | + if( c == '{' ) | |
921 | + /* ...when there is a brace bounded expression to expand... | |
922 | + */ | |
923 | + do { /* ...iterate to construct each of its expansions in | |
924 | + * turn, (together with any common suffix), and... | |
925 | + */ | |
926 | + if( glob_brace_expand( dest, src, &src ) == 0 ) | |
927 | + { | |
928 | + /* ...on success, note that there may be further | |
929 | + * embedded brace bounded sub-expressions; recurse | |
930 | + * to achieve full expansion... | |
931 | + */ | |
932 | + status = glob_match( sub_pattern, flags, errfn, gl_buf ); | |
933 | + /* | |
934 | + * ...and ensure that matches to all expansions | |
935 | + * after the first, will be appended. | |
936 | + */ | |
937 | + flags |= GLOB_APPEND; | |
938 | + } | |
939 | + else | |
940 | + { /* Brace expansion failed, (which implies an opening | |
941 | + * brace with no matching closing brace); bail out. | |
942 | + * | |
943 | + * FIXME: if errfn is specified (not NULL), perhaps we | |
944 | + * should invoke it (but how best? POSIX says it is to | |
945 | + * be invoked when pattern resolves to a directory which | |
946 | + * cannot be opened, or cannot be read; maybe pass the | |
947 | + * original failing pattern, with errno = EINVAL?). | |
948 | + */ | |
949 | + status = GLOB_ABORTED; | |
950 | + } | |
951 | + /* Repeat iteration until all specified substitutions | |
952 | + * for the current expression have been processed, (or | |
953 | + * aborted). | |
954 | + */ | |
955 | + } while( (status != GLOB_ABORTED) && (*src == ',') ); | |
956 | + | |
957 | + else | |
958 | + /* The current brace expression has been reduced to its final | |
959 | + * form, (with no further expansion pending); release it for | |
960 | + * fall-through glob matching. | |
961 | + */ | |
962 | + brace_option = 0; | |
963 | + } | |
757 | 964 | |
758 | - /* Check if there are any globbing tokens in the path prefix... | |
965 | + /* On falling through brace expansion, (if any)... | |
759 | 966 | */ |
760 | - if( is_glob_pattern( dir, flags ) ) | |
761 | - /* | |
762 | - * ...and recurse to identify all possible matching prefixes, | |
763 | - * as may be necessary... | |
967 | + if( brace_option == 0 ) | |
968 | + { | |
969 | + /* ...we have exactly one pattern, with no possible expansions | |
970 | + * of brace expressions, to be globbed; (alternate expansions of | |
971 | + * any brace expressions are processed in alternative recursive | |
972 | + * invocations of this function). | |
764 | 973 | */ |
765 | - status = glob_match( dir, flags | GLOB_DIRONLY, errfn, &local_gl_buf ); | |
974 | + glob_t local_gl_buf; | |
766 | 975 | |
767 | - else | |
768 | - /* ...or simply store the current prefix, if not. | |
976 | + /* Begin by separating out any path prefix from the glob pattern. | |
769 | 977 | */ |
770 | - status = glob_store_entry( glob_strdup( dir ), &local_gl_buf ); | |
978 | + char dirbuf[1 + strlen( pattern )]; | |
979 | + const char *dir = dirname( memcpy( dirbuf, pattern, sizeof( dirbuf )) ); | |
980 | + char **dirp, preferred_dirsep = GLOB_DIRSEP; | |
771 | 981 | |
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... | |
982 | + /* Initialise a temporary local glob_t structure, to capture the | |
983 | + * intermediate results at the current level of recursion... | |
793 | 984 | */ |
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 | - } | |
985 | + local_gl_buf.gl_offs = 0; | |
986 | + if( (status = glob_initialise( &local_gl_buf )) != GLOB_SUCCESS ) | |
987 | + /* | |
988 | + * ...bailing out if unsuccessful. | |
989 | + */ | |
990 | + return status; | |
801 | 991 | |
802 | - else | |
803 | - /* ...otherwise, we simply note that there was no prefix. | |
992 | + /* Check if there are any globbing tokens in the path prefix... | |
804 | 993 | */ |
805 | - dir = NULL; | |
994 | + if( is_glob_pattern( dir, flags ) ) | |
995 | + /* | |
996 | + * ...and recurse to identify all possible matching prefixes, | |
997 | + * as may be necessary... | |
998 | + */ | |
999 | + status = glob_match( dir, flags | GLOB_DIRONLY, errfn, &local_gl_buf ); | |
806 | 1000 | |
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; | |
1001 | + else | |
1002 | + /* ...or simply store the current prefix, if not. | |
1003 | + */ | |
1004 | + status = glob_store_entry( glob_strdup( dir ), &local_gl_buf ); | |
813 | 1005 | |
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)... | |
1006 | + /* Check nothing has gone wrong, so far... | |
823 | 1007 | */ |
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... | |
1008 | + if( status != GLOB_SUCCESS ) | |
1009 | + /* | |
1010 | + * ...and bail out if necessary. | |
1011 | + */ | |
1012 | + return status; | |
1013 | + | |
1014 | + /* The original "pattern" argument may have included a path name | |
1015 | + * prefix, which we used "dirname()" to isolate. If there was no | |
1016 | + * such prefix, then "dirname()" would have reported an effective | |
1017 | + * prefix which is identically equal to "."; however, this would | |
1018 | + * also be the case if the prefix was "./" (or ".\\" in the case | |
1019 | + * of a WIN32 host). Thus, we may deduce that... | |
834 | 1020 | */ |
835 | - if( status != GLOB_ABORTED ) | |
1021 | + if( glob_is_dirsep( pattern[1] ) || (strcmp( dir, "." ) != 0) ) | |
836 | 1022 | { |
837 | - /* ...take each candidate directory in turn, and prepare | |
838 | - * to collate any matched entities within it... | |
1023 | + /* ...when the prefix is not reported as ".", or even if it is | |
1024 | + * but the original pattern had "./" (or ".\\") as the prefix, | |
1025 | + * then we must adjust to identify the effective pattern with | |
1026 | + * its original prefix stripped away... | |
1027 | + */ | |
1028 | + const char *tail = pattern + strlen( dir ); | |
1029 | + while( (tail > pattern) && ! glob_is_dirsep( *tail ) ) | |
1030 | + --tail; | |
1031 | + while( glob_is_dirsep( *tail ) ) | |
1032 | + preferred_dirsep = *tail++; | |
1033 | + pattern = tail; | |
1034 | + } | |
1035 | + | |
1036 | + else | |
1037 | + /* ...otherwise, we simply note that there was no prefix. | |
839 | 1038 | */ |
840 | - struct glob_collator *collator = NULL; | |
1039 | + dir = NULL; | |
841 | 1040 | |
842 | - /* ...attempt to open the current candidate directory... | |
1041 | + /* We now have a globbed list of prefix directories, returned from | |
1042 | + * recursive processing, in local_gl_buf.gl_pathv, and we also have | |
1043 | + * a separate pattern which we may attempt to match in each of them; | |
1044 | + * at the outset, we have yet to match this pattern to anything. | |
1045 | + */ | |
1046 | + status = GLOB_NOMATCH; | |
1047 | + | |
1048 | + /* When the caller has enabled the GLOB_NOCHECK option, then in the | |
1049 | + * case of any pattern with no prefix, and which contains no explicit | |
1050 | + * globbing token... | |
1051 | + */ | |
1052 | + if( (dir == NULL) && accept_glob_nocheck_match( pattern, flags ) ) | |
1053 | + { | |
1054 | + /* ...we prefer to store it as is, without any attempt to find | |
1055 | + * a glob match, (which could also induce a case transliteration | |
1056 | + * on MS-Windows' case-insensitive file system)... | |
1057 | + */ | |
1058 | + glob_store_entry( glob_strdup( pattern ), gl_buf ); | |
1059 | + status = GLOB_SUCCESS; | |
1060 | + } | |
1061 | + /* ...otherwise we initiate glob matching, to find all possible | |
1062 | + * file system matches for the designated pattern, within each of | |
1063 | + * the identified prefix directory paths. | |
1064 | + */ | |
1065 | + else for( dirp = local_gl_buf.gl_pathv; *dirp != NULL; free( *dirp++ ) ) | |
1066 | + { | |
1067 | + /* Provided an earlier cycle hasn't scheduled an abort... | |
843 | 1068 | */ |
844 | - DIR *dp; | |
845 | - if( (dp = opendir( *dirp )) != NULL ) | |
1069 | + if( status != GLOB_ABORTED ) | |
846 | 1070 | { |
847 | - /* ...and when successful, instantiate a dirent structure... | |
1071 | + /* ...take each candidate directory in turn, and prepare | |
1072 | + * to collate any matched entities within it... | |
1073 | + */ | |
1074 | + struct glob_collator *collator = NULL; | |
1075 | + | |
1076 | + /* ...attempt to open the current candidate directory... | |
848 | 1077 | */ |
849 | - struct dirent *entry; | |
850 | - size_t dirlen = (dir == NULL) ? 0 : strlen( *dirp ); | |
851 | - while( (entry = readdir( dp )) != NULL ) | |
1078 | + DIR *dp; | |
1079 | + if( (dp = opendir( *dirp )) != NULL ) | |
852 | 1080 | { |
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) ) | |
1081 | + /* ...and when successful, instantiate a dirent structure... | |
1082 | + */ | |
1083 | + struct dirent *entry; | |
1084 | + size_t dirlen = (dir == NULL) ? 0 : strlen( *dirp ); | |
1085 | + while( (entry = readdir( dp )) != NULL ) | |
862 | 1086 | { |
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... | |
1087 | + /* ...into which we read each entry from the candidate | |
1088 | + * directory, in turn, then... | |
866 | 1089 | */ |
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 ) | |
1090 | + if( (((flags & GLOB_DIRONLY) == 0) || GLOB_ISDIR( entry )) | |
1091 | + /* | |
1092 | + * ...provided we don't require it to be a subdirectory, | |
1093 | + * or it actually is one... | |
1094 | + */ | |
1095 | + && (glob_strcmp( pattern, entry->d_name, flags ) == 0) ) | |
872 | 1096 | { |
873 | - /* ...first copying the prefix, if any, | |
874 | - * followed by a directory name separator... | |
1097 | + /* ...and it is a globbed match for the pattern, then | |
1098 | + * we allocate a temporary local buffer of sufficient | |
1099 | + * size to assemble the matching path name... | |
875 | 1100 | */ |
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. | |
1101 | + char *found; | |
1102 | + size_t prefix; | |
1103 | + size_t matchlen = D_NAMLEN( entry ); | |
1104 | + char matchpath[2 + dirlen + matchlen]; | |
1105 | + if( (prefix = dirlen) > 0 ) | |
1106 | + { | |
1107 | + /* ...first copying the prefix, if any, | |
1108 | + * followed by a directory name separator... | |
1109 | + */ | |
1110 | + memcpy( matchpath, *dirp, dirlen ); | |
1111 | + if( ! glob_is_dirsep( matchpath[prefix - 1] ) ) | |
1112 | + matchpath[prefix++] = preferred_dirsep; | |
1113 | + } | |
1114 | + /* ...and append the matching dirent entry. | |
891 | 1115 | */ |
892 | - status = GLOB_NOSPACE; | |
1116 | + memcpy( matchpath + prefix, entry->d_name, matchlen + 1 ); | |
893 | 1117 | |
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... | |
1118 | + /* Duplicate the content of the temporary buffer to | |
1119 | + * the heap, for assignment into gl_buf->gl_pathv... | |
899 | 1120 | */ |
900 | - if( status == GLOB_NOMATCH ) | |
1121 | + if( (found = glob_strdup( matchpath )) == NULL ) | |
901 | 1122 | /* |
902 | - * ...then record this successful match. | |
1123 | + * ...setting the appropriate error code, in the | |
1124 | + * event that the heap memory has been exhausted. | |
903 | 1125 | */ |
904 | - status = GLOB_SUCCESS; | |
1126 | + status = GLOB_NOSPACE; | |
905 | 1127 | |
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 | 1128 | 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. | |
1129 | + { /* This glob match has been successfully recorded on | |
1130 | + * the heap, ready for assignment to gl_buf->gl_pathv; | |
1131 | + * if this is the first match assigned to this gl_buf, | |
1132 | + * and we haven't trapped any prior error... | |
918 | 1133 | */ |
919 | - glob_store_entry( found, gl_buf ); | |
1134 | + if( status == GLOB_NOMATCH ) | |
1135 | + /* | |
1136 | + * ...then record this successful match. | |
1137 | + */ | |
1138 | + status = GLOB_SUCCESS; | |
1139 | + | |
1140 | + if( (flags & GLOB_NOSORT) == 0 ) | |
1141 | + { | |
1142 | + /* The results of this glob are to be sorted in | |
1143 | + * collating sequence order; divert the current | |
1144 | + * match into the collator. | |
1145 | + */ | |
1146 | + collator = glob_collate_entry( collator, found, flags ); | |
1147 | + } | |
1148 | + else | |
1149 | + { /* Sorting has been suppressed for this glob; | |
1150 | + * just add the current match directly into the | |
1151 | + * result vector at gl_buf->gl_pathv. | |
1152 | + */ | |
1153 | + glob_store_entry( found, gl_buf ); | |
1154 | + } | |
920 | 1155 | } |
921 | 1156 | } |
922 | 1157 | } |
1158 | + /* When we've processed all of the entries in the current | |
1159 | + * prefix directory, we may close it. | |
1160 | + */ | |
1161 | + closedir( dp ); | |
923 | 1162 | } |
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. | |
1163 | + /* In the event of failure to open the candidate prefix directory... | |
936 | 1164 | */ |
937 | - status = GLOB_ABORTED; | |
1165 | + else if( (flags & GLOB_ERR) || ((errfn != NULL) && errfn(*dirp, errno)) ) | |
1166 | + /* | |
1167 | + * ...and when the caller has set the GLOB_ERR flag, or has provided | |
1168 | + * an error handler which returns non-zero for the failure condition, | |
1169 | + * then we schedule an abort. | |
1170 | + */ | |
1171 | + status = GLOB_ABORTED; | |
938 | 1172 | |
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. | |
1173 | + /* When we diverted the glob results for collation... | |
948 | 1174 | */ |
949 | - glob_store_collated_entries( collator, gl_buf ); | |
1175 | + if( collator != NULL ) | |
1176 | + /* | |
1177 | + * ...then we redirect them to gl_buf->gl_pathv now, before we | |
1178 | + * begin a new cycle, to process any further prefix directories | |
1179 | + * which may have been identified; note that we do this even if | |
1180 | + * we scheduled an abort, so that we may return any results we | |
1181 | + * may have already collected before the error occurred. | |
1182 | + */ | |
1183 | + glob_store_collated_entries( collator, gl_buf ); | |
1184 | + } | |
950 | 1185 | } |
1186 | + /* Finally, free the memory block allocated for the results vector | |
1187 | + * in the internal glob buffer, to avoid leaking memory, before we | |
1188 | + * return the resultant status code. | |
1189 | + */ | |
1190 | + free( local_gl_buf.gl_pathv ); | |
951 | 1191 | } |
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 | 1192 | return status; |
958 | 1193 | } |
959 | 1194 | |
960 | -#define GLOB_INIT (0x100 << 0) | |
961 | -#define GLOB_FREE (0x100 << 1) | |
1195 | +#define GLOB_INIT (1 << __GLOB_FLAG_OFFSET_HIGH_WATER_MARK) | |
1196 | +#define GLOB_FREE (2 << __GLOB_FLAG_OFFSET_HIGH_WATER_MARK) | |
962 | 1197 | |
963 | 1198 | GLOB_INLINE int glob_signed( const char *check, const char *magic ) |
964 | 1199 | { |
@@ -101,9 +101,7 @@ void __mingw32_setargv( const char *cmdline ) | ||
101 | 101 | /* Capture any non-default globbing options, which the user may have |
102 | 102 | * specified via a custom setting for _CRT_glob. |
103 | 103 | */ |
104 | - int gl_opts = GLOB_NOCHECK; | |
105 | - if( _CRT_glob & __CRT_GLOB_CASE_SENSITIVE__ ) | |
106 | - gl_opts |= GLOB_CASEMATCH; | |
104 | + int gl_opts = GLOB_NOCHECK | (_CRT_glob & (GLOB_CASEMATCH | GLOB_BRACE)); | |
107 | 105 | |
108 | 106 | /* We explicitly DO NOT use the GLOB_DOOFFS capability; ensure that |
109 | 107 | * the associated field, in the glob_t structure, is initialized to |