update fnmatch to POSIX 2008 semantics

an invalid bracket expression must be treated as if the opening
bracket were just a literal character. this is to fix a bug whereby
POSIX left the behavior of the "[" shell command undefined due to it
being an invalid bracket expression.
This commit is contained in:
Rich Felker 2012-04-26 12:24:44 -04:00
parent 0bd7ac05d1
commit 2b87a5db82

View File

@ -53,6 +53,7 @@ int fnmatch(const char *p, const char *s, int flags)
int first; int first;
int no_slash = (flags & FNM_PATHNAME) ? '/' : 0; int no_slash = (flags & FNM_PATHNAME) ? '/' : 0;
int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100; int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100;
const char *p1;
flags |= __FNM_CONT; flags |= __FNM_CONT;
@ -84,6 +85,7 @@ int fnmatch(const char *p, const char *s, int flags)
break; break;
return FNM_NOMATCH; return FNM_NOMATCH;
case '[': case '[':
p1 = p-1;
not = (*p == '!' || *p == '^'); not = (*p == '!' || *p == '^');
if (not) p++; if (not) p++;
k = next(&s); k = next(&s);
@ -92,7 +94,7 @@ int fnmatch(const char *p, const char *s, int flags)
match = 0; match = 0;
first = 1; first = 1;
for (;;) { for (;;) {
if (!*p) return FNM_NOMATCH; if (!*p) goto literal_bracket;
if (*p == ']' && !first) break; if (*p == ']' && !first) break;
first = 0; first = 0;
if (*p == '[' && *(p+1) == ':') { if (*p == '[' && *(p+1) == ':') {
@ -112,15 +114,20 @@ int fnmatch(const char *p, const char *s, int flags)
continue; continue;
} }
c = bracket_next(&p); c = bracket_next(&p);
if (c == BRACKET_ERROR) if (c == BRACKET_ERROR) {
return FNM_NOMATCH; literal_bracket:
match = (k=='[');
p = p1;
not = 0;
break;
}
if (c == BRACKET_NOCHAR) if (c == BRACKET_NOCHAR)
continue; continue;
if (*p == '-' && *(p+1) != ']') { if (*p == '-' && *(p+1) != ']') {
p++; p++;
d = bracket_next(&p); d = bracket_next(&p);
if (d == BRACKET_ERROR) if (d == BRACKET_ERROR)
return FNM_NOMATCH; goto literal_bracket;
if (d == BRACKET_NOCHAR) if (d == BRACKET_NOCHAR)
continue; continue;
if (k >= c && k <= d) if (k >= c && k <= d)