Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libc/gen/fnmatch.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/libc/gen/fnmatch.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.6 retrieving revision 1.21.40.1 diff -u -p -r1.6 -r1.21.40.1 --- src/lib/libc/gen/fnmatch.c 1993/11/06 00:52:40 1.6 +++ src/lib/libc/gen/fnmatch.c 2011/02/08 16:18:59 1.21.40.1 @@ -1,5 +1,7 @@ +/* $NetBSD: fnmatch.c,v 1.21.40.1 2011/02/08 16:18:59 bouyer Exp $ */ + /* - * Copyright (c) 1989, 1993 + * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by @@ -13,11 +15,7 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors + * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * @@ -34,118 +32,182 @@ * SUCH DAMAGE. */ +#include #if defined(LIBC_SCCS) && !defined(lint) -/* from: static char sccsid[] = "@(#)fnmatch.c 8.1 (Berkeley) 6/4/93"; */ -static char *rcsid = "$Id: fnmatch.c,v 1.6 1993/11/06 00:52:40 cgd Exp $"; +#if 0 +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; +#else +__RCSID("$NetBSD: fnmatch.c,v 1.21.40.1 2011/02/08 16:18:59 bouyer Exp $"); +#endif #endif /* LIBC_SCCS and not lint */ /* - * Function fnmatch() as proposed in POSIX 1003.2 B.6 (D11.2). + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. * Compares a filename or pathname to a pattern. */ +#include "namespace.h" + +#include +#include #include #include +#ifdef __weak_alias +__weak_alias(fnmatch,_fnmatch) +#endif + #define EOS '\0' -static const char *rangematch __P((const char *, int)); +static inline int +foldcase(int ch, int flags) +{ + + if ((flags & FNM_CASEFOLD) != 0 && isupper(ch)) + return tolower(ch); + return ch; +} + +#define FOLDCASE(ch, flags) foldcase((unsigned char)(ch), (flags)) -fnmatch(pattern, string, flags) - register const char *pattern, *string; - int flags; +static const char * +rangematch(const char *pattern, int test, int flags) { - register char c; - char test; + int negate, ok; + char c, c2; - for (;;) - switch (c = *pattern++) { + _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; + char c, test; + + _DIAGASSERT(pattern != NULL); + _DIAGASSERT(string != NULL); + + if (recursion-- == 0) + return FNM_NORES; + + for (stringstart = string;;) { + switch (c = FOLDCASE(*pattern++, flags)) { case EOS: - return (*string == EOS ? 0 : FNM_NOMATCH); + if ((flags & FNM_LEADING_DIR) && *string == '/') + return 0; + return *string == EOS ? 0 : FNM_NOMATCH; case '?': - if ((test = *string++) == EOS || - test == '/' && flags & FNM_PATHNAME) - return (FNM_NOMATCH); + if (*string == EOS) + return FNM_NOMATCH; + if (*string == '/' && (flags & FNM_PATHNAME)) + return FNM_NOMATCH; + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return FNM_NOMATCH; + ++string; break; case '*': - c = *pattern; + c = FOLDCASE(*pattern, flags); /* Collapse multiple stars. */ while (c == '*') - c = *++pattern; + c = FOLDCASE(*++pattern, flags); + + if (*string == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + return FNM_NOMATCH; /* Optimize for pattern with * at end or before /. */ - if (c == EOS) + if (c == EOS) { if (flags & FNM_PATHNAME) - return (index(string, '/') == NULL ? - 0 : FNM_NOMATCH); + return (flags & FNM_LEADING_DIR) || + strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH; else - return (0); - else if (c == '/' && flags & FNM_PATHNAME) { - if ((string = index(string, '/')) == NULL) - return (FNM_NOMATCH); + return 0; + } else if (c == '/' && flags & FNM_PATHNAME) { + if ((string = strchr(string, '/')) == NULL) + return FNM_NOMATCH; break; } /* General case, use recursion. */ - while ((test = *string) != EOS) { - if (!fnmatch(pattern, string, flags)) - return (0); + while ((test = FOLDCASE(*string, flags)) != EOS) { + int e; + switch ((e = fnmatchx(pattern, string, + flags & ~FNM_PERIOD, recursion))) { + case FNM_NOMATCH: + break; + default: + return e; + } if (test == '/' && flags & FNM_PATHNAME) break; ++string; } - return (FNM_NOMATCH); + return FNM_NOMATCH; case '[': - if ((test = *string++) == EOS || - test == '/' && flags & FNM_PATHNAME) - return (FNM_NOMATCH); - if ((pattern = rangematch(pattern, test)) == NULL) - return (FNM_NOMATCH); + if (*string == EOS) + return FNM_NOMATCH; + if (*string == '/' && flags & FNM_PATHNAME) + return FNM_NOMATCH; + if ((pattern = rangematch(pattern, + FOLDCASE(*string, flags), flags)) == NULL) + return FNM_NOMATCH; + ++string; break; case '\\': if (!(flags & FNM_NOESCAPE)) { - if ((c = *pattern++) == EOS) { + if ((c = FOLDCASE(*pattern++, flags)) == EOS) { c = '\\'; --pattern; } - if (c != *string++) - return (FNM_NOMATCH); - break; } /* FALLTHROUGH */ default: - if (c != *string++) - return (FNM_NOMATCH); + if (c != FOLDCASE(*string++, flags)) + return FNM_NOMATCH; break; } + } /* NOTREACHED */ } -static const char * -rangematch(pattern, test) - register const char *pattern; - register int test; +int +fnmatch(const char *pattern, const char *string, int flags) { - 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); + return fnmatchx(pattern, string, flags, 64); }