rc

[fork] interactive rc shell
git clone https://hhvn.uk/rc
git clone git://hhvn.uk/rc
Log | Files | Refs | README | LICENSE

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 }