diff options
Diffstat (limited to '')
-rw-r--r-- | src/lib/wildcard-match.c | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/lib/wildcard-match.c b/src/lib/wildcard-match.c new file mode 100644 index 0000000..c1e2b2e --- /dev/null +++ b/src/lib/wildcard-match.c @@ -0,0 +1,105 @@ +/* + * 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 <ctype.h> + +#define WILDS '*' /* matches 0 or more characters (including spaces) */ +#define WILDQ '?' /* matches exactly one character */ + +#define NOMATCH 0 +#define MATCH (match+sofar) + +static int wildcard_match_int(const char *data, const char *mask, bool icase) +{ + const char *ma = mask, *na = data, *lsm = NULL, *lsn = NULL; + int match = 1; + int sofar = 0; + + if (na[0] == '\0') { + /* empty string can match only "*" wildcard(s) */ + while (ma[0] == '*') ma++; + return ma[0] == '\0' ? MATCH : NOMATCH; + } + /* find the end of each string */ + while (*(mask++) != '\0'); + mask-=2; + while (*(data++) != '\0'); + data-=2; + + 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 != NULL) { + data = --lsn; + mask = lsm; + if (data < na) + lsm = NULL; + 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 != NULL) { /* To to fallback on '*' */ + data = --lsn; + mask = lsm; + if (data < na) + lsm = NULL; /* 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; +} |