summaryrefslogtreecommitdiff
path: root/lib/libc/gen
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2008-10-01 23:04:14 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2008-10-01 23:04:14 +0000
commit3e694e55a5d271b025e26e1fb8815dc686bf0816 (patch)
treeedaad9777f0438233b13846a1e9056dee668b680 /lib/libc/gen
parent681fc59ab964ddcd2f94289c067b44b927a31576 (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.h29
-rw-r--r--lib/libc/gen/fnmatch.c50
-rw-r--r--lib/libc/gen/glob.c78
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);
}