/* * match.C: Casemapping and matching functions. * * Copyright © 2007 Pippijn van Steenhoven / The Ermyth Team * Rights to this code are as documented in COPYING. * * * Portions of this file were derived from sources bearing the following license: * Rights to this code are documented in doc/pod/license.pod. * Copyright © 2005-2007 Atheme Project (http://www.atheme.org) */ static char const rcsid[] = "$Id: match.C,v 1.6 2007/09/22 14:27:30 pippijn Exp $"; #include "atheme.h" #define BadPtr(x) (!(x) || (*(x) == '\0')) #define MAX_ITERATIONS 512 /* ** Compare if a given string (name) matches the given ** mask (which can contain wild cards: '*' - match any ** number of chars, '?' - match any single character. ** ** return 0, if match ** 1, if no match */ /* ** match() ** Iterative matching function, rather than recursive. ** Written by Douglas A Lewis (dalewis@acsu.buffalo.edu) */ int match (char const * const mask, char const * const name) { const u_char *m = (const u_char *) mask, *n = (const u_char *) name; char const *ma = mask, *na = name; int wild = 0, q = 0, calls = 0; if (!mask || !name) return 1; /* if the mask is "*", it matches everything */ if ((*m == '*') && (*(m + 1) == '\0')) return 0; while (1) { #ifdef MAX_ITERATIONS if (calls++ > MAX_ITERATIONS) break; #endif if (*m == '*') { while (*m == '*') m++; wild = 1; ma = reinterpret_cast (m); na = reinterpret_cast (n); } if (!*m) { if (!*n) return 0; for (m--; (m > (const u_char *) mask) && (*m == '?' || *m == '&' || *m == '#'); m--) ; if ((m > (const u_char *) mask) && (*m == '*') && (m[-1] != '\\')) return 0; if (!wild) return 1; m = (const u_char *) ma; n = (const u_char *) ++na; } else if (!*n) return 1; if ((*m == '\\') && ((m[1] == '*') || (m[1] == '?') || (m[1] == '&') || (m[1] == '#') || (m[1] == '%'))) { m++; q = 1; } else q = 0; if ((ToLower (*m) != ToLower (*n)) && (((*m != '?') && !(*m == '&' && IsAlpha (*n)) && !(*m == '#' && IsDigit (*n)) && !(*m == '%' && IsNon (*n))) || q)) { if (!wild) return 1; m = (const u_char *) ma; n = (const u_char *) ++na; } else { if (*m) m++; if (*n) n++; } } return 1; } /* ** collapse a pattern string into minimal components. ** This particular version is "in place", so that it changes the pattern ** which is to be reduced to a "minimal" size. */ char * collapse (char *pattern) { char *s = pattern, *s1, *t; if (BadPtr (pattern)) return pattern; /* * Collapse all \** into \*, \*[?]+\** into \*[?]+ */ for (; *s; s++) if (*s == '\\') if (!*(s + 1)) break; else s++; else if (*s == '*') { if (*(t = s1 = s + 1) == '*') while (*t == '*') t++; else if (*t == '?') for (t++, s1++; *t == '*' || *t == '?'; t++) if (*t == '?') *s1++ = *t; while ((*s1++ = *t++)) ; } return pattern; } /* * regex_compile() * Compile a regex of `pattern' and return it. */ regex_t * regex_create (char *pattern, int flags) { static char errmsg[BUFSIZE]; int errnum; regex_t *preg; if (pattern == NULL) { return NULL; } preg = new regex_t; errnum = regcomp (preg, pattern, (flags & AREGEX_ICASE ? REG_ICASE : 0) | REG_EXTENDED); if (errnum != 0) { regerror (errnum, preg, errmsg, BUFSIZE); slog (LG_ERROR, "regex_match(): %s\n", errmsg); regfree (preg); delete preg; return NULL; } return preg; } char * regex_extract (char *pattern, char **pend, int *pflags) { char c, *p, *p2; bool backslash = false; c = *pattern; if (isalnum (c) || isspace (c) || c == '\\') return NULL; p = pattern + 1; while (*p != c || backslash) { if (*p == '\0') return NULL; if (backslash || *p == '\\') backslash = !backslash; p++; } p2 = p; p++; *pflags = 0; while (*p != '\0' && *p != ' ') { if (*p == 'i') *pflags |= AREGEX_ICASE; else if (!isalnum (*p)) return NULL; p++; } *pend = p; *p2 = '\0'; return pattern + 1; } /* * regex_match() * Internal wrapper API for POSIX-based regex matching. * `preg' is the regex to check with, `string' needs to be checked against. * Returns `true' on match, `false' else. */ bool regex_match (regex_t * preg, char *string) { bool retval; if (preg == NULL || string == NULL) { slog (LG_ERROR, "regex_match(): we were given NULL string or pattern, bad!"); return false; } /* match it */ if (regexec (preg, string, 0, NULL, 0) == 0) retval = true; else retval = false; return retval; } /* * regex_destroy() * Perform cleanup with regex `preg', free associated memory. */ bool regex_destroy (regex_t * preg) { regfree (preg); delete preg; return true; }