]> granicus.if.org Git - sudo/commitdiff
Add character class support to included glob(3) and fnmatch(3).
authorTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 26 Sep 2008 21:13:29 +0000 (21:13 +0000)
committerTodd C. Miller <Todd.Miller@courtesan.com>
Fri, 26 Sep 2008 21:13:29 +0000 (21:13 +0000)
emul/charclass.h [new file with mode: 0644]
fnmatch.c
glob.c

diff --git a/emul/charclass.h b/emul/charclass.h
new file mode 100644 (file)
index 0000000..13fc18f
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * $Sudo$
+ */
+
+/*
+ * 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)
index 148435808656a16ec21740810f655e478b5d246b..31c89521265c1d1e68667464236dc1621e69853b 100644 (file)
--- a/fnmatch.c
+++ b/fnmatch.c
@@ -49,6 +49,7 @@
 
 #include <compat.h>
 #include "emul/fnmatch.h"
+#include "emul/charclass.h"
 
 #undef EOS
 #define        EOS     '\0'
@@ -61,7 +62,8 @@
 __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 *, char, int, char **));
+static int rangematch __P((const char *, int, int, char **));
+static int classmatch __P((const char *, int, int, const char **));
 
 int
 fnmatch(pattern, string, flags)
@@ -167,16 +169,16 @@ fnmatch(pattern, string, flags)
 
 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;
 
        /*
@@ -190,7 +192,7 @@ rangematch(pattern, test, flags, newp)
                ++pattern;
 
        if (ISSET(flags, FNM_CASEFOLD))
-               test = tolower((unsigned char)test);
+               test = tolower(test);
 
        /*
         * A right bracket shall lose its special meaning and represent
@@ -200,6 +202,17 @@ rangematch(pattern, test, flags, 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 == '\\' && !ISSET(flags, FNM_NOESCAPE))
                        c = *pattern++;
                if (c == EOS)
@@ -226,3 +239,43 @@ rangematch(pattern, test, flags, newp)
        *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);
+}
diff --git a/glob.c b/glob.c
index 6d4f1a2533111537605281a03394661b8d6d0f2a..ef6f67b9dd34c3d416f0d479405f2f0cf828a1de 100644 (file)
--- a/glob.c
+++ b/glob.c
@@ -99,6 +99,7 @@
 
 #include <compat.h>
 #include "emul/glob.h"
+#include "emul/charclass.h"
 
 #define        DOLLAR          '$'
 #define        DOT             '.'
@@ -147,6 +148,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)
 
 
@@ -154,7 +156,8 @@ static int   compare __P((const void *, const void *));
 static int      g_Ctoc __P((const Char *, char *, unsigned int));
 static int      g_lstat __P((Char *, struct stat *, glob_t *));
 static DIR     *g_opendir __P((Char *, glob_t *));
-static Char    *g_strchr __P((Char *, int));
+static Char    *g_strchr __P((const Char *, int));
+static int      g_strncmp __P((const Char *, const char *, size_t));
 static int      g_stat __P((Char *, struct stat *, glob_t *));
 static int      glob0 __P((const Char *, glob_t *));
 static int      glob1 __P((Char *, Char *, glob_t *));
@@ -238,7 +241,7 @@ globexp1(pattern, 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;
 
@@ -415,6 +418,47 @@ globtilde(pattern, patbuf, patbuf_len, 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
@@ -444,7 +488,7 @@ glob0(pattern, 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;
@@ -455,6 +499,20 @@ glob0(pattern, 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) {
@@ -753,6 +811,13 @@ match(name, pat, 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;
@@ -834,12 +899,12 @@ g_stat(fn, sb, pglob)
 
 static Char *
 g_strchr(str, ch)
-       Char *str;
+       const Char *str;
        int ch;
 {
        do {
                if (*str == ch)
-                       return (str);
+                       return ((Char *)str);
        } while (*str++);
        return (NULL);
 }