Close of build 15.
Fix regressions in fnmatch rewrite.
https://bugzilla.redhat.com/show_bug.cgi?id=706203
http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/strings/apr_fnmatch.c?r1=1098902&r2=1124999
--- strings/apr_fnmatch.c.fnmatch
+++ strings/apr_fnmatch.c
@@ -90,10 +90,13 @@ static APR_INLINE int fnmatch_ch(const c
if (negate)
++*pattern;
+ /* ']' is an ordinary character at the start of the range pattern */
+ if (**pattern == ']')
+ goto leadingclosebrace;
+
while (**pattern)
{
- /* ']' is an ordinary character at the start of the range pattern */
- if ((**pattern == ']') && (*pattern > mismatch)) {
+ if (**pattern == ']') {
++*pattern;
/* XXX: Fix for MBCS character width */
++*string;
@@ -112,17 +115,23 @@ static APR_INLINE int fnmatch_ch(const c
if (slash && (**pattern == '/'))
break;
- /* Look at only well-formed range patterns; ']' is allowed only if escaped,
- * while '/' is not allowed at all in FNM_PATHNAME mode.
+leadingclosebrace:
+ /* Look at only well-formed range patterns;
+ * "x-]" is not allowed unless escaped ("x-\]")
+ * XXX: Fix for locale/MBCS character width
*/
- /* XXX: Fix for locale/MBCS character width */
- if (((*pattern)[1] == '-') && (*pattern)[2]
- && ((escape && ((*pattern)[2] != '\\'))
- ? (((*pattern)[2] != ']') && (!slash || ((*pattern)[2] != '/')))
- : (((*pattern)[3]) && (!slash || ((*pattern)[3] != '/'))))) {
+ if (((*pattern)[1] == '-') && ((*pattern)[2] != ']'))
+ {
startch = *pattern;
*pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2;
+ /* NOT a properly balanced [expr] pattern, EOS terminated
+ * or ranges containing a slash in FNM_PATHNAME mode pattern
+ * fall out to to the rewind and test '[' literal code path
+ */
+ if (!**pattern || (slash && (**pattern == '/')))
+ break;
+
/* XXX: handle locale/MBCS comparison, advance by MBCS char width */
if ((**string >= *startch) && (**string <= **pattern))
result = 0;
@@ -146,7 +155,9 @@ static APR_INLINE int fnmatch_ch(const c
++*pattern;
}
- /* NOT a properly balanced [expr] pattern; Rewind to test '[' literal */
+ /* NOT a properly balanced [expr] pattern; Rewind
+ * and reset result to test '[' literal
+ */
*pattern = mismatch;
result = APR_FNM_NOMATCH;
}
@@ -196,9 +207,13 @@ APR_DECLARE(int) apr_fnmatch(const char
const char *mismatch = NULL;
int matchlen = 0;
- while (*pattern)
+ if (*pattern == '*')
+ goto firstsegment;
+
+ while (*pattern && *string)
{
- /* Match balanced slashes, starting a new segment pattern
+ /* Pre-decode "\/" which has no special significance, and
+ * match balanced slashes, starting a new segment pattern
*/
if (slash && escape && (*pattern == '\\') && (pattern[1] == '/'))
++pattern;
@@ -207,6 +222,7 @@ APR_DECLARE(int) apr_fnmatch(const char
++string;
}
+firstsegment:
/* At the beginning of each segment, validate leading period behavior.
*/
if ((flags & APR_FNM_PERIOD) && (*string == '.'))
@@ -235,12 +251,17 @@ APR_DECLARE(int) apr_fnmatch(const char
/* Allow pattern '*' to be consumed even with no remaining string to match
*/
- while (*pattern && !(slash && ((*pattern == '/')
- || (escape && (*pattern == '\\')
- && (pattern[1] == '/'))))
- && ((string < strendseg)
- || ((*pattern == '*') && (string == strendseg))))
+ while (*pattern)
{
+ if ((string > strendseg)
+ || ((string == strendseg) && (*pattern != '*')))
+ break;
+
+ if (slash && ((*pattern == '/')
+ || (escape && (*pattern == '\\')
+ && (pattern[1] == '/'))))
+ break;
+
/* Reduce groups of '*' and '?' to n '?' matches
* followed by one '*' test for simplicity
*/
@@ -324,9 +345,10 @@ APR_DECLARE(int) apr_fnmatch(const char
if (*pattern == '*')
break;
- if (slash && ((*string == '/') || (*pattern == '/')
- || (escape && (*pattern == '\\')
- && (pattern[1] == '/'))))
+ if (slash && ((*string == '/')
+ || (*pattern == '/')
+ || (escape && (*pattern == '\\')
+ && (pattern[1] == '/'))))
break;
/* Compare ch's (the pattern is advanced over "\/" to the '/',
@@ -352,18 +374,18 @@ APR_DECLARE(int) apr_fnmatch(const char
}
}
- if (*string && (!slash || (*string != '/')))
+ if (*string && !(slash && (*string == '/')))
return APR_FNM_NOMATCH;
- if (*pattern && (!slash || ((*pattern != '/')
- && (!escape || (*pattern != '\\')
- || (pattern[1] != '/')))))
+ if (*pattern && !(slash && ((*pattern == '/')
+ || (escape && (*pattern == '\\')
+ && (pattern[1] == '/')))))
return APR_FNM_NOMATCH;
}
- /* pattern is at EOS; if string is also, declare success
+ /* Where both pattern and string are at EOS, declare success
*/
- if (!*string)
+ if (!*string && !*pattern)
return 0;
/* pattern didn't match to the end of string */