diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | posix/fnmatch.c | 96 | ||||
-rw-r--r-- | posix/testfnm.c | 33 |
3 files changed, 108 insertions, 30 deletions
@@ -1,3 +1,12 @@ +1999-04-26 Ulrich Drepper <drepper@cygnus.com> + + * posix/fnmatch.c (internal_fnmatch): Renamed from fnmatch. Take + extra parameter. Fix several more bugs involving wildcard and + ranges. + (fnmatch): New function. Call internal_fnmatch. + + * posix/testfnm.c: More test cases. + 1999-04-03 Andreas Jaeger <aj@arthur.rhein-neckar.de> * manual/install.texi (Configuring and compiling): Explain that diff --git a/posix/fnmatch.c b/posix/fnmatch.c index e0ff2c34d2..d31c375bd2 100644 --- a/posix/fnmatch.c +++ b/posix/fnmatch.c @@ -129,11 +129,10 @@ extern int errno; /* Match STRING against the filename pattern PATTERN, returning zero if it matches, nonzero if not. */ -int -fnmatch (pattern, string, flags) - const char *pattern; - const char *string; - int flags; +static int +internal_function +internal_fnmatch (const char *pattern, const char *string, + int no_leading_period, int flags) { register const char *p = pattern, *n = string; register unsigned char c; @@ -156,8 +155,7 @@ fnmatch (pattern, string, flags) return FNM_NOMATCH; else if (*n == '/' && (flags & FNM_FILE_NAME)) return FNM_NOMATCH; - else if (*n == '.' && (flags & FNM_PERIOD) && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + else if (*n == '.' && no_leading_period) return FNM_NOMATCH; break; @@ -175,8 +173,7 @@ fnmatch (pattern, string, flags) break; case '*': - if (*n == '.' && (flags & FNM_PERIOD) && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + if (*n == '.' && no_leading_period) return FNM_NOMATCH; for (c = *p++; c == '?' || c == '*'; c = *p++) @@ -214,9 +211,22 @@ fnmatch (pattern, string, flags) if (c == '[') { for (--p; n < endp; ++n) - if (fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + if (internal_fnmatch (p, n, + (n == string) && no_leading_period, + ((flags & FNM_FILE_NAME) + ? flags : (flags & ~FNM_PERIOD))) + == 0) return 0; } + else if (c == '/' && (flags & FNM_FILE_NAME)) + { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' + && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, + flags) == 0)) + return 0; + } else { if (c == '\\' && !(flags & FNM_NOESCAPE)) @@ -224,7 +234,13 @@ fnmatch (pattern, string, flags) c = FOLD (c); for (--p; n < endp; ++n) if (FOLD ((unsigned char) *n) == c - && fnmatch (p, n, flags & ~FNM_PERIOD) == 0) + && (internal_fnmatch (p, n, + ((n == string) + && no_leading_period), + ((flags & FNM_FILE_NAME) + ? flags + : (flags & ~FNM_PERIOD))) + == 0)) return 0; } } @@ -245,8 +261,7 @@ fnmatch (pattern, string, flags) if (*n == '\0') return FNM_NOMATCH; - if (*n == '.' && (flags & FNM_PERIOD) && - (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) + if (*n == '.' && no_leading_period) return FNM_NOMATCH; if (*n == '/' && (flags & FNM_FILE_NAME)) @@ -294,7 +309,15 @@ fnmatch (pattern, string, flags) p += 2; break; } - str[c1++] = 'c'; + if (c < 'a' || c >= 'z') + { + /* This cannot possibly be a character class name. + Match it as a normal range. */ + --p; + c = '['; + goto normal_bracket; + } + str[c1++] = c; } str[c1] = '\0'; @@ -325,26 +348,31 @@ fnmatch (pattern, string, flags) else if (c == '\0') /* [ (unterminated) loses. */ return FNM_NOMATCH; - else if (FOLD (c) == fn) - goto matched; - - cold = c; - c = *p++; - - if (c == '-' && *p != ']') + else { - /* It is a range. */ - unsigned char cend = *p++; - if (!(flags & FNM_NOESCAPE) && cend == '\\') - cend = *p++; - if (cend == '\0') - return FNM_NOMATCH; - - if (cold <= fn && fn <= FOLD (cend)) + normal_bracket: + if (FOLD (c) == fn) goto matched; + cold = c; c = *p++; + + if (c == '-' && *p != ']') + { + /* It is a range. */ + unsigned char cend = *p++; + if (!(flags & FNM_NOESCAPE) && cend == '\\') + cend = *p++; + if (cend == '\0') + return FNM_NOMATCH; + + if (cold <= fn && fn <= FOLD (cend)) + goto matched; + + c = *p++; + } } + if (c == ']') break; } @@ -404,4 +432,14 @@ fnmatch (pattern, string, flags) # undef FOLD } + +int +fnmatch (pattern, string, flags) + const char *pattern; + const char *string; + int flags; +{ + return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); +} + #endif /* _LIBC or not __GNU_LIBRARY__. */ diff --git a/posix/testfnm.c b/posix/testfnm.c index b43f9531fb..5a6c7e12ea 100644 --- a/posix/testfnm.c +++ b/posix/testfnm.c @@ -15,7 +15,38 @@ struct { { "a/b", "[a-z]/[a-z]", 0, 0 }, { "a/b", "*", FNM_FILE_NAME, FNM_NOMATCH }, { "a/b", "*[/]b", FNM_FILE_NAME, FNM_NOMATCH }, - { "a/b", "*[b]", FNM_FILE_NAME, FNM_NOMATCH } + { "a/b", "*[b]", FNM_FILE_NAME, FNM_NOMATCH }, + { "a/b", "[*]/b", 0, FNM_NOMATCH }, + { "*/b", "[*]/b", 0, 0 }, + { "a/b", "[?]/b", 0, FNM_NOMATCH }, + { "?/b", "[?]/b", 0, 0 }, + { "a/b", "[[a]/b", 0, 0 }, + { "[/b", "[[a]/b", 0, 0 }, + { "a/b", "\\*/b", 0, FNM_NOMATCH }, + { "*/b", "\\*/b", 0, 0 }, + { "a/b", "\\?/b", 0, FNM_NOMATCH }, + { "?/b", "\\?/b", 0, 0 }, + { "[/b", "[/b", 0, FNM_NOMATCH }, + { "[/b", "\\[/b", 0, 0 }, + { "aa/b", "??/b", 0, 0 }, + { "aa/b", "???b", 0, 0 }, + { "aa/b", "???b", FNM_PATHNAME, FNM_NOMATCH }, + { ".a/b", "?a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { "a/.b", "a/?b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { ".a/b", "*a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { "a/.b", "a/*b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { ".a/b", "[.]a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { "a/.b", "a/[.]b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { "a/b", "*/?", FNM_PATHNAME|FNM_PERIOD, 0 }, + { "a/b", "?/*", FNM_PATHNAME|FNM_PERIOD, 0 }, + { ".a/b", ".*/?", FNM_PATHNAME|FNM_PERIOD, 0 }, + { "a/.b", "*/.?", FNM_PATHNAME|FNM_PERIOD, 0 }, + { "a/.b", "*/*", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH }, + { "a/.b", "*?*/*", FNM_PERIOD, 0 }, + { "a./b", "*[.]/b", FNM_PATHNAME|FNM_PERIOD, 0 }, + { "a/b", "*[[:alpha:]]/*[[:alnum:]]", FNM_PATHNAME, 0 }, + { "a/b", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, 0 }, + { "a/[", "*[![:digit:]]*/[![:d-d]", FNM_PATHNAME, FNM_NOMATCH }, }; int |