xref: /plan9/sys/src/ape/cmd/expr/regexp.h (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 #define	CBRA	2
2 #define	CCHR	4
3 #define	CDOT	8
4 #define	CCL	12
5 #define	CDOL	20
6 #define	CEOF	22
7 #define	CKET	24
8 #define	CBACK	36
9 
10 #define	STAR	01
11 #define RNGE	03
12 
13 #define	NBRA	9
14 
15 #define PLACE(c)	ep[c >> 3] |= bittab[c & 07]
16 #define ISTHERE(c)	(ep[c >> 3] & bittab[c & 07])
17 
18 char	*braslist[NBRA];
19 char	*braelist[NBRA];
20 int	nbra, ebra;
21 char *loc1, *loc2, *locs;
22 int	sed;
23 
24 int	circf;
25 int	low;
26 int	size;
27 
28 char	bittab[] = {
29 	1,
30 	2,
31 	4,
32 	8,
33 	16,
34 	32,
35 	64,
36 	128
37 };
38 
39 char *
compile(instring,ep,endbuf,seof)40 compile(instring, ep, endbuf, seof)
41 register char *ep;
42 char *instring, *endbuf;
43 {
44 	INIT	/* Dependent declarations and initializations */
45 	register c;
46 	register eof = seof;
47 	char *lastep = instring;
48 	int cclcnt;
49 	char bracket[NBRA], *bracketp;
50 	int closed;
51 	char neg;
52 	int lc;
53 	int i, cflg;
54 
55 	lastep = 0;
56 	if((c = GETC()) == eof) {
57 		if(*ep == 0 && !sed)
58 			ERROR(41);
59 		RETURN(ep);
60 	}
61 	bracketp = bracket;
62 	circf = closed = nbra = ebra = 0;
63 	if (c == '^')
64 		circf++;
65 	else
66 		UNGETC(c);
67 	for (;;) {
68 		if (ep >= endbuf)
69 			ERROR(50);
70 		if((c = GETC()) != '*' && ((c != '\\') || (PEEKC() != '{')))
71 			lastep = ep;
72 		if (c == eof) {
73 			*ep++ = CEOF;
74 			RETURN(ep);
75 		}
76 		switch (c) {
77 
78 		case '.':
79 			*ep++ = CDOT;
80 			continue;
81 
82 		case '\n':
83 			ERROR(36);
84 		case '*':
85 			if (lastep==0 || *lastep==CBRA || *lastep==CKET)
86 				goto defchar;
87 			*lastep |= STAR;
88 			continue;
89 
90 		case '$':
91 			if(PEEKC() != eof)
92 				goto defchar;
93 			*ep++ = CDOL;
94 			continue;
95 
96 		case '[':
97 			if(&ep[17] >= endbuf)
98 				ERROR(50);
99 
100 			*ep++ = CCL;
101 			lc = 0;
102 			for(i = 0; i < 16; i++)
103 				ep[i] = 0;
104 
105 			neg = 0;
106 			if((c = GETC()) == '^') {
107 				neg = 1;
108 				c = GETC();
109 			}
110 
111 			do {
112 				if(c == '\0' || c == '\n')
113 					ERROR(49);
114 				if(c == '-' && lc != 0) {
115 					if ((c = GETC()) == ']') {
116 						PLACE('-');
117 						break;
118 					}
119 					while(lc < c) {
120 						PLACE(lc);
121 						lc++;
122 					}
123 				}
124 				lc = c;
125 				PLACE(c);
126 			} while((c = GETC()) != ']');
127 			if(neg) {
128 				for(cclcnt = 0; cclcnt < 16; cclcnt++)
129 					ep[cclcnt] ^= -1;
130 				ep[0] &= 0376;
131 			}
132 
133 			ep += 16;
134 
135 			continue;
136 
137 		case '\\':
138 			switch(c = GETC()) {
139 
140 			case '(':
141 				if(nbra >= NBRA)
142 					ERROR(43);
143 				*bracketp++ = nbra;
144 				*ep++ = CBRA;
145 				*ep++ = nbra++;
146 				continue;
147 
148 			case ')':
149 				if(bracketp <= bracket || ++ebra != nbra)
150 					ERROR(42);
151 				*ep++ = CKET;
152 				*ep++ = *--bracketp;
153 				closed++;
154 				continue;
155 
156 			case '{':
157 				if(lastep == (char *) (0))
158 					goto defchar;
159 				*lastep |= RNGE;
160 				cflg = 0;
161 			nlim:
162 				c = GETC();
163 				i = 0;
164 				do {
165 					if ('0' <= c && c <= '9')
166 						i = 10 * i + c - '0';
167 					else
168 						ERROR(16);
169 				} while(((c = GETC()) != '\\') && (c != ','));
170 				if (i > 255)
171 					ERROR(11);
172 				*ep++ = i;
173 				if (c == ',') {
174 					if(cflg++)
175 						ERROR(44);
176 					if((c = GETC()) == '\\')
177 						*ep++ = 255;
178 					else {
179 						UNGETC(c);
180 						goto nlim; /* get 2'nd number */
181 					}
182 				}
183 				if(GETC() != '}')
184 					ERROR(45);
185 				if(!cflg)	/* one number */
186 					*ep++ = i;
187 				else if((ep[-1] & 0377) < (ep[-2] & 0377))
188 					ERROR(46);
189 				continue;
190 
191 			case '\n':
192 				ERROR(36);
193 
194 			case 'n':
195 				c = '\n';
196 				goto defchar;
197 
198 			default:
199 				if(c >= '1' && c <= '9') {
200 					if((c -= '1') >= closed)
201 						ERROR(25);
202 					*ep++ = CBACK;
203 					*ep++ = c;
204 					continue;
205 				}
206 			}
207 			/* Drop through to default to use \ to turn off special chars */
208 
209 		defchar:
210 		default:
211 			lastep = ep;
212 			*ep++ = CCHR;
213 			*ep++ = c;
214 		}
215 	}
216 }
217 
step(p1,p2)218 step(p1, p2)
219 register char *p1, *p2;
220 {
221 	register c;
222 
223 	if (circf) {
224 		loc1 = p1;
225 		return(advance(p1, p2));
226 	}
227 	/* fast check for first character */
228 	if (*p2==CCHR) {
229 		c = p2[1];
230 		do {
231 			if (*p1 != c)
232 				continue;
233 			if (advance(p1, p2)) {
234 				loc1 = p1;
235 				return(1);
236 			}
237 		} while (*p1++);
238 		return(0);
239 	}
240 		/* regular algorithm */
241 	do {
242 		if (advance(p1, p2)) {
243 			loc1 = p1;
244 			return(1);
245 		}
246 	} while (*p1++);
247 	return(0);
248 }
249 
advance(lp,ep)250 advance(lp, ep)
251 register char *lp, *ep;
252 {
253 	register char *curlp;
254 	char c;
255 	char *bbeg;
256 	int ct;
257 
258 	for (;;) switch (*ep++) {
259 
260 	case CCHR:
261 		if (*ep++ == *lp++)
262 			continue;
263 		return(0);
264 
265 	case CDOT:
266 		if (*lp++)
267 			continue;
268 		return(0);
269 
270 	case CDOL:
271 		if (*lp==0)
272 			continue;
273 		return(0);
274 
275 	case CEOF:
276 		loc2 = lp;
277 		return(1);
278 
279 	case CCL:
280 		c = *lp++ & 0177;
281 		if(ISTHERE(c)) {
282 			ep += 16;
283 			continue;
284 		}
285 		return(0);
286 	case CBRA:
287 		braslist[*ep++] = lp;
288 		continue;
289 
290 	case CKET:
291 		braelist[*ep++] = lp;
292 		continue;
293 
294 	case CCHR|RNGE:
295 		c = *ep++;
296 		getrnge(ep);
297 		while(low--)
298 			if(*lp++ != c)
299 				return(0);
300 		curlp = lp;
301 		while(size--)
302 			if(*lp++ != c)
303 				break;
304 		if(size < 0)
305 			lp++;
306 		ep += 2;
307 		goto star;
308 
309 	case CDOT|RNGE:
310 		getrnge(ep);
311 		while(low--)
312 			if(*lp++ == '\0')
313 				return(0);
314 		curlp = lp;
315 		while(size--)
316 			if(*lp++ == '\0')
317 				break;
318 		if(size < 0)
319 			lp++;
320 		ep += 2;
321 		goto star;
322 
323 	case CCL|RNGE:
324 		getrnge(ep + 16);
325 		while(low--) {
326 			c = *lp++ & 0177;
327 			if(!ISTHERE(c))
328 				return(0);
329 		}
330 		curlp = lp;
331 		while(size--) {
332 			c = *lp++ & 0177;
333 			if(!ISTHERE(c))
334 				break;
335 		}
336 		if(size < 0)
337 			lp++;
338 		ep += 18;		/* 16 + 2 */
339 		goto star;
340 
341 	case CBACK:
342 		bbeg = braslist[*ep];
343 		ct = braelist[*ep++] - bbeg;
344 
345 		if(ecmp(bbeg, lp, ct)) {
346 			lp += ct;
347 			continue;
348 		}
349 		return(0);
350 
351 	case CBACK|STAR:
352 		bbeg = braslist[*ep];
353 		ct = braelist[*ep++] - bbeg;
354 		curlp = lp;
355 		while(ecmp(bbeg, lp, ct))
356 			lp += ct;
357 
358 		while(lp >= curlp) {
359 			if(advance(lp, ep))	return(1);
360 			lp -= ct;
361 		}
362 		return(0);
363 
364 
365 	case CDOT|STAR:
366 		curlp = lp;
367 		while (*lp++);
368 		goto star;
369 
370 	case CCHR|STAR:
371 		curlp = lp;
372 		while (*lp++ == *ep);
373 		ep++;
374 		goto star;
375 
376 	case CCL|STAR:
377 		curlp = lp;
378 		do {
379 			c = *lp++ & 0177;
380 		} while(ISTHERE(c));
381 		ep += 16;
382 		goto star;
383 
384 	star:
385 		do {
386 			if(--lp == locs)
387 				break;
388 			if (advance(lp, ep))
389 				return(1);
390 		} while (lp > curlp);
391 		return(0);
392 
393 	}
394 }
395 
getrnge(str)396 getrnge(str)
397 register char *str;
398 {
399 	low = *str++ & 0377;
400 	size = *str == 255 ? 20000 : (*str &0377) - low;
401 }
402 
ecmp(a,b,count)403 ecmp(a, b, count)
404 register char	*a, *b;
405 register	count;
406 {
407 	while(count--)
408 		if(*a++ != *b++)	return(0);
409 	return(1);
410 }
411