|
From: Keith M. <no...@so...> - 2017-02-12 16:34:41
|
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Repository: mingw-org-wsl".
The branch, 5.0-active has been updated
via 1559fe3708515b7c61a0e7d2672102ec5ea1f1fa (commit)
via f034c6d7403650f81e872f025913fb6d46bba894 (commit)
from f6247c6eec6e8bd16880df5f9bdcecb6deff196c (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
https://sf.net/p/mingw/mingw-org-wsl/ci/1559fe3708515b7c61a0e7d2672102ec5ea1f1fa/
commit 1559fe3708515b7c61a0e7d2672102ec5ea1f1fa
Author: Keith Marshall <kei...@us...>
Date: Sun Feb 12 10:12:06 2017 +0000
Support brace expansion in globbing patterns.
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 <kei...@us...>
+
+ 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 <kei...@us...>
Refactor <getopt.h> and <unistd.h> 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.h>
+ *
+ * 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 <stddef.h>, just as <sys/types.h> does.
*/
#define __need_size_t
#include <stddef.h>
@@ -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
https://sf.net/p/mingw/mingw-org-wsl/ci/f034c6d7403650f81e872f025913fb6d46bba894/
commit f034c6d7403650f81e872f025913fb6d46bba894
Author: Keith Marshall <kei...@us...>
Date: Sat Feb 11 12:35:12 2017 +0000
Refactor <getopt.h> and <unistd.h> shared declarations.
diff --git a/mingwrt/ChangeLog b/mingwrt/ChangeLog
index e316cf1..322c564 100644
--- a/mingwrt/ChangeLog
+++ b/mingwrt/ChangeLog
@@ -1,3 +1,21 @@
+2017-02-11 Keith Marshall <kei...@us...>
+
+ Refactor <getopt.h> and <unistd.h> shared declarations.
+
+ * include/getopt.h: Assert copyright.
+ (_BEGIN_C_DECLS, _END_C_DECLS): Use as appropriate.
+ (__GETOPT_H__, __GETOPT_LONG_H__): Delete them; replace them with...
+ (_GETOPT_H): This new macro; it guards the entire file, except when...
+ [__UNISTD_H_SOURCED__]: ...do not activate it; hence when...
+ [!_GETOPT_H]: ...do not expose API declarations for...
+ (getopt_long, getopt_long_only): ...these functions.
+ [_GETOPT_H && _UNISTD_H]: Skip second pass API declarations for...
+ (getopt): ...this function.
+
+ * include/unistd.h: Use the #include "..." form when including...
+ (io.h, process.h, getopt.h): ...these, to ensure correct association.
+ (ftruncate): Map it directly to MSVCRT.DLL's _chsize() entry point.
+
2017-02-10 Keith Marshall <kei...@us...>
Avoid unnecessary duplication of configuration files.
diff --git a/mingwrt/include/getopt.h b/mingwrt/include/getopt.h
index 45a8afb..28f02d4 100644
--- a/mingwrt/include/getopt.h
+++ b/mingwrt/include/getopt.h
@@ -1,41 +1,62 @@
-#ifndef __GETOPT_H__
/*
* getopt.h
*
- * $Id$
- *
* Defines constants and function prototypes required to implement
- * the `getopt', `getopt_long' and `getopt_long_only' APIs.
- *
- * This file is part of the MinGW32 package set.
+ * the getopt(), getopt_long() and getopt_long_only() APIs.
*
- * Contributed by Keith Marshall <kei...@us...>
+ * $Id$
*
+ * Written by Keith Marshall <kei...@us...>
+ * Copyright (C) 2003, 2008, 2009, 2017, MinGW.org Project.
*
- * THIS SOFTWARE IS NOT COPYRIGHTED
*
- * This source code is offered for use in the public domain. You may
- * use, modify or distribute it freely.
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
*
- * This code is distributed in the hope that it will be useful but
- * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
- * DISCLAIMED. This includes but is not limited to warranties of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
*
- * $Revision$
- * $Author$
- * $Date$
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
*
*/
-#define __GETOPT_H__
+#ifndef _GETOPT_H
+#pragma GCC system_header
-/* All the headers include this file. */
-#include <_mingw.h>
+#ifndef __UNISTD_H_SOURCED__
+/* POSIX requires the getopt() API to be specified in <unistd.h>; thus,
+ * <unistd.h> includes <getopt.h>. However, we do not want to expose the
+ * getopt_long() or getopt_long_only() APIs, when included in this manner.
+ * Thus, we process only part of <getopt.h> when __UNISTD_H_SOURCED__ has
+ * been defined, and activate the _GETOPT_H repeat inclusion guard macro
+ * only when it has not.
+ */
+#define _GETOPT_H
-#ifdef __cplusplus
-extern "C" {
+/* All MinGW headers are required to include <_mingw.h>, before anything
+ * else; however, when sourced by <unistd.h>, this has been done already.
+ */
+#include <_mingw.h>
#endif
+_BEGIN_C_DECLS
+
+#if ! (defined _GETOPT_H && defined _UNISTD_H)
+/* This section of <getopt.h> is always to be processed, but it doesn't
+ * need to be processed twice; if both _GETOPT_H and _UNISTD_H have been
+ * defined, when we get to here, then we have reached this point for the
+ * second time, so we may safely skip this section.
+ */
extern int optind; /* index of first non-option in argv */
extern int optopt; /* single option character, as parsed */
extern int opterr; /* flag to enable built-in diagnostics... */
@@ -46,66 +67,41 @@ extern char *optarg; /* pointer to argument of current option */
extern int getopt( int, char * const [], const char * );
#ifdef _BSD_SOURCE
-/*
- * BSD adds the non-standard `optreset' feature, for reinitialisation
- * of `getopt' parsing. We support this feature, for applications which
+/* BSD adds the non-standard "optreset" feature, for reinitialization
+ * of getopt() parsing. We support this feature, for applications which
* proclaim their BSD heritage, before including this header; however,
* to maintain portability, developers are advised to avoid it.
*/
# define optreset __mingw_optreset
extern int optreset;
-#endif
-#ifdef __cplusplus
-}
-#endif
-/*
- * POSIX requires the `getopt' API to be specified in `unistd.h';
- * thus, `unistd.h' includes this header. However, we do not want
- * to expose the `getopt_long' or `getopt_long_only' APIs, when
- * included in this manner. Thus, close the standard __GETOPT_H__
- * declarations block, and open an additional __GETOPT_LONG_H__
- * specific block, only when *not* __UNISTD_H_SOURCED__, in which
- * to declare the extended API.
- */
-#endif /* !defined(__GETOPT_H__) */
-#if !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__)
-#define __GETOPT_LONG_H__
-#ifdef __cplusplus
-extern "C" {
-#endif
+#endif /* _BSD_SOURCE */
+#endif /* !(_GETOPT_H && _UNISTD_H) */
+#ifdef _GETOPT_H
+/* This is the section of <getopt.h> which declares the getopt_long()
+ * and getopt_long_only() APIs; it is processed only when <getopt.h>
+ * is included directly.
+ */
struct option /* specification for a long form option... */
-{
- const char *name; /* option name, without leading hyphens */
+{ const char *name; /* option name, without leading hyphens */
int has_arg; /* does it take an argument? */
int *flag; /* where to save its status, or NULL */
int val; /* its associated status value */
};
-enum /* permitted values for its `has_arg' field... */
-{
- no_argument = 0, /* option never takes an argument */
+enum /* permitted values for its "has_arg" field... */
+{ no_argument = 0, /* option never takes an argument */
required_argument, /* option always requires an argument */
optional_argument /* option may take an argument */
};
extern int getopt_long( int, char * const [], const char *, const struct option *, int * );
extern int getopt_long_only( int, char * const [], const char *, const struct option *, int * );
-/*
- * Previous MinGW implementation had...
- */
-#ifndef HAVE_DECL_GETOPT
-/*
- * ...for the long form API only; keep this for compatibility.
- */
-# define HAVE_DECL_GETOPT 1
-#endif
-#ifdef __cplusplus
-}
-#endif
+#endif /* _GETOPT_H */
+
+_END_C_DECLS
-#endif /* !defined(__UNISTD_H_SOURCED__) && !defined(__GETOPT_LONG_H__) */
-/* $RCSfile$$Revision$: end of file */
+#endif /* !_GETOPT_H: $RCSfile$: end of file */
diff --git a/mingwrt/include/unistd.h b/mingwrt/include/unistd.h
index 495f3af..4080ab5 100644
--- a/mingwrt/include/unistd.h
+++ b/mingwrt/include/unistd.h
@@ -11,7 +11,7 @@
* Ramiro Polla <ra...@li...>
* Gregory McGarry <gre...@us...>
* Keith Marshall <kei...@us...>
- * Copyright (C) 1997, 1999, 2002-2004, 2007-2009, 2014-2016,
+ * Copyright (C) 1997, 1999, 2002-2004, 2007-2009, 2014-2017,
* MinGW.org Project.
*
*
@@ -50,9 +50,12 @@
*/
#define __UNISTD_H_SOURCED__ 1
-#include <io.h>
-#include <process.h>
-#include <getopt.h>
+/* Use "..." inclusion here, to ensure that we get our own headers, which
+ * are designed to interoperate with the __UNISTD_H_SOURCED__ filter.
+ */
+#include "io.h"
+#include "process.h"
+#include "getopt.h"
/* These are defined in stdio.h. POSIX also requires that they
* are to be consistently defined here; don't guard against prior
@@ -125,7 +128,7 @@ unsigned sleep( unsigned period ){ return __mingw_sleep( period, 0 ); }
int __cdecl ftruncate( int, off_t );
#ifndef __NO_INLINE__
-__CRT_INLINE __JMPSTUB__(( FUNCTION = ftruncate, REMAPPED = _chsize ))
+__CRT_INLINE __JMPSTUB__(( FUNCTION = ftruncate, DLLENTRY = _chsize ))
int ftruncate( int __fd, off_t __length ){ return _chsize( __fd, __length ); }
#endif
@@ -134,4 +137,4 @@ _END_C_DECLS
#endif /* _POSIX_C_SOURCE */
#undef __UNISTD_H_SOURCED__
-#endif /* ! _UNISTD_H: $RCSfile$: end of file */
+#endif /* !_UNISTD_H: $RCSfile$: end of file */
-----------------------------------------------------------------------
Summary of changes:
mingwrt/ChangeLog | 38 +++
mingwrt/include/_mingw.h.in | 10 +-
mingwrt/include/getopt.h | 122 +++++----
mingwrt/include/glob.h | 18 +-
mingwrt/include/unistd.h | 15 +-
mingwrt/mingwex/glob.c | 583 +++++++++++++++++++++++++++++++-------------
mingwrt/setargv.c | 4 +-
7 files changed, 537 insertions(+), 253 deletions(-)
hooks/post-receive
--
Repository: mingw-org-wsl
|