summaryrefslogtreecommitdiffstats
path: root/src/lib/wildcard-match.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/wildcard-match.c')
-rw-r--r--src/lib/wildcard-match.c105
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;
+}