BSD 4_4_Lite1 development
[unix-history] / usr / src / contrib / rc-1.4 / match.c
CommitLineData
9d25673b
C
1/* match.c: pattern matching routines */
2
3#include "rc.h"
4
5static int rangematch(char *, char);
6
7enum { RANGE_FAIL = -1, RANGE_ERROR = -2 };
8
9/* match() matches a single pattern against a single string. */
10
11extern bool match(char *p, char *m, char *s) {
12 int i, j;
13 if (m == NULL)
14 return streq(p, s);
15 i = 0;
16 while (1) {
17 if (p[i] == '\0')
18 return *s == '\0';
19 else if (m[i]) {
20 switch (p[i++]) {
21 case '?':
22 if (*s++ == '\0')
23 return FALSE;
24 break;
25 case '*':
26 while (p[i] == '*' && m[i] == 1) /* collapse multiple stars */
27 i++;
28 if (p[i] == '\0') /* star at end of pattern? */
29 return TRUE;
30 while (*s != '\0')
31 if (match(p + i, m + i, s++))
32 return TRUE;
33 return FALSE;
34 case '[':
35 if (*s == '\0')
36 return FALSE;
37 switch (j = rangematch(p + i, *s)) {
38 default:
39 i += j;
40 break;
41 case RANGE_FAIL:
42 return FALSE;
43 case RANGE_ERROR:
44 if (*s != '[')
45 return FALSE;
46 }
47 s++;
48 break;
49 default:
50 panic("bad metacharacter in match");
51 /* NOTREACHED */
52 return FALSE; /* hush up gcc -Wall */
53 }
54 } else if (p[i++] != *s++)
55 return FALSE;
56 }
57}
58
59/*
60 From the ed(1) man pages (on ranges):
61
62 The `-' is treated as an ordinary character if it occurs first
63 (or first after an initial ^) or last in the string.
64
65 The right square bracket does not terminate the enclosed string
66 if it is the first character (after an initial `^', if any), in
67 the bracketed string.
68
69 rangematch() matches a single character against a class, and returns
70 an integer offset to the end of the range on success, or -1 on
71 failure.
72*/
73
74static int rangematch(char *p, char c) {
75 char *orig = p;
76 bool neg = (*p == '~');
77 bool matched = FALSE;
78 if (neg)
79 p++;
80 if (*p == ']') {
81 p++;
82 matched = (c == ']');
83 }
84 for (; *p != ']'; p++) {
85 if (*p == '\0')
86 return RANGE_ERROR; /* bad syntax */
87 if (p[1] == '-' && p[2] != ']') { /* check for [..-..] but ignore [..-] */
88 if (c >= *p)
89 matched |= (c <= p[2]);
90 p += 2;
91 } else {
92 matched |= (*p == c);
93 }
94 }
95 if (matched ^ neg)
96 return p - orig + 1; /* skip the right-bracket */
97 else
98 return RANGE_FAIL;
99}