summaryrefslogtreecommitdiff
path: root/match.c
diff options
context:
space:
mode:
authorByron Rakitzis <byron@archone.tamu.edu>1992-05-27 00:00:01 +0100
committerToby Goodwin <toby@paccrat.org>2015-05-16 21:22:04 +0100
commit6bb38f6a01dbf4bbd584e038ceace0a00faa27bb (patch)
tree589705b2492ce4681760846d9ca45600f0af298d /match.c
release: rc-1.4
Diffstat (limited to 'match.c')
-rw-r--r--match.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/match.c b/match.c
new file mode 100644
index 0000000..6f87614
--- /dev/null
+++ b/match.c
@@ -0,0 +1,99 @@
+/* match.c: pattern matching routines */
+
+#include "rc.h"
+
+static int rangematch(char *, char);
+
+enum { RANGE_FAIL = -1, RANGE_ERROR = -2 };
+
+/* match() matches a single pattern against a single string. */
+
+extern bool match(char *p, char *m, char *s) {
+ int i, j;
+ if (m == NULL)
+ return streq(p, s);
+ i = 0;
+ while (1) {
+ if (p[i] == '\0')
+ return *s == '\0';
+ else if (m[i]) {
+ switch (p[i++]) {
+ case '?':
+ if (*s++ == '\0')
+ return FALSE;
+ break;
+ case '*':
+ while (p[i] == '*' && m[i] == 1) /* collapse multiple stars */
+ i++;
+ if (p[i] == '\0') /* star at end of pattern? */
+ return TRUE;
+ while (*s != '\0')
+ if (match(p + i, m + i, s++))
+ return TRUE;
+ return FALSE;
+ case '[':
+ if (*s == '\0')
+ return FALSE;
+ switch (j = rangematch(p + i, *s)) {
+ default:
+ i += j;
+ break;
+ case RANGE_FAIL:
+ return FALSE;
+ case RANGE_ERROR:
+ if (*s != '[')
+ return FALSE;
+ }
+ s++;
+ break;
+ default:
+ panic("bad metacharacter in match");
+ /* NOTREACHED */
+ return FALSE; /* hush up gcc -Wall */
+ }
+ } else if (p[i++] != *s++)
+ return FALSE;
+ }
+}
+
+/*
+ From the ed(1) man pages (on ranges):
+
+ The `-' is treated as an ordinary character if it occurs first
+ (or first after an initial ^) or last in the string.
+
+ The right square bracket does not terminate the enclosed string
+ if it is the first character (after an initial `^', if any), in
+ the bracketed string.
+
+ rangematch() matches a single character against a class, and returns
+ an integer offset to the end of the range on success, or -1 on
+ failure.
+*/
+
+static int rangematch(char *p, char c) {
+ char *orig = p;
+ bool neg = (*p == '~');
+ bool matched = FALSE;
+ if (neg)
+ p++;
+ if (*p == ']') {
+ p++;
+ matched = (c == ']');
+ }
+ for (; *p != ']'; p++) {
+ if (*p == '\0')
+ return RANGE_ERROR; /* bad syntax */
+ if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
+ if (c >= *p)
+ matched |= (c <= p[2]);
+ p += 2;
+ } else {
+ matched |= (*p == c);
+ }
+ }
+ if (matched ^ neg)
+ return p - orig + 1; /* skip the right-bracket */
+ else
+ return RANGE_FAIL;
+}