From 1559fe3708515b7c61a0e7d2672102ec5ea1f1fa Mon Sep 17 00:00:00 2001 From: Keith Marshall Date: Sun, 12 Feb 2017 10:12:06 +0000 Subject: [PATCH] Support brace expansion in globbing patterns. --- mingwrt/ChangeLog | 20 ++ mingwrt/include/_mingw.h.in | 10 +- mingwrt/include/glob.h | 18 +- mingwrt/mingwex/glob.c | 583 +++++++++++++++++++++++++++++++------------- mingwrt/setargv.c | 4 +- 5 files changed, 451 insertions(+), 184 deletions(-) diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog index 322c564..e3ffe46 100644 --- a/mingwrt/ChangeLog +++ b/mingwrt/ChangeLog @@ -1,3 +1,23 @@ +2017-02-12 Keith Marshall + + Support brace expansion in globbing patterns. + + * include/glob.h (GLOB_BRACE): New manifest constant; define it... + (__GLOB_FLAG__): ...in terms of this macro. + + * mingwex/glob.c (glob_match): Reindent, with preamble invoking... + (glob_brace_expand): ...this new static inline function; implement it. + (GLOB_INIT, GLOB_FREE): Redefine them, relating them to... + (__GLOB_FLAG_OFFSET_HIGH_WATER_MARK): ...this. + + * setargv.c (__mingw32_setargv) [_CRT_glob]: Check if it includes... + [GLOB_CASEMATCH | GLOB_BRACE]: either of these; remove check for... + [__CRT_GLOB_CASE_SENSITIVE__]: ...this defunct option. + + * include/_mingw.h.in (GLOB_BRACE): Note its use in _CRT_glob. + (GLOB_CASEMATCH): Likewise; this replaces all former usage of... + (__CRT_GLOB_CASE_SENSITIVE__): ...this; delete definition. + 2017-02-11 Keith Marshall Refactor and shared declarations. diff --git a/mingwrt/include/_mingw.h.in b/mingwrt/include/_mingw.h.in index fd99590..da4ea87 100644 --- a/mingwrt/include/_mingw.h.in +++ b/mingwrt/include/_mingw.h.in @@ -132,7 +132,10 @@ * character which is either included * in, or excluded from the group. * - * __CRT_GLOB_CASE_SENSITIVE__ enable case sensitive matching for + * The following options, which may also be specified within _CRT_glob, + * are specified in terms of their glob() flags, as defined in + * + * GLOB_CASEMATCH enable case sensitive matching for * globbing patterns; this is default * behaviour for POSIX, but because of * the case insensitive nature of the @@ -140,10 +143,13 @@ * appropriate to use case insensitive * globbing as the MinGW default. * + * GLOB_BRACE enable expansion of GNU style brace + * delimited expression groups within + * the globbing pattern. + * */ #define __CRT_GLOB_USE_SINGLE_QUOTE__ 0x0010 #define __CRT_GLOB_BRACKET_GROUPS__ 0x0020 -#define __CRT_GLOB_CASE_SENSITIVE__ 0x0040 /* The MinGW globbing algorithm uses the ASCII DEL control code as a marker * for globbing characters which were embedded within quoted arguments; (the diff --git a/mingwrt/include/glob.h b/mingwrt/include/glob.h index 45e1c9a..b73302a 100644 --- a/mingwrt/include/glob.h +++ b/mingwrt/include/glob.h @@ -32,12 +32,15 @@ * */ #define _GLOB_H 1 -#include <_mingw.h> #pragma GCC system_header +/* All MinGW.org system headers are required to include <_mingw.h>. + */ +#include <_mingw.h> + #ifndef RC_INVOKED /* POSIX requires glob.h to define the size_t type; we need to - * get this from GCC, just as sys/types.h does. + * get this from GCC's , just as does. */ #define __need_size_t #include @@ -73,8 +76,8 @@ enum { * GNU's implementation of glob() supports a supplementary set of * options, none of which are required by POSIX. We include these * for reference, and to reserve the flag identities for a possible - * future implementation; the current MinGW implementation does not - * support them. + * future implementation; of these extensions, the current MinGW + * implementation supports only GLOB_BRACE. */ __GLOB_TILDE_OFFSET, __GLOB_TILDE_CHECK_OFFSET, @@ -115,6 +118,11 @@ enum { #define GLOB_NOESCAPE __GLOB_FLAG__(NOESCAPE) #define GLOB_NOSORT __GLOB_FLAG__(NOSORT) +/* Flag definitions for those GNU extensions, as listed above, for which + * we provide support; (i.e. GLOB_BRACE only, at present). + */ +#define GLOB_BRACE __GLOB_FLAG__(BRACE) + /* Additional flags definitions, for MinGW specific extensions. */ #define GLOB_CASEMATCH __GLOB_FLAG__(CASEMATCH) @@ -155,4 +163,4 @@ _END_C_DECLS #define GLOB_NOSPACE (3) #endif /* ! RC_INVOKED */ -#endif /* ! defined _GLOB_H */ +#endif /* !_GLOB_H: $RCSfile$: end of file */ diff --git a/mingwrt/mingwex/glob.c b/mingwrt/mingwex/glob.c index 1f064e1..b51fdf0 100644 --- a/mingwrt/mingwex/glob.c +++ b/mingwrt/mingwex/glob.c @@ -728,6 +728,132 @@ accept_glob_nocheck_match( const char *pattern, int flags ) return (flags & GLOB_NOCHECK) && (is_glob_pattern( pattern, flags ) == 0); } +GLOB_INLINE int +glob_brace_expand( char *dest, const char *src, const char **resume ) +{ + /* Helper to iteratively expand the first substitution field within + * a glob brace expression, while recursively collecting the set of + * individual globbing patterns to be processed by glob_match(), when + * GLOB_BRACE is specified, and the original pattern includes a brace + * expression. (Notice that this does not guarantee to fully expand + * the pattern in a single pass; recursion within glob_match() will + * ensure that this is achieved, before attempting to match each + * possible expansion of the original pattern). + * + * Returns zero on a successful (possibly partial) expansion; > zero + * indicates unmatched opening braces, (an error condition). + */ + char c; int level = 1; + do { /* Copy characters one by one, from the start of the current + * substitution field within the original glob pattern, to the + * appropriate location in the pattern which will be presented + * to glob_match(). The initial part of this copy represents + * the substitution for the outermost level of brace bounded + * expression, terminating at either the closing brace or at + * any intervening comma at this level; however... + */ + if( (c = *++src) == glob_escape_char ) + { /* ...any escaped character must be copied verbatim, without + * being considered as a possible substitution terminator... + */ + *dest++ = c; *dest++ = c = *++src; + /* ...while taking care not to overrun the ultimate string + * terminator of the original pattern. + */ + if( c != '\0' ) c = *++src; + } + /* Provided it has not been escaped, any closing brace, or a + * comma separator at the outer level only, results in closure + * of a brace nesting level... + */ + if( (c == '}') || ((c == ',') && (level == 1)) ) --level; + /* + * ...while an opening brace creates a new (inner) level. + */ + else if( c == '{' ) ++level; + + /* Provided we have not closed the outermost brace expression + * level, complete the copy of the current character within + * the substitution... + */ + if( level > 0 ) *dest++ = c; + /* ...continuing to the next character, until the outermost + * level has been reached, or the original pattern string + * has been exhausted. + */ + } while( (level > 0) && (c != '\0') ); + + /* Save a reference to the point, within the original pattern, + * where the current substitution ended, and thus where the next + * iteration (if any) is to begin. + */ + *resume = src; + + /* Complete construction of a candidate pattern, to be passed + * to glob_match(), by copying any characters which follow the + * closing brace of the initial brace bounded expression within + * the original pattern; thus... + */ + if( c != '\0' ) + { /* ...when any characters are present, beyond the current + * resume point... + */ + if( c == ',' ) + { /* ...and when any of these represent a substitution which + * is to be made in a subsequent iteration... + */ + level = 1; + do { /* ...we simply skip over all characters, up to and + * including the closing brace at the outermost level + * of expression, (while once again taking care not + * to overrun the string terminator)... + */ + if( c != '\0' ) ++src; + /* ...and once again, honouring escapes which may be + * intended to force literal interpretation of '{'... + */ + while( (*src == glob_escape_char) && (*++src != '\0') ) ++src; + /* + * ...and simply ignoring any nested (inner) brace + * bounded expression... + */ + if( *src == '{' ) ++level; else if( *src == '}' ) --level; + /* + * ...we continue skipping, until we find the closing + * brace at the outermost level of the expression, or + * we have have exhausted the original pattern. + */ + } while( ((c = *src) != '\0') && (level > 0) ); + } + /* Finally... + */ + if( level == 0 ) + { /* ...when we've skipped to the closing brace ... (checking + * that we didn't exhaust the original pattern is belt and + * braces here, because *src should be '}') ... we now skip + * past it... + */ + if( c != '\0' ) ++src; + /* ...we simply copy all further characters from the original + * pattern, without consideration that there may be any further + * possible expansion; (this will be picked up by recursion). + */ + do { *dest++ = *src; } while( *src++ != '\0' ); + } + else + /* Alternatively, when the closing brace has not been found, + * (which implies exhaustion of the original pattern), we + * must ensure that the expanded copy is terminated. + */ + *dest = '\0'; + } + /* Regardless, we return the residual brace expansion level; zero + * indicates successful expansion; > zero is an error, indicating + * one (or more) unmatched opening braces. + */ + return level; +} + static int glob_match( const char *pattern, int flags, int (*errfn)(), glob_t *gl_buf ) { @@ -735,230 +861,339 @@ glob_match( const char *pattern, int flags, int (*errfn)(), glob_t *gl_buf ) * implementation, recursively decomposing the pattern into separate * globbable path components, to collect the union of all possible * matches to the pattern, in all possible matching directories. + * + * At the outset, assume that this will succeed. */ - glob_t local_gl_buf; int status = GLOB_SUCCESS; - /* Begin by separating out any path prefix from the glob pattern. + /* To handle the GNU specific GLOB_BRACE option, we need a + * recursive preamble to the bare glob_match() strategy; when + * GLOB_BRACE expansion is specified... */ - char dirbuf[1 + strlen( pattern )]; - const char *dir = dirname( memcpy( dirbuf, pattern, sizeof( dirbuf )) ); - char **dirp, preferred_dirsep = GLOB_DIRSEP; + int brace_option; + if( (brace_option = flags & GLOB_BRACE) == GLOB_BRACE ) + { + /* ...we recursively parse the original pattern, so as to + * decompose it into a series of substitute patterns, each + * of which represents one pattern expansion to which glob + * matching is applied in turn, such that the aggregate of + * matches for the series represents all possible matches + * for all possible expansions of the original pattern. + */ + const char *src = pattern; + char c, sub_pattern[1 + strlen( pattern )], *dest = sub_pattern; - /* Initialise a temporary local glob_t structure, to capture the - * intermediate results at the current level of recursion... - */ - local_gl_buf.gl_offs = 0; - if( (status = glob_initialise( &local_gl_buf )) != GLOB_SUCCESS ) - /* - * ...bailing out if unsuccessful. + /* We begin by initialising the prefix portion which is + * common to all substitute patterns... + */ + do { /* ...by copying characters one at a time, from the + * original pattern to the substitute pattern buffer... + */ + while( *src == glob_escape_char ) + { + /* ...ensuring that all escaped characters are + * copied verbatim, without consideration as a + * possible brace expression initiator... + */ + *dest++ = *src++; + /* + * ...but taking care that we don't overrun the + * original pattern's string terminator... + */ + if( *src != '\0') *dest++ = *src++; + } + /* ...copying every character up to but excluding the + * opening brace of the first brace bounded expression + * (if any), or up to and including the NUL terminator + * otherwise... + */ + if( (c = *src) != '{' ) *dest++ = *src++; + /* + * ...repeating until we either exhaust the original + * pattern, or we find an opening brace. + */ + } while( (c != '\0') && (c != '{') ); + + /* After copying the prefix, (which may represent the entire + * pattern)... */ - return status; + if( c == '{' ) + /* ...when there is a brace bounded expression to expand... + */ + do { /* ...iterate to construct each of its expansions in + * turn, (together with any common suffix), and... + */ + if( glob_brace_expand( dest, src, &src ) == 0 ) + { + /* ...on success, note that there may be further + * embedded brace bounded sub-expressions; recurse + * to achieve full expansion... + */ + status = glob_match( sub_pattern, flags, errfn, gl_buf ); + /* + * ...and ensure that matches to all expansions + * after the first, will be appended. + */ + flags |= GLOB_APPEND; + } + else + { /* Brace expansion failed, (which implies an opening + * brace with no matching closing brace); bail out. + * + * FIXME: if errfn is specified (not NULL), perhaps we + * should invoke it (but how best? POSIX says it is to + * be invoked when pattern resolves to a directory which + * cannot be opened, or cannot be read; maybe pass the + * original failing pattern, with errno = EINVAL?). + */ + status = GLOB_ABORTED; + } + /* Repeat iteration until all specified substitutions + * for the current expression have been processed, (or + * aborted). + */ + } while( (status != GLOB_ABORTED) && (*src == ',') ); + + else + /* The current brace expression has been reduced to its final + * form, (with no further expansion pending); release it for + * fall-through glob matching. + */ + brace_option = 0; + } - /* Check if there are any globbing tokens in the path prefix... + /* On falling through brace expansion, (if any)... */ - if( is_glob_pattern( dir, flags ) ) - /* - * ...and recurse to identify all possible matching prefixes, - * as may be necessary... + if( brace_option == 0 ) + { + /* ...we have exactly one pattern, with no possible expansions + * of brace expressions, to be globbed; (alternate expansions of + * any brace expressions are processed in alternative recursive + * invocations of this function). */ - status = glob_match( dir, flags | GLOB_DIRONLY, errfn, &local_gl_buf ); + glob_t local_gl_buf; - else - /* ...or simply store the current prefix, if not. + /* Begin by separating out any path prefix from the glob pattern. */ - status = glob_store_entry( glob_strdup( dir ), &local_gl_buf ); + char dirbuf[1 + strlen( pattern )]; + const char *dir = dirname( memcpy( dirbuf, pattern, sizeof( dirbuf )) ); + char **dirp, preferred_dirsep = GLOB_DIRSEP; - /* Check nothing has gone wrong, so far... - */ - if( status != GLOB_SUCCESS ) - /* - * ...and bail out if necessary. - */ - return status; - - /* The original "pattern" argument may have included a path name - * prefix, which we used "dirname()" to isolate. If there was no - * such prefix, then "dirname()" would have reported an effective - * prefix which is identically equal to "."; however, this would - * also be the case if the prefix was "./" (or ".\\" in the case - * of a WIN32 host). Thus, we may deduce that... - */ - if( glob_is_dirsep( pattern[1] ) || (strcmp( dir, "." ) != 0) ) - { - /* ...when the prefix is not reported as ".", or even if it is - * but the original pattern had "./" (or ".\\") as the prefix, - * then we must adjust to identify the effective pattern with - * its original prefix stripped away... + /* Initialise a temporary local glob_t structure, to capture the + * intermediate results at the current level of recursion... */ - const char *tail = pattern + strlen( dir ); - while( (tail > pattern) && ! glob_is_dirsep( *tail ) ) - --tail; - while( glob_is_dirsep( *tail ) ) - preferred_dirsep = *tail++; - pattern = tail; - } + local_gl_buf.gl_offs = 0; + if( (status = glob_initialise( &local_gl_buf )) != GLOB_SUCCESS ) + /* + * ...bailing out if unsuccessful. + */ + return status; - else - /* ...otherwise, we simply note that there was no prefix. + /* Check if there are any globbing tokens in the path prefix... */ - dir = NULL; + if( is_glob_pattern( dir, flags ) ) + /* + * ...and recurse to identify all possible matching prefixes, + * as may be necessary... + */ + status = glob_match( dir, flags | GLOB_DIRONLY, errfn, &local_gl_buf ); - /* We now have a globbed list of prefix directories, returned from - * recursive processing, in local_gl_buf.gl_pathv, and we also have - * a separate pattern which we may attempt to match in each of them; - * at the outset, we have yet to match this pattern to anything. - */ - status = GLOB_NOMATCH; + else + /* ...or simply store the current prefix, if not. + */ + status = glob_store_entry( glob_strdup( dir ), &local_gl_buf ); - /* When the caller has enabled the GLOB_NOCHECK option, then in the - * case of any pattern with no prefix, and which contains no explicit - * globbing token... - */ - if( (dir == NULL) && accept_glob_nocheck_match( pattern, flags ) ) - { - /* ...we prefer to store it as is, without any attempt to find - * a glob match, (which could also induce a case transliteration - * on MS-Windows' case-insensitive file system)... + /* Check nothing has gone wrong, so far... */ - glob_store_entry( glob_strdup( pattern ), gl_buf ); - status = GLOB_SUCCESS; - } - /* ...otherwise we initiate glob matching, to find all possible - * file system matches for the designated pattern, within each of - * the identified prefix directory paths. - */ - else for( dirp = local_gl_buf.gl_pathv; *dirp != NULL; free( *dirp++ ) ) - { - /* Provided an earlier cycle hasn't scheduled an abort... + if( status != GLOB_SUCCESS ) + /* + * ...and bail out if necessary. + */ + return status; + + /* The original "pattern" argument may have included a path name + * prefix, which we used "dirname()" to isolate. If there was no + * such prefix, then "dirname()" would have reported an effective + * prefix which is identically equal to "."; however, this would + * also be the case if the prefix was "./" (or ".\\" in the case + * of a WIN32 host). Thus, we may deduce that... */ - if( status != GLOB_ABORTED ) + if( glob_is_dirsep( pattern[1] ) || (strcmp( dir, "." ) != 0) ) { - /* ...take each candidate directory in turn, and prepare - * to collate any matched entities within it... + /* ...when the prefix is not reported as ".", or even if it is + * but the original pattern had "./" (or ".\\") as the prefix, + * then we must adjust to identify the effective pattern with + * its original prefix stripped away... + */ + const char *tail = pattern + strlen( dir ); + while( (tail > pattern) && ! glob_is_dirsep( *tail ) ) + --tail; + while( glob_is_dirsep( *tail ) ) + preferred_dirsep = *tail++; + pattern = tail; + } + + else + /* ...otherwise, we simply note that there was no prefix. */ - struct glob_collator *collator = NULL; + dir = NULL; - /* ...attempt to open the current candidate directory... + /* We now have a globbed list of prefix directories, returned from + * recursive processing, in local_gl_buf.gl_pathv, and we also have + * a separate pattern which we may attempt to match in each of them; + * at the outset, we have yet to match this pattern to anything. + */ + status = GLOB_NOMATCH; + + /* When the caller has enabled the GLOB_NOCHECK option, then in the + * case of any pattern with no prefix, and which contains no explicit + * globbing token... + */ + if( (dir == NULL) && accept_glob_nocheck_match( pattern, flags ) ) + { + /* ...we prefer to store it as is, without any attempt to find + * a glob match, (which could also induce a case transliteration + * on MS-Windows' case-insensitive file system)... + */ + glob_store_entry( glob_strdup( pattern ), gl_buf ); + status = GLOB_SUCCESS; + } + /* ...otherwise we initiate glob matching, to find all possible + * file system matches for the designated pattern, within each of + * the identified prefix directory paths. + */ + else for( dirp = local_gl_buf.gl_pathv; *dirp != NULL; free( *dirp++ ) ) + { + /* Provided an earlier cycle hasn't scheduled an abort... */ - DIR *dp; - if( (dp = opendir( *dirp )) != NULL ) + if( status != GLOB_ABORTED ) { - /* ...and when successful, instantiate a dirent structure... + /* ...take each candidate directory in turn, and prepare + * to collate any matched entities within it... + */ + struct glob_collator *collator = NULL; + + /* ...attempt to open the current candidate directory... */ - struct dirent *entry; - size_t dirlen = (dir == NULL) ? 0 : strlen( *dirp ); - while( (entry = readdir( dp )) != NULL ) + DIR *dp; + if( (dp = opendir( *dirp )) != NULL ) { - /* ...into which we read each entry from the candidate - * directory, in turn, then... - */ - if( (((flags & GLOB_DIRONLY) == 0) || GLOB_ISDIR( entry )) - /* - * ...provided we don't require it to be a subdirectory, - * or it actually is one... - */ - && (glob_strcmp( pattern, entry->d_name, flags ) == 0) ) + /* ...and when successful, instantiate a dirent structure... + */ + struct dirent *entry; + size_t dirlen = (dir == NULL) ? 0 : strlen( *dirp ); + while( (entry = readdir( dp )) != NULL ) { - /* ...and it is a globbed match for the pattern, then - * we allocate a temporary local buffer of sufficient - * size to assemble the matching path name... + /* ...into which we read each entry from the candidate + * directory, in turn, then... */ - char *found; - size_t prefix; - size_t matchlen = D_NAMLEN( entry ); - char matchpath[2 + dirlen + matchlen]; - if( (prefix = dirlen) > 0 ) + if( (((flags & GLOB_DIRONLY) == 0) || GLOB_ISDIR( entry )) + /* + * ...provided we don't require it to be a subdirectory, + * or it actually is one... + */ + && (glob_strcmp( pattern, entry->d_name, flags ) == 0) ) { - /* ...first copying the prefix, if any, - * followed by a directory name separator... + /* ...and it is a globbed match for the pattern, then + * we allocate a temporary local buffer of sufficient + * size to assemble the matching path name... */ - memcpy( matchpath, *dirp, dirlen ); - if( ! glob_is_dirsep( matchpath[prefix - 1] ) ) - matchpath[prefix++] = preferred_dirsep; - } - /* ...and append the matching dirent entry. - */ - memcpy( matchpath + prefix, entry->d_name, matchlen + 1 ); - - /* Duplicate the content of the temporary buffer to - * the heap, for assignment into gl_buf->gl_pathv... - */ - if( (found = glob_strdup( matchpath )) == NULL ) - /* - * ...setting the appropriate error code, in the - * event that the heap memory has been exhausted. + char *found; + size_t prefix; + size_t matchlen = D_NAMLEN( entry ); + char matchpath[2 + dirlen + matchlen]; + if( (prefix = dirlen) > 0 ) + { + /* ...first copying the prefix, if any, + * followed by a directory name separator... + */ + memcpy( matchpath, *dirp, dirlen ); + if( ! glob_is_dirsep( matchpath[prefix - 1] ) ) + matchpath[prefix++] = preferred_dirsep; + } + /* ...and append the matching dirent entry. */ - status = GLOB_NOSPACE; + memcpy( matchpath + prefix, entry->d_name, matchlen + 1 ); - else - { /* This glob match has been successfully recorded on - * the heap, ready for assignment to gl_buf->gl_pathv; - * if this is the first match assigned to this gl_buf, - * and we haven't trapped any prior error... + /* Duplicate the content of the temporary buffer to + * the heap, for assignment into gl_buf->gl_pathv... */ - if( status == GLOB_NOMATCH ) + if( (found = glob_strdup( matchpath )) == NULL ) /* - * ...then record this successful match. + * ...setting the appropriate error code, in the + * event that the heap memory has been exhausted. */ - status = GLOB_SUCCESS; + status = GLOB_NOSPACE; - if( (flags & GLOB_NOSORT) == 0 ) - { - /* The results of this glob are to be sorted in - * collating sequence order; divert the current - * match into the collator. - */ - collator = glob_collate_entry( collator, found, flags ); - } else - { /* Sorting has been suppressed for this glob; - * just add the current match directly into the - * result vector at gl_buf->gl_pathv. + { /* This glob match has been successfully recorded on + * the heap, ready for assignment to gl_buf->gl_pathv; + * if this is the first match assigned to this gl_buf, + * and we haven't trapped any prior error... */ - glob_store_entry( found, gl_buf ); + if( status == GLOB_NOMATCH ) + /* + * ...then record this successful match. + */ + status = GLOB_SUCCESS; + + if( (flags & GLOB_NOSORT) == 0 ) + { + /* The results of this glob are to be sorted in + * collating sequence order; divert the current + * match into the collator. + */ + collator = glob_collate_entry( collator, found, flags ); + } + else + { /* Sorting has been suppressed for this glob; + * just add the current match directly into the + * result vector at gl_buf->gl_pathv. + */ + glob_store_entry( found, gl_buf ); + } } } } + /* When we've processed all of the entries in the current + * prefix directory, we may close it. + */ + closedir( dp ); } - /* When we've processed all of the entries in the current - * prefix directory, we may close it. - */ - closedir( dp ); - } - /* In the event of failure to open the candidate prefix directory... - */ - else if( (flags & GLOB_ERR) || ((errfn != NULL) && errfn( *dirp, errno )) ) - /* - * ...and when the caller has set the GLOB_ERR flag, or has provided - * an error handler which returns non-zero for the failure condition, - * then we schedule an abort. + /* In the event of failure to open the candidate prefix directory... */ - status = GLOB_ABORTED; + else if( (flags & GLOB_ERR) || ((errfn != NULL) && errfn(*dirp, errno)) ) + /* + * ...and when the caller has set the GLOB_ERR flag, or has provided + * an error handler which returns non-zero for the failure condition, + * then we schedule an abort. + */ + status = GLOB_ABORTED; - /* When we diverted the glob results for collation... - */ - if( collator != NULL ) - /* - * ...then we redirect them to gl_buf->gl_pathv now, before we - * begin a new cycle, to process any further prefix directories - * which may have been identified; note that we do this even if - * we scheduled an abort, so that we may return any results we - * may have already collected before the error occurred. + /* When we diverted the glob results for collation... */ - glob_store_collated_entries( collator, gl_buf ); + if( collator != NULL ) + /* + * ...then we redirect them to gl_buf->gl_pathv now, before we + * begin a new cycle, to process any further prefix directories + * which may have been identified; note that we do this even if + * we scheduled an abort, so that we may return any results we + * may have already collected before the error occurred. + */ + glob_store_collated_entries( collator, gl_buf ); + } } + /* Finally, free the memory block allocated for the results vector + * in the internal glob buffer, to avoid leaking memory, before we + * return the resultant status code. + */ + free( local_gl_buf.gl_pathv ); } - /* Finally, free the memory block allocated for the results vector - * in the internal glob buffer, to avoid leaking memory, before we - * return the resultant status code. - */ - free( local_gl_buf.gl_pathv ); return status; } -#define GLOB_INIT (0x100 << 0) -#define GLOB_FREE (0x100 << 1) +#define GLOB_INIT (1 << __GLOB_FLAG_OFFSET_HIGH_WATER_MARK) +#define GLOB_FREE (2 << __GLOB_FLAG_OFFSET_HIGH_WATER_MARK) GLOB_INLINE int glob_signed( const char *check, const char *magic ) { diff --git a/mingwrt/setargv.c b/mingwrt/setargv.c index 36aaab7..1b57f85 100644 --- a/mingwrt/setargv.c +++ b/mingwrt/setargv.c @@ -101,9 +101,7 @@ void __mingw32_setargv( const char *cmdline ) /* Capture any non-default globbing options, which the user may have * specified via a custom setting for _CRT_glob. */ - int gl_opts = GLOB_NOCHECK; - if( _CRT_glob & __CRT_GLOB_CASE_SENSITIVE__ ) - gl_opts |= GLOB_CASEMATCH; + int gl_opts = GLOB_NOCHECK | (_CRT_glob & (GLOB_CASEMATCH | GLOB_BRACE)); /* We explicitly DO NOT use the GLOB_DOOFFS capability; ensure that * the associated field, in the glob_t structure, is initialized to -- 2.11.0