From: Timo Sirainen Date: Thu, 18 Mar 2010 02:11:55 +0000 (+0200) Subject: Added wildcard_match*() for matching strings with '*' and '?' wildcards. X-Git-Tag: 2.0.beta4~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f2528b977128fbac005fc940012eac9e50022c4d;p=thirdparty%2Fdovecot%2Fcore.git Added wildcard_match*() for matching strings with '*' and '?' wildcards. --HG-- branch : HEAD --- diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index ccfbec39c4..28a2ac28f7 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -111,6 +111,7 @@ liblib_la_SOURCES = \ utc-offset.c \ utc-mktime.c \ var-expand.c \ + wildcard-match.c \ write-full.c headers = \ @@ -203,6 +204,7 @@ headers = \ utc-offset.h \ utc-mktime.h \ var-expand.h \ + wildcard-match.h \ write-full.h test_programs = test-lib diff --git a/src/lib/wildcard-match.c b/src/lib/wildcard-match.c new file mode 100644 index 0000000000..99a6fc6e99 --- /dev/null +++ b/src/lib/wildcard-match.c @@ -0,0 +1,103 @@ +/* + * This code would not have been possible without the prior work and + * suggestions of various sourced. Special thanks to Robey for + * all his time/help tracking down bugs and his ever-helpful advice. + * + * 04/09: Fixed the "*\*" against "*a" bug (caused an endless loop) + * + * Chris Fuller (aka Fred1@IRC & Fwitz@IRC) + * crf@cfox.bchs.uh.edu + * + * I hereby release this code into the public domain + * + */ + +#include "lib.h" +#include "wildcard-match.h" + +#include + +#define WILDS '*' /* matches 0 or more characters (including spaces) */ +#define WILDQ '?' /* matches ecactly one character */ + +#define NOMATCH 0 +#define MATCH (match+sofar) + +static int wildcard_match_int(const char *data, const char *mask, int icase) +{ + const char *ma = mask, *na = data, *lsm = 0, *lsn = 0; + int match = 1; + int sofar = 0; + + /* null strings should never match */ + if ((ma == 0) || (na == 0) || (!*ma) || (!*na)) + return NOMATCH; + /* find the end of each string */ + while (*(++mask)); + mask--; + while (*(++data)); + data--; + + while (data >= na) { + /* If the mask runs out of chars before the string, fall back on + * a wildcard or fail. */ + if (mask < ma) { + if (lsm) { + data = --lsn; + mask = lsm; + if (data < na) + lsm = 0; + sofar = 0; + } + else + return NOMATCH; + } + + switch (*mask) { + case WILDS: /* Matches anything */ + do + mask--; /* Zap redundant wilds */ + while ((mask >= ma) && (*mask == WILDS)); + lsm = mask; + lsn = data; + match += sofar; + sofar = 0; /* Update fallback pos */ + if (mask < ma) + return MATCH; + continue; /* Next char, please */ + case WILDQ: + mask--; + data--; + continue; /* '?' always matches */ + } + if (icase ? (i_toupper(*mask) == i_toupper(*data)) : + (*mask == *data)) { /* If matching char */ + mask--; + data--; + sofar++; /* Tally the match */ + continue; /* Next char, please */ + } + if (lsm) { /* To to fallback on '*' */ + data = --lsn; + mask = lsm; + if (data < na) + lsm = 0; /* Rewind to saved pos */ + sofar = 0; + continue; /* Next char, please */ + } + return NOMATCH; /* No fallback=No match */ + } + while ((mask >= ma) && (*mask == WILDS)) + mask--; /* Zap leftover %s & *s */ + return (mask >= ma) ? NOMATCH : MATCH; /* Start of both = match */ +} + +bool wildcard_match(const char *data, const char *mask) +{ + return wildcard_match_int(data, mask, FALSE) != 0; +} + +bool wildcard_match_icase(const char *data, const char *mask) +{ + return wildcard_match_int(data, mask, TRUE) != 0; +} diff --git a/src/lib/wildcard-match.h b/src/lib/wildcard-match.h new file mode 100644 index 0000000000..cda9fd84ce --- /dev/null +++ b/src/lib/wildcard-match.h @@ -0,0 +1,9 @@ +#ifndef WILDCARD_MATCH_H +#define WILDCARD_MATCH_H + +/* Returns TRUE if mask matches data. mask can contain '*' and '?' wildcards. */ +bool wildcard_match(const char *data, const char *mask); +/* Like wildcard_match(), but match ASCII characters case-insensitively. */ +bool wildcard_match_icase(const char *data, const char *mask); + +#endif