From 0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sat, 12 Feb 2011 00:22:29 -0500 Subject: initial check-in, version 0.5.0 --- src/regex/fnmatch.c | 150 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 src/regex/fnmatch.c (limited to 'src/regex/fnmatch.c') diff --git a/src/regex/fnmatch.c b/src/regex/fnmatch.c new file mode 100644 index 00000000..5f2fccdb --- /dev/null +++ b/src/regex/fnmatch.c @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include + +static int next(const char **s) +{ + wchar_t c; + int l = mbtowc(&c, *s, MB_LEN_MAX); + /* hack to allow literal matches of invalid byte sequences */ + if (l < 0) return (unsigned char)*(*s)++ - 0x100; + *s += l; + return c; +} + +#define BRACKET_ERROR -0x100 +#define BRACKET_NOCHAR -0x101 + +static int bracket_next(const char **s) +{ + int c; + int type; + if (**s == '[') { + type = *(*s+1); + if (type == '.' || type == '=') { + *s += 2; + c = next(s); + if (c <= 0) return BRACKET_ERROR; + if (**s == type && *(*s+1) == ']') { + *s += 2; + return c; + } + for (; **s && (**s != type || *(*s+1) != ']'); (*s)++); + if (!**s) return BRACKET_ERROR; + *s += 2; + return BRACKET_NOCHAR; + } + } + c = next(s); + if (c <= 0) return BRACKET_ERROR; + return c; +} + +#define __FNM_CONT 0x8000 + +int fnmatch(const char *p, const char *s, int flags) +{ + int c, d, k; + int not; + int match; + int first; + int no_slash = (flags & FNM_PATHNAME) ? '/' : 0; + int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100; + + flags |= __FNM_CONT; + + while ((c = *p++)) { + switch (c) { + case '?': + k = next(&s); + if (!k || k == no_period || k == no_slash) + return FNM_NOMATCH; + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + c = *p++; + goto literal; + } + if (*s++ != c) return FNM_NOMATCH; + break; + case '*': + for (; *p == '*'; p++); + if (*p && !*s) return FNM_NOMATCH; + if (*s == no_period) + return FNM_NOMATCH; + if (!*p && (!no_slash || !strchr(s, no_slash))) + return 0; + for (; *s; s++) + if (!fnmatch(p, s, flags)) + return 0; + else if (*s == no_slash) + break; + return FNM_NOMATCH; + case '[': + not = (*p == '!' || *p == '^'); + if (not) p++; + k = next(&s); + if (!k || k == no_slash || k == no_period) + return FNM_NOMATCH; + match = 0; + first = 1; + for (;;) { + if (!*p) return FNM_NOMATCH; + if (*p == ']' && !first) break; + first = 0; + if (*p == '[' && *(p+1) == ':') { + const char *z; + p += 2; + for (z=p; *z && (*z != ':' || *(z+1) != ']'); z++); + if (!*z || z-p > 32) { /* FIXME: symbolic const? */ + return FNM_NOMATCH; + } else { + char class[z-p+1]; + memcpy(class, p, z-p); + class[z-p] = 0; + if (iswctype(k, wctype(class))) + match = 1; + } + p = z+2; + continue; + } + c = bracket_next(&p); + if (c == BRACKET_ERROR) + return FNM_NOMATCH; + if (c == BRACKET_NOCHAR) + continue; + if (*p == '-' && *(p+1) != ']') { + p++; + d = bracket_next(&p); + if (d == BRACKET_ERROR) + return FNM_NOMATCH; + if (d == BRACKET_NOCHAR) + continue; + if (k >= c && k <= d) + match = 1; + continue; + } + if (k == c) match = 1; + } + p++; + if (not == match) + return FNM_NOMATCH; + break; + default: + literal: + if (*s++ != c) + return FNM_NOMATCH; + if (c == no_slash && (flags & FNM_PERIOD)) { + no_period = '.'; + continue; + } + break; + } + no_period = 0x100; + } + if (*s) return FNM_NOMATCH; + return 0; +} -- cgit v1.2.1