| version 1.2, 1993/04/10 00:25:35 |
version 1.3, 1993/06/16 17:16:13 |
|
|
| */ |
*/ |
| |
|
| #if defined(LIBC_SCCS) && !defined(lint) |
#if defined(LIBC_SCCS) && !defined(lint) |
| static char sccsid[] = "@(#)fnmatch.c 5.4 (Berkeley) 2/23/91"; |
static char sccsid[] = "@(#)fnmatch.c 5.6 (Berkeley) 6/28/92"; |
| #endif /* LIBC_SCCS and not lint */ |
#endif /* LIBC_SCCS and not lint */ |
| |
|
| /* |
/* |
| * Function fnmatch() as proposed in Posix 1003.2 B.6 (rev. 9). |
* Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2). |
| * Compares a filename or pathname to a pattern. |
* Compares a filename or pathname to a pattern. |
| */ |
*/ |
| |
|
| #include <unistd.h> |
#include <fnmatch.h> |
| #include <string.h> |
#include <string.h> |
| |
|
| #define EOS '\0' |
#define EOS '\0' |
| |
|
| static char * |
static const char *rangematch __P((const char *, int)); |
| rangematch(pattern, test) |
|
| register char *pattern, test; |
|
| { |
|
| register char c, c2; |
|
| int negate, ok; |
|
| |
|
| if (negate = (*pattern == '!')) |
|
| ++pattern; |
|
| |
|
| /* |
|
| * TO DO: quoting |
|
| */ |
|
| |
|
| for (ok = 0; (c = *pattern++) != ']';) { |
|
| if (c == EOS) |
|
| return(NULL); /* illegal pattern */ |
|
| if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { |
|
| if (c <= test && test <= c2) |
|
| ok = 1; |
|
| pattern += 2; |
|
| } |
|
| else if (c == test) |
|
| ok = 1; |
|
| } |
|
| return(ok == negate ? NULL : pattern); |
|
| } |
|
| |
|
| fnmatch(pattern, string, flags) |
fnmatch(pattern, string, flags) |
| register const char *pattern; |
register const char *pattern, *string; |
| register const char *string; |
|
| int flags; |
int flags; |
| { |
{ |
| register char c; |
register char c; |
| char test, *rangematch(); |
char test; |
| |
|
| for (;;) |
for (;;) |
| switch (c = *pattern++) { |
switch (c = *pattern++) { |
| case EOS: |
case EOS: |
| return(!(*string == EOS)); |
return (*string == EOS ? 0 : FNM_NOMATCH); |
| case '?': |
case '?': |
| if (((test = *string++) == EOS) || |
if ((test = *string++) == EOS || |
| ((test == '/') && (flags & FNM_PATHNAME))) |
test == '/' && flags & FNM_PATHNAME) |
| return(1); |
return (FNM_NOMATCH); |
| break; |
break; |
| case '*': |
case '*': |
| c = *pattern; |
c = *pattern; |
| /* collapse multiple stars */ |
/* Collapse multiple stars. */ |
| while (c == '*') |
while (c == '*') |
| c = *++pattern; |
c = *++pattern; |
| |
|
| /* 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(index(string, '/') != NULL); |
return (index(string, '/') == NULL ? |
| |
0 : FNM_NOMATCH); |
| else |
else |
| return(0); |
return (0); |
| else if ((c == '/') && (flags & FNM_PATHNAME)) { |
else if (c == '/' && flags & FNM_PATHNAME) { |
| if ((string = index(string, '/')) == NULL) |
if ((string = index(string, '/')) == NULL) |
| return(1); |
return (FNM_NOMATCH); |
| break; |
break; |
| } |
} |
| |
|
| /* general case, use recursion */ |
/* General case, use recursion. */ |
| while ((test = *string) != EOS) { |
while ((test = *string) != EOS) { |
| if (!fnmatch(pattern, string, flags)) |
if (!fnmatch(pattern, string, flags)) |
| return(0); |
return (0); |
| if (test == '/' && flags & FNM_PATHNAME) |
if (test == '/' && flags & FNM_PATHNAME) |
| break; |
break; |
| ++string; |
++string; |
| } |
} |
| return(1); |
return (FNM_NOMATCH); |
| case '[': |
case '[': |
| if ((test = *string++) == EOS || |
if ((test = *string++) == EOS || |
| test == '/' && flags & FNM_PATHNAME) |
test == '/' && flags & FNM_PATHNAME) |
| return(1); |
return (FNM_NOMATCH); |
| if ((pattern = rangematch(pattern, test)) == NULL) |
if ((pattern = rangematch(pattern, test)) == NULL) |
| return(1); |
return (FNM_NOMATCH); |
| break; |
break; |
| case '\\': |
case '\\': |
| if (flags & FNM_QUOTE) { |
if (!(flags & FNM_NOESCAPE)) { |
| if ((c = *pattern++) == EOS) { |
if ((c = *pattern++) == EOS) { |
| c = '\\'; |
c = '\\'; |
| --pattern; |
--pattern; |
| } |
} |
| if (c != *string++) |
if (c != *string++) |
| return(1); |
return (FNM_NOMATCH); |
| break; |
break; |
| } |
} |
| /* FALLTHROUGH */ |
/* FALLTHROUGH */ |
| default: |
default: |
| if (c != *string++) |
if (c != *string++) |
| return(1); |
return (FNM_NOMATCH); |
| break; |
break; |
| } |
} |
| |
/* NOTREACHED */ |
| |
} |
| |
|
| |
static const char * |
| |
rangematch(pattern, test) |
| |
register const char *pattern; |
| |
register int test; |
| |
{ |
| |
register char c, c2; |
| |
int negate, ok; |
| |
|
| |
if (negate = (*pattern == '!')) |
| |
++pattern; |
| |
|
| |
/* |
| |
* XXX |
| |
* TO DO: quoting |
| |
*/ |
| |
for (ok = 0; (c = *pattern++) != ']';) { |
| |
if (c == EOS) |
| |
return (NULL); /* Illegal pattern. */ |
| |
if (*pattern == '-' && (c2 = pattern[1]) != EOS && c2 != ']') { |
| |
if (c <= test && test <= c2) |
| |
ok = 1; |
| |
pattern += 2; |
| |
} |
| |
else if (c == test) |
| |
ok = 1; |
| |
} |
| |
return (ok == negate ? NULL : pattern); |
| } |
} |