/*
+ * Copyright (c) 2008 Todd C. Miller <Todd.Miller@courtesan.com>
* Copyright (c) 1989, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* 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.
*
* SUCH DAMAGE.
*/
-#if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
-#endif /* LIBC_SCCS and not lint */
-
/*
* Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
* Compares a filename or pathname to a pattern.
*/
-#include "config.h"
+#include <config.h>
#include <stdio.h>
#include <ctype.h>
# endif
#endif /* HAVE_STRING_H */
-#include "compat.h"
+#include <compat.h>
#include "emul/fnmatch.h"
+#include "emul/charclass.h"
#undef EOS
#define EOS '\0'
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
-static int rangematch __P((const char *, char, int, char **));
+#if defined(LIBC_SCCS) && !defined(lint)
+__unused static const char rcsid[] = "$OpenBSD: fnmatch.c,v 1.6 1998/03/19 00:29:59 millert Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+static int rangematch __P((const char *, int, int, char **));
+static int classmatch __P((const char *, int, int, const char **));
int
fnmatch(pattern, string, flags)
for (stringstart = string;;)
switch (c = *pattern++) {
case EOS:
- if ((flags & FNM_LEADING_DIR) && *string == '/')
+ if (ISSET(flags, FNM_LEADING_DIR) && *string == '/')
return (0);
return (*string == EOS ? 0 : FNM_NOMATCH);
case '?':
if (*string == EOS)
return (FNM_NOMATCH);
- if (*string == '/' && (flags & FNM_PATHNAME))
+ if (*string == '/' && ISSET(flags, FNM_PATHNAME))
return (FNM_NOMATCH);
- if (*string == '.' && (flags & FNM_PERIOD) &&
+ if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
(string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
++string;
break;
while (c == '*')
c = *++pattern;
- if (*string == '.' && (flags & FNM_PERIOD) &&
+ if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
(string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
/* Optimize for pattern with * at end or before /. */
if (c == EOS) {
- if (flags & FNM_PATHNAME)
- return ((flags & FNM_LEADING_DIR) ||
+ if (ISSET(flags, FNM_PATHNAME))
+ return (ISSET(flags, FNM_LEADING_DIR) ||
strchr(string, '/') == NULL ?
0 : FNM_NOMATCH);
else
return (0);
- } else if (c == '/' && (flags & FNM_PATHNAME)) {
+ } else if (c == '/' && ISSET(flags, FNM_PATHNAME)) {
if ((string = strchr(string, '/')) == NULL)
return (FNM_NOMATCH);
break;
while ((test = *string) != EOS) {
if (!fnmatch(pattern, string, flags & ~FNM_PERIOD))
return (0);
- if (test == '/' && (flags & FNM_PATHNAME))
+ if (test == '/' && ISSET(flags, FNM_PATHNAME))
break;
++string;
}
case '[':
if (*string == EOS)
return (FNM_NOMATCH);
- if (*string == '/' && (flags & FNM_PATHNAME))
+ if (*string == '/' && ISSET(flags, FNM_PATHNAME))
return (FNM_NOMATCH);
- if (*string == '.' && (flags & FNM_PERIOD) &&
+ if (*string == '.' && ISSET(flags, FNM_PERIOD) &&
(string == stringstart ||
- ((flags & FNM_PATHNAME) && *(string - 1) == '/')))
+ (ISSET(flags, FNM_PATHNAME) && *(string - 1) == '/')))
return (FNM_NOMATCH);
switch (rangematch(pattern, *string, flags, &newp)) {
++string;
break;
case '\\':
- if (!(flags & FNM_NOESCAPE)) {
+ if (!ISSET(flags, FNM_NOESCAPE)) {
if ((c = *pattern++) == EOS) {
c = '\\';
--pattern;
/* FALLTHROUGH */
default:
normal:
- if (c != *string && !((flags & FNM_CASEFOLD) &&
+ if (c != *string && !(ISSET(flags, FNM_CASEFOLD) &&
(tolower((unsigned char)c) ==
tolower((unsigned char)*string))))
return (FNM_NOMATCH);
static int
#ifdef __STDC__
-rangematch(const char *pattern, char test, int flags, char **newp)
+rangematch(const char *pattern, int test, int flags, char **newp)
#else
rangematch(pattern, test, flags, newp)
const char *pattern;
- char test;
+ int test;
int flags;
char **newp;
#endif
{
- int negate, ok;
+ int negate, ok, rv;
char c, c2;
/*
if ((negate = (*pattern == '!' || *pattern == '^')))
++pattern;
- if (flags & FNM_CASEFOLD)
- test = tolower((unsigned char)test);
+ if (ISSET(flags, FNM_CASEFOLD))
+ test = tolower(test);
/*
* A right bracket shall lose its special meaning and represent
ok = 0;
c = *pattern++;
do {
- if (c == '\\' && !(flags & FNM_NOESCAPE))
+ if (c == '[' && *pattern == ':') {
+ do {
+ rv = classmatch(pattern + 1, test,
+ (flags & FNM_CASEFOLD), &pattern);
+ if (rv == RANGE_MATCH)
+ ok = 1;
+ c = *pattern++;
+ } while (rv != RANGE_ERROR && c == '[' && *pattern == ':');
+ if (c == ']')
+ break;
+ }
+ if (c == '\\' && !ISSET(flags, FNM_NOESCAPE))
c = *pattern++;
if (c == EOS)
return (RANGE_ERROR);
- if (c == '/' && (flags & FNM_PATHNAME))
+ if (c == '/' && ISSET(flags, FNM_PATHNAME))
return (RANGE_NOMATCH);
- if ((flags & FNM_CASEFOLD))
+ if (ISSET(flags, FNM_CASEFOLD))
c = tolower((unsigned char)c);
if (*pattern == '-'
&& (c2 = *(pattern+1)) != EOS && c2 != ']') {
pattern += 2;
- if (c2 == '\\' && !(flags & FNM_NOESCAPE))
+ if (c2 == '\\' && !ISSET(flags, FNM_NOESCAPE))
c2 = *pattern++;
if (c2 == EOS)
return (RANGE_ERROR);
- if (flags & FNM_CASEFOLD)
+ if (ISSET(flags, FNM_CASEFOLD))
c2 = tolower((unsigned char)c2);
if (c <= test && test <= c2)
ok = 1;
*newp = (char *)pattern;
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
}
+
+static int
+#ifdef __STDC__
+classmatch(const char *pattern, int test, int foldcase, const char **ep)
+#else
+classmatch(pattern, test, foldcase, ep)
+ const char *pattern;
+ int test;
+ int foldcase;
+ const char **ep;
+#endif
+{
+ struct cclass *cc;
+ const char *colon;
+ size_t len;
+ int rval = RANGE_NOMATCH;
+
+ if ((colon = strchr(pattern, ':')) == NULL || colon[1] != ']') {
+ *ep = pattern - 2;
+ return(RANGE_ERROR);
+ }
+ *ep = colon + 2;
+ len = (size_t)(colon - pattern);
+
+ if (foldcase && strncmp(pattern, "upper:]", 7) == 0)
+ pattern = "lower:]";
+ for (cc = cclasses; cc->name != NULL; cc++) {
+ if (!strncmp(pattern, cc->name, len) && cc->name[len] == '\0') {
+ if (cc->isctype(test))
+ rval = RANGE_MATCH;
+ break;
+ }
+ }
+ if (cc->name == NULL) {
+ /* invalid character class, return EOS */
+ *ep = colon + strlen(colon);
+ rval = RANGE_ERROR;
+ }
+ return(rval);
+}