| version 1.21, 2005/12/24 21:11:16 |
version 1.21.40.1, 2011/02/08 16:18:59 |
| Line 59 __weak_alias(fnmatch,_fnmatch) |
|
| Line 59 __weak_alias(fnmatch,_fnmatch) |
|
| |
|
| #define EOS '\0' |
#define EOS '\0' |
| |
|
| static const char *rangematch __P((const char *, int, int)); |
|
| |
|
| static inline int |
static inline int |
| foldcase(int ch, int flags) |
foldcase(int ch, int flags) |
| { |
{ |
| |
|
| if ((flags & FNM_CASEFOLD) != 0 && isupper(ch)) |
if ((flags & FNM_CASEFOLD) != 0 && isupper(ch)) |
| return (tolower(ch)); |
return tolower(ch); |
| return (ch); |
return ch; |
| } |
} |
| |
|
| #define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags)) |
#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags)) |
| |
|
| int |
static const char * |
| fnmatch(pattern, string, flags) |
rangematch(const char *pattern, int test, int flags) |
| const char *pattern, *string; |
{ |
| int flags; |
int negate, ok; |
| |
char c, c2; |
| |
|
| |
_DIAGASSERT(pattern != NULL); |
| |
|
| |
/* |
| |
* A bracket expression starting with an unquoted circumflex |
| |
* character produces unspecified results (IEEE 1003.2-1992, |
| |
* 3.13.2). This implementation treats it like '!', for |
| |
* consistency with the regular expression syntax. |
| |
* J.T. Conklin (conklin@ngai.kaleida.com) |
| |
*/ |
| |
if ((negate = (*pattern == '!' || *pattern == '^')) != 0) |
| |
++pattern; |
| |
|
| |
for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) { |
| |
if (c == '\\' && !(flags & FNM_NOESCAPE)) |
| |
c = FOLDCASE(*pattern++, flags); |
| |
if (c == EOS) |
| |
return NULL; |
| |
if (*pattern == '-' |
| |
&& (c2 = FOLDCASE(*(pattern + 1), flags)) != EOS && |
| |
c2 != ']') { |
| |
pattern += 2; |
| |
if (c2 == '\\' && !(flags & FNM_NOESCAPE)) |
| |
c2 = FOLDCASE(*pattern++, flags); |
| |
if (c2 == EOS) |
| |
return NULL; |
| |
if (c <= test && test <= c2) |
| |
ok = 1; |
| |
} else if (c == test) |
| |
ok = 1; |
| |
} |
| |
return ok == negate ? NULL : pattern; |
| |
} |
| |
|
| |
|
| |
static int |
| |
fnmatchx(const char *pattern, const char *string, int flags, size_t recursion) |
| { |
{ |
| const char *stringstart; |
const char *stringstart; |
| char c, test; |
char c, test; |
| Line 83 fnmatch(pattern, string, flags) |
|
| Line 119 fnmatch(pattern, string, flags) |
|
| _DIAGASSERT(pattern != NULL); |
_DIAGASSERT(pattern != NULL); |
| _DIAGASSERT(string != NULL); |
_DIAGASSERT(string != NULL); |
| |
|
| for (stringstart = string;;) |
if (recursion-- == 0) |
| |
return FNM_NORES; |
| |
|
| |
for (stringstart = string;;) { |
| switch (c = FOLDCASE(*pattern++, flags)) { |
switch (c = FOLDCASE(*pattern++, flags)) { |
| case EOS: |
case EOS: |
| if ((flags & FNM_LEADING_DIR) && *string == '/') |
if ((flags & FNM_LEADING_DIR) && *string == '/') |
| return (0); |
return 0; |
| return (*string == EOS ? 0 : FNM_NOMATCH); |
return *string == EOS ? 0 : FNM_NOMATCH; |
| case '?': |
case '?': |
| if (*string == EOS) |
if (*string == EOS) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| if (*string == '/' && (flags & FNM_PATHNAME)) |
if (*string == '/' && (flags & FNM_PATHNAME)) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| if (*string == '.' && (flags & FNM_PERIOD) && |
if (*string == '.' && (flags & FNM_PERIOD) && |
| (string == stringstart || |
(string == stringstart || |
| ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| ++string; |
++string; |
| break; |
break; |
| case '*': |
case '*': |
| Line 109 fnmatch(pattern, string, flags) |
|
| Line 148 fnmatch(pattern, string, flags) |
|
| if (*string == '.' && (flags & FNM_PERIOD) && |
if (*string == '.' && (flags & FNM_PERIOD) && |
| (string == stringstart || |
(string == stringstart || |
| ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
((flags & FNM_PATHNAME) && *(string - 1) == '/'))) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| |
|
| /* Optimize for pattern with * at end or before /. */ |
/* Optimize for pattern with * at end or before /. */ |
| if (c == EOS) { |
if (c == EOS) { |
| if (flags & FNM_PATHNAME) |
if (flags & FNM_PATHNAME) |
| return ((flags & FNM_LEADING_DIR) || |
return (flags & FNM_LEADING_DIR) || |
| strchr(string, '/') == NULL ? |
strchr(string, '/') == NULL ? |
| 0 : FNM_NOMATCH); |
0 : FNM_NOMATCH; |
| else |
else |
| return (0); |
return 0; |
| } else if (c == '/' && flags & FNM_PATHNAME) { |
} else if (c == '/' && flags & FNM_PATHNAME) { |
| if ((string = strchr(string, '/')) == NULL) |
if ((string = strchr(string, '/')) == NULL) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| break; |
break; |
| } |
} |
| |
|
| /* General case, use recursion. */ |
/* General case, use recursion. */ |
| while ((test = FOLDCASE(*string, flags)) != EOS) { |
while ((test = FOLDCASE(*string, flags)) != EOS) { |
| if (!fnmatch(pattern, string, |
int e; |
| flags & ~FNM_PERIOD)) |
switch ((e = fnmatchx(pattern, string, |
| return (0); |
flags & ~FNM_PERIOD, recursion))) { |
| |
case FNM_NOMATCH: |
| |
break; |
| |
default: |
| |
return e; |
| |
} |
| if (test == '/' && flags & FNM_PATHNAME) |
if (test == '/' && flags & FNM_PATHNAME) |
| break; |
break; |
| ++string; |
++string; |
| } |
} |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| case '[': |
case '[': |
| if (*string == EOS) |
if (*string == EOS) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| if (*string == '/' && flags & FNM_PATHNAME) |
if (*string == '/' && flags & FNM_PATHNAME) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| if ((pattern = |
if ((pattern = rangematch(pattern, |
| rangematch(pattern, FOLDCASE(*string, flags), |
FOLDCASE(*string, flags), flags)) == NULL) |
| flags)) == NULL) |
return FNM_NOMATCH; |
| return (FNM_NOMATCH); |
|
| ++string; |
++string; |
| break; |
break; |
| case '\\': |
case '\\': |
| Line 156 fnmatch(pattern, string, flags) |
|
| Line 199 fnmatch(pattern, string, flags) |
|
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
| default: |
default: |
| if (c != FOLDCASE(*string++, flags)) |
if (c != FOLDCASE(*string++, flags)) |
| return (FNM_NOMATCH); |
return FNM_NOMATCH; |
| break; |
break; |
| } |
} |
| |
} |
| /* NOTREACHED */ |
/* NOTREACHED */ |
| } |
} |
| |
|
| static const char * |
int |
| rangematch(pattern, test, flags) |
fnmatch(const char *pattern, const char *string, int flags) |
| const char *pattern; |
|
| int test, flags; |
|
| { |
{ |
| int negate, ok; |
return fnmatchx(pattern, string, flags, 64); |
| char c, c2; |
|
| |
|
| _DIAGASSERT(pattern != NULL); |
|
| |
|
| /* |
|
| * A bracket expression starting with an unquoted circumflex |
|
| * character produces unspecified results (IEEE 1003.2-1992, |
|
| * 3.13.2). This implementation treats it like '!', for |
|
| * consistency with the regular expression syntax. |
|
| * J.T. Conklin (conklin@ngai.kaleida.com) |
|
| */ |
|
| if ((negate = (*pattern == '!' || *pattern == '^')) != 0) |
|
| ++pattern; |
|
| |
|
| for (ok = 0; (c = FOLDCASE(*pattern++, flags)) != ']';) { |
|
| if (c == '\\' && !(flags & FNM_NOESCAPE)) |
|
| c = FOLDCASE(*pattern++, flags); |
|
| if (c == EOS) |
|
| return (NULL); |
|
| if (*pattern == '-' |
|
| && (c2 = FOLDCASE(*(pattern+1), flags)) != EOS && |
|
| c2 != ']') { |
|
| pattern += 2; |
|
| if (c2 == '\\' && !(flags & FNM_NOESCAPE)) |
|
| c2 = FOLDCASE(*pattern++, flags); |
|
| if (c2 == EOS) |
|
| return (NULL); |
|
| if (c <= test && test <= c2) |
|
| ok = 1; |
|
| } else if (c == test) |
|
| ok = 1; |
|
| } |
|
| return (ok == negate ? NULL : pattern); |
|
| } |
} |