diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2008-10-01 23:04:14 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2008-10-01 23:04:14 +0000 |
commit | 3e694e55a5d271b025e26e1fb8815dc686bf0816 (patch) | |
tree | edaad9777f0438233b13846a1e9056dee668b680 /lib/libc/gen | |
parent | 681fc59ab964ddcd2f94289c067b44b927a31576 (diff) |
POSIX character class support for fnmatch(3) and glob(3). OK deraadt@
Diffstat (limited to 'lib/libc/gen')
-rw-r--r-- | lib/libc/gen/charclass.h | 29 | ||||
-rw-r--r-- | lib/libc/gen/fnmatch.c | 50 | ||||
-rw-r--r-- | lib/libc/gen/glob.c | 78 |
3 files changed, 149 insertions, 8 deletions
diff --git a/lib/libc/gen/charclass.h b/lib/libc/gen/charclass.h new file mode 100644 index 00000000000..5edb2c1144c --- /dev/null +++ b/lib/libc/gen/charclass.h @@ -0,0 +1,29 @@ +/* + * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com> + * + * $OpenBSD: charclass.h,v 1.1 2008/10/01 23:04:13 millert Exp $ + */ + +/* + * POSIX character class support for fnmatch() and glob(). + */ +static struct cclass { + const char *name; + int (*isctype)(int); +} cclasses[] = { + { "alnum", isalnum }, + { "alpha", isalpha }, + { "blank", isblank }, + { "cntrl", iscntrl }, + { "digit", isdigit }, + { "graph", isgraph }, + { "lower", islower }, + { "print", isprint }, + { "punct", ispunct }, + { "space", isspace }, + { "upper", isupper }, + { "xdigit", isxdigit }, + { NULL, NULL } +}; + +#define NCCLASSES (sizeof(cclasses) / sizeof(cclasses[0]) - 1) diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c index 5a282f1e596..2388f826382 100644 --- a/lib/libc/gen/fnmatch.c +++ b/lib/libc/gen/fnmatch.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fnmatch.c,v 1.13 2006/03/31 05:34:14 deraadt Exp $ */ +/* $OpenBSD: fnmatch.c,v 1.14 2008/10/01 23:04:13 millert Exp $ */ /* * Copyright (c) 1989, 1993, 1994 @@ -42,6 +42,8 @@ #include <string.h> #include <fnmatch.h> +#include "charclass.h" + #define EOS '\0' #define RANGE_MATCH 1 @@ -49,6 +51,7 @@ #define RANGE_ERROR (-1) static int rangematch(const char *, char, int, char **); +static int classmatch(const char *, char, int, const char **); int fnmatch(const char *pattern, const char *string, int flags) @@ -153,7 +156,7 @@ fnmatch(const char *pattern, const char *string, int flags) static int rangematch(const char *pattern, char test, int flags, char **newp) { - int negate, ok; + int negate, ok, rv; char c, c2; /* @@ -177,6 +180,17 @@ rangematch(const char *pattern, char test, int flags, char **newp) ok = 0; c = *pattern++; do { + 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 == '\\' && !(flags & FNM_NOESCAPE)) c = *pattern++; if (c == EOS) @@ -203,3 +217,35 @@ rangematch(const char *pattern, char test, int flags, char **newp) *newp = (char *)pattern; return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); } + +static int +classmatch(const char *pattern, char test, int foldcase, const char **ep) +{ + 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((unsigned char)test)) + rval = RANGE_MATCH; + break; + } + } + if (cc->name == NULL) { + /* invalid character class, return EOS */ + *ep = colon + strlen(colon); + rval = RANGE_ERROR; + } + return(rval); +} diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index 67b534f3b2c..59c26629659 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -1,4 +1,4 @@ -/* $OpenBSD: glob.c,v 1.26 2005/11/28 17:50:12 deraadt Exp $ */ +/* $OpenBSD: glob.c,v 1.27 2008/10/01 23:04:13 millert Exp $ */ /* * Copyright (c) 1989, 1993 * The Regents of the University of California. All rights reserved. @@ -69,6 +69,8 @@ #include <string.h> #include <unistd.h> +#include "charclass.h" + #define DOLLAR '$' #define DOT '.' #define EOS '\0' @@ -116,6 +118,7 @@ typedef char Char; #define M_ONE META('?') #define M_RNG META('-') #define M_SET META('[') +#define M_CLASS META(':') #define ismeta(c) (((c)&M_QUOTE) != 0) @@ -123,7 +126,8 @@ static int compare(const void *, const void *); static int g_Ctoc(const Char *, char *, u_int); static int g_lstat(Char *, struct stat *, glob_t *); static DIR *g_opendir(Char *, glob_t *); -static Char *g_strchr(Char *, int); +static Char *g_strchr(const Char *, int); +static int g_strncmp(const Char *, const char *, size_t); static int g_stat(Char *, struct stat *, glob_t *); static int glob0(const Char *, glob_t *); static int glob1(Char *, Char *, glob_t *, size_t *); @@ -200,7 +204,7 @@ globexp1(const Char *pattern, glob_t *pglob) if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) return glob0(pattern, pglob); - while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL) + while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) if (!globexp2(ptr, pattern, pglob, &rv)) return rv; @@ -375,6 +379,47 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) return patbuf; } +static int +g_strncmp(const Char *s1, const char *s2, size_t n) +{ + int rv = 0; + + while (n--) { + rv = *(Char *)s1 - *(const unsigned char *)s2++; + if (rv) + break; + if (*s1++ == '\0') + break; + } + return rv; +} + +static int +g_charclass(const Char **patternp, Char **bufnextp) +{ + const Char *pattern = *patternp + 1; + Char *bufnext = *bufnextp; + const Char *colon; + struct cclass *cc; + size_t len; + + if ((colon = g_strchr(pattern, ':')) == NULL || colon[1] != ']') + return 1; /* not a character class */ + + len = (size_t)(colon - pattern); + for (cc = cclasses; cc->name != NULL; cc++) { + if (!g_strncmp(pattern, cc->name, len) && cc->name[len] == '\0') + break; + } + if (cc->name == NULL) + return -1; /* invalid character class */ + *bufnext++ = M_CLASS; + *bufnext++ = (Char)(cc - &cclasses[0]); + *bufnextp = bufnext; + *patternp += len + 3; + + return 0; +} /* * The main glob() routine: compiles the pattern (optionally processing @@ -403,7 +448,7 @@ glob0(const Char *pattern, glob_t *pglob) if (c == NOT) ++qpatnext; if (*qpatnext == EOS || - g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) { + g_strchr(qpatnext+1, RBRACKET) == NULL) { *bufnext++ = LBRACKET; if (c == NOT) --qpatnext; @@ -414,6 +459,20 @@ glob0(const Char *pattern, glob_t *pglob) *bufnext++ = M_NOT; c = *qpatnext++; do { + if (c == LBRACKET && *qpatnext == ':') { + do { + err = g_charclass(&qpatnext, + &bufnext); + if (err) + break; + c = *qpatnext++; + } while (c == LBRACKET && *qpatnext == ':'); + if (err == -1 && + !(pglob->gl_flags & GLOB_NOCHECK)) + return GLOB_NOMATCH; + if (c == RBRACKET) + break; + } *bufnext++ = CHAR(c); if (*qpatnext == RANGE && (c = qpatnext[1]) != RBRACKET) { @@ -728,6 +787,13 @@ match(Char *name, Char *pat, Char *patend) if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) ++pat; while (((c = *pat++) & M_MASK) != M_END) + if ((c & M_MASK) == M_CLASS) { + int idx = *pat & M_MASK; + if (idx < NCCLASSES && + cclasses[idx].isctype(k)) + ok = 1; + ++pat; + } if ((*pat & M_MASK) == M_RNG) { if (c <= k && k <= pat[1]) ok = 1; @@ -806,11 +872,11 @@ g_stat(Char *fn, struct stat *sb, glob_t *pglob) } static Char * -g_strchr(Char *str, int ch) +g_strchr(const Char *str, int ch) { do { if (*str == ch) - return (str); + return ((Char *)str); } while (*str++); return (NULL); } |