match.c (2020B)
1 /* match.c: pattern matching routines */ 2 3 #include "rc.h" 4 5 static int rangematch(char *, char); 6 7 /* match() matches a single pattern against a single string. */ 8 9 extern bool match(char *p, char *m, char *s) { 10 struct { char *p, *m, *s; } next; 11 if (m == NULL) 12 return streq(p, s); 13 next.s = NULL; 14 while (*p || *s) { 15 if (*p) { 16 if (!*m) { 17 /* ordinary character */ 18 if (*s == *p) { 19 p++, m++, s++; 20 continue; 21 } 22 } else switch (*p) { 23 case '?': 24 if (*s) { 25 p++, m++, s++; 26 continue; 27 } 28 break; 29 case '[': { 30 int r = 1 + rangematch(p+1, *s); 31 if (r > 0) { 32 p += r, m += r, s++; 33 continue; 34 } 35 break; 36 } 37 case '*': 38 next.p = p++; 39 next.m = m++; 40 next.s = *s ? s+1 : NULL; 41 continue; 42 default: 43 panic("bad metacharacter in match"); 44 /* NOTREACHED */ 45 return FALSE; /* hush up gcc -Wall */ 46 } 47 } 48 if (next.s != NULL) { 49 p = next.p; 50 m = next.m; 51 s = next.s; 52 continue; 53 } 54 return FALSE; 55 } 56 return TRUE; 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 74 static 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 c == '[' ? 0 : -1; /* no right-bracket */ 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 -1; 99 }