Line data Source code
1 : /*
2 : * lexical analyzer
3 : * This file is #included by regcomp.c.
4 : *
5 : * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
6 : *
7 : * Development of this software was funded, in part, by Cray Research Inc.,
8 : * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
9 : * Corporation, none of whom are responsible for the results. The author
10 : * thanks all of them.
11 : *
12 : * Redistribution and use in source and binary forms -- with or without
13 : * modification -- are permitted for any purpose, provided that
14 : * redistributions in source form retain this entire copyright notice and
15 : * indicate the origin and nature of any modifications.
16 : *
17 : * I'd appreciate being given credit for this package in the documentation
18 : * of software which uses it, but that is not a requirement.
19 : *
20 : * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
21 : * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22 : * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23 : * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 : * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 : * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 : * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 : * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 : *
31 : * src/backend/regex/regc_lex.c
32 : *
33 : */
34 :
35 : /* scanning macros (know about v) */
36 : #define ATEOS() (v->now >= v->stop)
37 : #define HAVE(n) (v->stop - v->now >= (n))
38 : #define NEXT1(c) (!ATEOS() && *v->now == CHR(c))
39 : #define NEXT2(a,b) (HAVE(2) && *v->now == CHR(a) && *(v->now+1) == CHR(b))
40 : #define NEXT3(a,b,c) (HAVE(3) && *v->now == CHR(a) && \
41 : *(v->now+1) == CHR(b) && \
42 : *(v->now+2) == CHR(c))
43 : #define SET(c) (v->nexttype = (c))
44 : #define SETV(c, n) (v->nexttype = (c), v->nextvalue = (n))
45 : #define RET(c) return (SET(c), 1)
46 : #define RETV(c, n) return (SETV(c, n), 1)
47 : #define FAILW(e) return (ERR(e), 0) /* ERR does SET(EOS) */
48 : #define LASTTYPE(t) (v->lasttype == (t))
49 :
50 : /* lexical contexts */
51 : #define L_ERE 1 /* mainline ERE/ARE */
52 : #define L_BRE 2 /* mainline BRE */
53 : #define L_Q 3 /* REG_QUOTE */
54 : #define L_EBND 4 /* ERE/ARE bound */
55 : #define L_BBND 5 /* BRE bound */
56 : #define L_BRACK 6 /* brackets */
57 : #define L_CEL 7 /* collating element */
58 : #define L_ECL 8 /* equivalence class */
59 : #define L_CCL 9 /* character class */
60 : #define INTOCON(c) (v->lexcon = (c))
61 : #define INCON(con) (v->lexcon == (con))
62 :
63 : /* construct pointer past end of chr array */
64 : #define ENDOF(array) ((array) + sizeof(array)/sizeof(chr))
65 :
66 : /*
67 : * lexstart - set up lexical stuff, scan leading options
68 : */
69 : static void
70 7392 : lexstart(struct vars *v)
71 : {
72 7392 : prefixes(v); /* may turn on new type bits etc. */
73 7392 : NOERR();
74 :
75 7386 : if (v->cflags & REG_QUOTE)
76 : {
77 : assert(!(v->cflags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)));
78 96 : INTOCON(L_Q);
79 : }
80 7290 : else if (v->cflags & REG_EXTENDED)
81 : {
82 : assert(!(v->cflags & REG_QUOTE));
83 7034 : INTOCON(L_ERE);
84 : }
85 : else
86 : {
87 : assert(!(v->cflags & (REG_QUOTE | REG_ADVF)));
88 256 : INTOCON(L_BRE);
89 : }
90 :
91 7386 : v->nexttype = EMPTY; /* remember we were at the start */
92 7386 : next(v); /* set up the first token */
93 : }
94 :
95 : /*
96 : * prefixes - implement various special prefixes
97 : */
98 : static void
99 7392 : prefixes(struct vars *v)
100 : {
101 : /* literal string doesn't get any of this stuff */
102 7392 : if (v->cflags & REG_QUOTE)
103 82 : return;
104 :
105 : /* initial "***" gets special things */
106 7310 : if (HAVE(4) && NEXT3('*', '*', '*'))
107 20 : switch (*(v->now + 3))
108 : {
109 4 : case CHR('?'): /* "***?" error, msg shows version */
110 4 : ERR(REG_BADPAT);
111 4 : return; /* proceed no further */
112 : break;
113 4 : case CHR('='): /* "***=" shifts to literal string */
114 4 : NOTE(REG_UNONPOSIX);
115 4 : v->cflags |= REG_QUOTE;
116 4 : v->cflags &= ~(REG_ADVANCED | REG_EXPANDED | REG_NEWLINE);
117 4 : v->now += 4;
118 4 : return; /* and there can be no more prefixes */
119 : break;
120 12 : case CHR(':'): /* "***:" shifts to AREs */
121 12 : NOTE(REG_UNONPOSIX);
122 12 : v->cflags |= REG_ADVANCED;
123 12 : v->now += 4;
124 12 : break;
125 0 : default: /* otherwise *** is just an error */
126 0 : ERR(REG_BADRPT);
127 0 : return;
128 : break;
129 : }
130 :
131 : /* BREs and EREs don't get embedded options */
132 7302 : if ((v->cflags & REG_ADVANCED) != REG_ADVANCED)
133 266 : return;
134 :
135 : /* embedded options (AREs only) */
136 7036 : if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2)))
137 : {
138 56 : NOTE(REG_UNONPOSIX);
139 56 : v->now += 2;
140 120 : for (; !ATEOS() && iscalpha(*v->now); v->now++)
141 66 : switch (*v->now)
142 : {
143 6 : case CHR('b'): /* BREs (but why???) */
144 6 : v->cflags &= ~(REG_ADVANCED | REG_QUOTE);
145 6 : break;
146 6 : case CHR('c'): /* case sensitive */
147 6 : v->cflags &= ~REG_ICASE;
148 6 : break;
149 4 : case CHR('e'): /* plain EREs */
150 4 : v->cflags |= REG_EXTENDED;
151 4 : v->cflags &= ~(REG_ADVF | REG_QUOTE);
152 4 : break;
153 10 : case CHR('i'): /* case insensitive */
154 10 : v->cflags |= REG_ICASE;
155 10 : break;
156 10 : case CHR('m'): /* Perloid synonym for n */
157 : case CHR('n'): /* \n affects ^ $ . [^ */
158 10 : v->cflags |= REG_NEWLINE;
159 10 : break;
160 4 : case CHR('p'): /* ~Perl, \n affects . [^ */
161 4 : v->cflags |= REG_NLSTOP;
162 4 : v->cflags &= ~REG_NLANCH;
163 4 : break;
164 12 : case CHR('q'): /* literal string */
165 12 : v->cflags |= REG_QUOTE;
166 12 : v->cflags &= ~REG_ADVANCED;
167 12 : break;
168 2 : case CHR('s'): /* single line, \n ordinary */
169 2 : v->cflags &= ~REG_NEWLINE;
170 2 : break;
171 2 : case CHR('t'): /* tight syntax */
172 2 : v->cflags &= ~REG_EXPANDED;
173 2 : break;
174 4 : case CHR('w'): /* weird, \n affects ^ $ only */
175 4 : v->cflags &= ~REG_NLSTOP;
176 4 : v->cflags |= REG_NLANCH;
177 4 : break;
178 4 : case CHR('x'): /* expanded syntax */
179 4 : v->cflags |= REG_EXPANDED;
180 4 : break;
181 2 : default:
182 2 : ERR(REG_BADOPT);
183 2 : return;
184 : }
185 54 : if (!NEXT1(')'))
186 : {
187 0 : ERR(REG_BADOPT);
188 0 : return;
189 : }
190 54 : v->now++;
191 54 : if (v->cflags & REG_QUOTE)
192 10 : v->cflags &= ~(REG_EXPANDED | REG_NEWLINE);
193 : }
194 : }
195 :
196 : /*
197 : * next - get next token
198 : */
199 : static int /* 1 normal, 0 failure */
200 137774 : next(struct vars *v)
201 : {
202 : chr c;
203 :
204 137774 : next_restart: /* loop here after eating a comment */
205 :
206 : /* errors yield an infinite sequence of failures */
207 137774 : if (ISERR())
208 136 : return 0; /* the error has set nexttype to EOS */
209 :
210 : /* remember flavor of last token */
211 137638 : v->lasttype = v->nexttype;
212 :
213 : /* REG_BOSONLY */
214 137638 : if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
215 : {
216 : /* at start of a REG_BOSONLY RE */
217 4 : RETV(SBEGIN, 0); /* same as \A */
218 : }
219 :
220 : /* skip white space etc. if appropriate (not in literal or []) */
221 137634 : if (v->cflags & REG_EXPANDED)
222 2466 : switch (v->lexcon)
223 : {
224 1626 : case L_ERE:
225 : case L_BRE:
226 : case L_EBND:
227 : case L_BBND:
228 1626 : skip(v);
229 1626 : break;
230 : }
231 :
232 : /* handle EOS, depending on context */
233 137634 : if (ATEOS())
234 : {
235 7202 : switch (v->lexcon)
236 : {
237 7170 : case L_ERE:
238 : case L_BRE:
239 : case L_Q:
240 7170 : RET(EOS);
241 : break;
242 4 : case L_EBND:
243 : case L_BBND:
244 4 : FAILW(REG_EBRACE);
245 : break;
246 28 : case L_BRACK:
247 : case L_CEL:
248 : case L_ECL:
249 : case L_CCL:
250 28 : FAILW(REG_EBRACK);
251 : break;
252 : }
253 : assert(NOTREACHED);
254 : }
255 :
256 : /* okay, time to actually get a character */
257 130432 : c = *v->now++;
258 :
259 : /* deal with the easy contexts, punt EREs to code below */
260 130432 : switch (v->lexcon)
261 : {
262 644 : case L_BRE: /* punt BREs to separate function */
263 644 : return brenext(v, c);
264 : break;
265 121908 : case L_ERE: /* see below */
266 121908 : break;
267 494 : case L_Q: /* literal strings are easy */
268 494 : RETV(PLAIN, c);
269 : break;
270 1594 : case L_BBND: /* bounds are fairly simple */
271 : case L_EBND:
272 1594 : switch (c)
273 : {
274 834 : case CHR('0'):
275 : case CHR('1'):
276 : case CHR('2'):
277 : case CHR('3'):
278 : case CHR('4'):
279 : case CHR('5'):
280 : case CHR('6'):
281 : case CHR('7'):
282 : case CHR('8'):
283 : case CHR('9'):
284 834 : RETV(DIGIT, (chr) DIGITVAL(c));
285 : break;
286 244 : case CHR(','):
287 244 : RET(',');
288 : break;
289 508 : case CHR('}'): /* ERE bound ends with } */
290 508 : if (INCON(L_EBND))
291 : {
292 508 : INTOCON(L_ERE);
293 508 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
294 : {
295 90 : v->now++;
296 90 : NOTE(REG_UNONPOSIX);
297 90 : RETV('}', 0);
298 : }
299 418 : RETV('}', 1);
300 : }
301 : else
302 0 : FAILW(REG_BADBR);
303 : break;
304 6 : case CHR('\\'): /* BRE bound ends with \} */
305 6 : if (INCON(L_BBND) && NEXT1('}'))
306 : {
307 4 : v->now++;
308 4 : INTOCON(L_BRE);
309 4 : RETV('}', 1);
310 : }
311 : else
312 2 : FAILW(REG_BADBR);
313 : break;
314 2 : default:
315 2 : FAILW(REG_BADBR);
316 : break;
317 : }
318 : assert(NOTREACHED);
319 : break;
320 4258 : case L_BRACK: /* brackets are not too hard */
321 : switch (c)
322 : {
323 1200 : case CHR(']'):
324 1200 : if (LASTTYPE('['))
325 4 : RETV(PLAIN, c);
326 : else
327 : {
328 1196 : INTOCON((v->cflags & REG_EXTENDED) ?
329 : L_ERE : L_BRE);
330 1196 : RET(']');
331 : }
332 : break;
333 136 : case CHR('\\'):
334 136 : NOTE(REG_UBBS);
335 136 : if (!(v->cflags & REG_ADVF))
336 14 : RETV(PLAIN, c);
337 122 : NOTE(REG_UNONPOSIX);
338 122 : if (ATEOS())
339 0 : FAILW(REG_EESCAPE);
340 122 : if (!lexescape(v))
341 0 : return 0;
342 122 : switch (v->nexttype)
343 : { /* not all escapes okay here */
344 120 : case PLAIN:
345 : case CCLASSS:
346 : case CCLASSC:
347 120 : return 1;
348 : break;
349 : }
350 : /* not one of the acceptable escapes */
351 2 : FAILW(REG_EESCAPE);
352 : break;
353 606 : case CHR('-'):
354 606 : if (LASTTYPE('[') || NEXT1(']'))
355 16 : RETV(PLAIN, c);
356 : else
357 590 : RETV(RANGE, c);
358 : break;
359 308 : case CHR('['):
360 308 : if (ATEOS())
361 0 : FAILW(REG_EBRACK);
362 308 : switch (*v->now++)
363 : {
364 24 : case CHR('.'):
365 24 : INTOCON(L_CEL);
366 : /* might or might not be locale-specific */
367 24 : RET(COLLEL);
368 : break;
369 32 : case CHR('='):
370 32 : INTOCON(L_ECL);
371 32 : NOTE(REG_ULOCALE);
372 32 : RET(ECLASS);
373 : break;
374 248 : case CHR(':'):
375 248 : INTOCON(L_CCL);
376 248 : NOTE(REG_ULOCALE);
377 248 : RET(CCLASS);
378 : break;
379 4 : default: /* oops */
380 4 : v->now--;
381 4 : RETV(PLAIN, c);
382 : break;
383 : }
384 : assert(NOTREACHED);
385 : break;
386 2008 : default:
387 2008 : RETV(PLAIN, c);
388 : break;
389 : }
390 : assert(NOTREACHED);
391 : break;
392 64 : case L_CEL: /* collating elements are easy */
393 64 : if (c == CHR('.') && NEXT1(']'))
394 : {
395 20 : v->now++;
396 20 : INTOCON(L_BRACK);
397 20 : RETV(END, '.');
398 : }
399 : else
400 44 : RETV(PLAIN, c);
401 : break;
402 48 : case L_ECL: /* ditto equivalence classes */
403 48 : if (c == CHR('=') && NEXT1(']'))
404 : {
405 24 : v->now++;
406 24 : INTOCON(L_BRACK);
407 24 : RETV(END, '=');
408 : }
409 : else
410 24 : RETV(PLAIN, c);
411 : break;
412 1422 : case L_CCL: /* ditto character classes */
413 1422 : if (c == CHR(':') && NEXT1(']'))
414 : {
415 238 : v->now++;
416 238 : INTOCON(L_BRACK);
417 238 : RETV(END, ':');
418 : }
419 : else
420 1184 : RETV(PLAIN, c);
421 : break;
422 0 : default:
423 : assert(NOTREACHED);
424 0 : break;
425 : }
426 :
427 : /* that got rid of everything except EREs and AREs */
428 : assert(INCON(L_ERE));
429 :
430 : /* deal with EREs and AREs, except for backslashes */
431 121908 : switch (c)
432 : {
433 622 : case CHR('|'):
434 622 : RET('|');
435 : break;
436 21162 : case CHR('*'):
437 21162 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
438 : {
439 54 : v->now++;
440 54 : NOTE(REG_UNONPOSIX);
441 54 : RETV('*', 0);
442 : }
443 21108 : RETV('*', 1);
444 : break;
445 910 : case CHR('+'):
446 910 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
447 : {
448 44 : v->now++;
449 44 : NOTE(REG_UNONPOSIX);
450 44 : RETV('+', 0);
451 : }
452 866 : RETV('+', 1);
453 : break;
454 122 : case CHR('?'):
455 122 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
456 : {
457 4 : v->now++;
458 4 : NOTE(REG_UNONPOSIX);
459 4 : RETV('?', 0);
460 : }
461 118 : RETV('?', 1);
462 : break;
463 524 : case CHR('{'): /* bounds start or plain character */
464 524 : if (v->cflags & REG_EXPANDED)
465 32 : skip(v);
466 524 : if (ATEOS() || !iscdigit(*v->now))
467 : {
468 8 : NOTE(REG_UBRACES);
469 8 : NOTE(REG_UUNSPEC);
470 8 : RETV(PLAIN, c);
471 : }
472 : else
473 : {
474 516 : NOTE(REG_UBOUNDS);
475 516 : INTOCON(L_EBND);
476 516 : RET('{');
477 : }
478 : assert(NOTREACHED);
479 : break;
480 5254 : case CHR('('): /* parenthesis, or advanced extension */
481 5254 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
482 : {
483 486 : NOTE(REG_UNONPOSIX);
484 486 : v->now++;
485 486 : if (ATEOS())
486 0 : FAILW(REG_BADRPT);
487 486 : switch (*v->now++)
488 : {
489 214 : case CHR(':'): /* non-capturing paren */
490 214 : RETV('(', 0);
491 : break;
492 2 : case CHR('#'): /* comment */
493 16 : while (!ATEOS() && *v->now != CHR(')'))
494 14 : v->now++;
495 2 : if (!ATEOS())
496 2 : v->now++;
497 : assert(v->nexttype == v->lasttype);
498 2 : goto next_restart;
499 84 : case CHR('='): /* positive lookahead */
500 84 : NOTE(REG_ULOOKAROUND);
501 84 : RETV(LACON, LATYPE_AHEAD_POS);
502 : break;
503 78 : case CHR('!'): /* negative lookahead */
504 78 : NOTE(REG_ULOOKAROUND);
505 78 : RETV(LACON, LATYPE_AHEAD_NEG);
506 : break;
507 106 : case CHR('<'):
508 106 : if (ATEOS())
509 0 : FAILW(REG_BADRPT);
510 106 : switch (*v->now++)
511 : {
512 78 : case CHR('='): /* positive lookbehind */
513 78 : NOTE(REG_ULOOKAROUND);
514 78 : RETV(LACON, LATYPE_BEHIND_POS);
515 : break;
516 28 : case CHR('!'): /* negative lookbehind */
517 28 : NOTE(REG_ULOOKAROUND);
518 28 : RETV(LACON, LATYPE_BEHIND_NEG);
519 : break;
520 0 : default:
521 0 : FAILW(REG_BADRPT);
522 : break;
523 : }
524 : assert(NOTREACHED);
525 : break;
526 2 : default:
527 2 : FAILW(REG_BADRPT);
528 : break;
529 : }
530 4768 : assert(NOTREACHED);
531 : }
532 4768 : RETV('(', 1);
533 : break;
534 5188 : case CHR(')'):
535 5188 : if (LASTTYPE('('))
536 46 : NOTE(REG_UUNSPEC);
537 5188 : RETV(')', c);
538 : break;
539 1134 : case CHR('['): /* easy except for [[:<:]] and [[:>:]] */
540 1134 : if (HAVE(6) && *(v->now + 0) == CHR('[') &&
541 270 : *(v->now + 1) == CHR(':') &&
542 250 : (*(v->now + 2) == CHR('<') ||
543 240 : *(v->now + 2) == CHR('>')) &&
544 20 : *(v->now + 3) == CHR(':') &&
545 20 : *(v->now + 4) == CHR(']') &&
546 20 : *(v->now + 5) == CHR(']'))
547 : {
548 20 : c = *(v->now + 2);
549 20 : v->now += 6;
550 20 : NOTE(REG_UNONPOSIX);
551 20 : RET((c == CHR('<')) ? '<' : '>');
552 : }
553 1114 : INTOCON(L_BRACK);
554 1114 : if (NEXT1('^'))
555 : {
556 232 : v->now++;
557 232 : RETV('[', 0);
558 : }
559 882 : RETV('[', 1);
560 : break;
561 3062 : case CHR('.'):
562 3062 : RET('.');
563 : break;
564 4674 : case CHR('^'):
565 4674 : RET('^');
566 : break;
567 4112 : case CHR('$'):
568 4112 : RET('$');
569 : break;
570 2216 : case CHR('\\'): /* mostly punt backslashes to code below */
571 2216 : if (ATEOS())
572 2 : FAILW(REG_EESCAPE);
573 2214 : break;
574 72928 : default: /* ordinary character */
575 72928 : RETV(PLAIN, c);
576 : break;
577 : }
578 :
579 : /* ERE/ARE backslash handling; backslash already eaten */
580 : assert(!ATEOS());
581 2214 : if (!(v->cflags & REG_ADVF))
582 : { /* only AREs have non-trivial escapes */
583 8 : if (iscalnum(*v->now))
584 : {
585 6 : NOTE(REG_UBSALNUM);
586 6 : NOTE(REG_UUNSPEC);
587 : }
588 8 : RETV(PLAIN, *v->now++);
589 : }
590 2206 : return lexescape(v);
591 : }
592 :
593 : /*
594 : * lexescape - parse an ARE backslash escape (backslash already eaten)
595 : *
596 : * This is used for ARE backslashes both normally and inside bracket
597 : * expressions. In the latter case, not all escape types are allowed,
598 : * but the caller must reject unwanted ones after we return.
599 : */
600 : static int
601 2328 : lexescape(struct vars *v)
602 : {
603 : chr c;
604 : static const chr alert[] = {
605 : CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
606 : };
607 : static const chr esc[] = {
608 : CHR('E'), CHR('S'), CHR('C')
609 : };
610 : const chr *save;
611 :
612 : assert(v->cflags & REG_ADVF);
613 :
614 : assert(!ATEOS());
615 2328 : c = *v->now++;
616 :
617 : /* if it's not alphanumeric ASCII, treat it as a plain character */
618 2328 : if (!('a' <= c && c <= 'z') &&
619 1746 : !('A' <= c && c <= 'Z') &&
620 632 : !('0' <= c && c <= '9'))
621 1296 : RETV(PLAIN, c);
622 :
623 1032 : NOTE(REG_UNONPOSIX);
624 1032 : switch (c)
625 : {
626 2 : case CHR('a'):
627 2 : RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
628 : break;
629 22 : case CHR('A'):
630 22 : RETV(SBEGIN, 0);
631 : break;
632 26 : case CHR('b'):
633 26 : RETV(PLAIN, CHR('\b'));
634 : break;
635 10 : case CHR('B'):
636 10 : RETV(PLAIN, CHR('\\'));
637 : break;
638 4 : case CHR('c'):
639 4 : NOTE(REG_UUNPORT);
640 4 : if (ATEOS())
641 0 : FAILW(REG_EESCAPE);
642 4 : RETV(PLAIN, (chr) (*v->now++ & 037));
643 : break;
644 240 : case CHR('d'):
645 240 : NOTE(REG_ULOCALE);
646 240 : RETV(CCLASSS, CC_DIGIT);
647 : break;
648 28 : case CHR('D'):
649 28 : NOTE(REG_ULOCALE);
650 28 : RETV(CCLASSC, CC_DIGIT);
651 : break;
652 2 : case CHR('e'):
653 2 : NOTE(REG_UUNPORT);
654 2 : RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
655 : break;
656 2 : case CHR('f'):
657 2 : RETV(PLAIN, CHR('\f'));
658 : break;
659 34 : case CHR('m'):
660 34 : RET('<');
661 : break;
662 28 : case CHR('M'):
663 28 : RET('>');
664 : break;
665 12 : case CHR('n'):
666 12 : RETV(PLAIN, CHR('\n'));
667 : break;
668 10 : case CHR('r'):
669 10 : RETV(PLAIN, CHR('\r'));
670 : break;
671 56 : case CHR('s'):
672 56 : NOTE(REG_ULOCALE);
673 56 : RETV(CCLASSS, CC_SPACE);
674 : break;
675 34 : case CHR('S'):
676 34 : NOTE(REG_ULOCALE);
677 34 : RETV(CCLASSC, CC_SPACE);
678 : break;
679 4 : case CHR('t'):
680 4 : RETV(PLAIN, CHR('\t'));
681 : break;
682 56 : case CHR('u'):
683 56 : c = lexdigits(v, 16, 4, 4);
684 56 : if (ISERR() || !CHR_IS_IN_RANGE(c))
685 2 : FAILW(REG_EESCAPE);
686 54 : RETV(PLAIN, c);
687 : break;
688 20 : case CHR('U'):
689 20 : c = lexdigits(v, 16, 8, 8);
690 20 : if (ISERR() || !CHR_IS_IN_RANGE(c))
691 10 : FAILW(REG_EESCAPE);
692 10 : RETV(PLAIN, c);
693 : break;
694 2 : case CHR('v'):
695 2 : RETV(PLAIN, CHR('\v'));
696 : break;
697 100 : case CHR('w'):
698 100 : NOTE(REG_ULOCALE);
699 100 : RETV(CCLASSS, CC_WORD);
700 : break;
701 16 : case CHR('W'):
702 16 : NOTE(REG_ULOCALE);
703 16 : RETV(CCLASSC, CC_WORD);
704 : break;
705 12 : case CHR('x'):
706 12 : NOTE(REG_UUNPORT);
707 12 : c = lexdigits(v, 16, 1, 255); /* REs >255 long outside spec */
708 12 : if (ISERR() || !CHR_IS_IN_RANGE(c))
709 8 : FAILW(REG_EESCAPE);
710 4 : RETV(PLAIN, c);
711 : break;
712 18 : case CHR('y'):
713 18 : NOTE(REG_ULOCALE);
714 18 : RETV(WBDRY, 0);
715 : break;
716 38 : case CHR('Y'):
717 38 : NOTE(REG_ULOCALE);
718 38 : RETV(NWBDRY, 0);
719 : break;
720 12 : case CHR('Z'):
721 12 : RETV(SEND, 0);
722 : break;
723 232 : case CHR('1'):
724 : case CHR('2'):
725 : case CHR('3'):
726 : case CHR('4'):
727 : case CHR('5'):
728 : case CHR('6'):
729 : case CHR('7'):
730 : case CHR('8'):
731 : case CHR('9'):
732 232 : save = v->now;
733 232 : v->now--; /* put first digit back */
734 232 : c = lexdigits(v, 10, 1, 255); /* REs >255 long outside spec */
735 232 : if (ISERR())
736 0 : FAILW(REG_EESCAPE);
737 : /* ugly heuristic (first test is "exactly 1 digit?") */
738 232 : if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
739 : {
740 222 : NOTE(REG_UBACKREF);
741 222 : RETV(BACKREF, c);
742 : }
743 : /* oops, doesn't look like it's a backref after all... */
744 10 : v->now = save;
745 : /* and fall through into octal number */
746 : /* FALLTHROUGH */
747 20 : case CHR('0'):
748 20 : NOTE(REG_UUNPORT);
749 20 : v->now--; /* put first digit back */
750 20 : c = lexdigits(v, 8, 1, 3);
751 20 : if (ISERR())
752 0 : FAILW(REG_EESCAPE);
753 20 : if (c > 0xff)
754 : {
755 : /* out of range, so we handled one digit too much */
756 2 : v->now--;
757 2 : c >>= 3;
758 : }
759 20 : RETV(PLAIN, c);
760 : break;
761 2 : default:
762 :
763 : /*
764 : * Throw an error for unrecognized ASCII alpha escape sequences,
765 : * which reserves them for future use if needed.
766 : */
767 2 : FAILW(REG_EESCAPE);
768 : break;
769 : }
770 : assert(NOTREACHED);
771 : }
772 :
773 : /*
774 : * lexdigits - slurp up digits and return chr value
775 : *
776 : * This does not account for overflow; callers should range-check the result
777 : * if maxlen is large enough to make that possible.
778 : */
779 : static chr /* chr value; errors signalled via ERR */
780 340 : lexdigits(struct vars *v,
781 : int base,
782 : int minlen,
783 : int maxlen)
784 : {
785 : uchr n; /* unsigned to avoid overflow misbehavior */
786 : int len;
787 : chr c;
788 : int d;
789 340 : const uchr ub = (uchr) base;
790 :
791 340 : n = 0;
792 1086 : for (len = 0; len < maxlen && !ATEOS(); len++)
793 : {
794 920 : c = *v->now++;
795 920 : switch (c)
796 : {
797 686 : case CHR('0'):
798 : case CHR('1'):
799 : case CHR('2'):
800 : case CHR('3'):
801 : case CHR('4'):
802 : case CHR('5'):
803 : case CHR('6'):
804 : case CHR('7'):
805 : case CHR('8'):
806 : case CHR('9'):
807 686 : d = DIGITVAL(c);
808 686 : break;
809 0 : case CHR('a'):
810 : case CHR('A'):
811 0 : d = 10;
812 0 : break;
813 16 : case CHR('b'):
814 : case CHR('B'):
815 16 : d = 11;
816 16 : break;
817 4 : case CHR('c'):
818 : case CHR('C'):
819 4 : d = 12;
820 4 : break;
821 0 : case CHR('d'):
822 : case CHR('D'):
823 0 : d = 13;
824 0 : break;
825 4 : case CHR('e'):
826 : case CHR('E'):
827 4 : d = 14;
828 4 : break;
829 58 : case CHR('f'):
830 : case CHR('F'):
831 58 : d = 15;
832 58 : break;
833 152 : default:
834 152 : v->now--; /* oops, not a digit at all */
835 152 : d = -1;
836 152 : break;
837 : }
838 :
839 920 : if (d >= base)
840 : { /* not a plausible digit */
841 22 : v->now--;
842 22 : d = -1;
843 : }
844 920 : if (d < 0)
845 174 : break; /* NOTE BREAK OUT */
846 746 : n = n * ub + (uchr) d;
847 : }
848 340 : if (len < minlen)
849 14 : ERR(REG_EESCAPE);
850 :
851 340 : return (chr) n;
852 : }
853 :
854 : /*
855 : * brenext - get next BRE token
856 : *
857 : * This is much like EREs except for all the stupid backslashes and the
858 : * context-dependency of some things.
859 : */
860 : static int /* 1 normal, 0 failure */
861 644 : brenext(struct vars *v,
862 : chr c)
863 : {
864 644 : switch (c)
865 : {
866 46 : case CHR('*'):
867 46 : if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
868 12 : RETV(PLAIN, c);
869 34 : RETV('*', 1);
870 : break;
871 148 : case CHR('['):
872 148 : if (HAVE(6) && *(v->now + 0) == CHR('[') &&
873 44 : *(v->now + 1) == CHR(':') &&
874 24 : (*(v->now + 2) == CHR('<') ||
875 16 : *(v->now + 2) == CHR('>')) &&
876 16 : *(v->now + 3) == CHR(':') &&
877 16 : *(v->now + 4) == CHR(']') &&
878 16 : *(v->now + 5) == CHR(']'))
879 : {
880 16 : c = *(v->now + 2);
881 16 : v->now += 6;
882 16 : NOTE(REG_UNONPOSIX);
883 16 : RET((c == CHR('<')) ? '<' : '>');
884 : }
885 132 : INTOCON(L_BRACK);
886 132 : if (NEXT1('^'))
887 : {
888 12 : v->now++;
889 12 : RETV('[', 0);
890 : }
891 120 : RETV('[', 1);
892 : break;
893 8 : case CHR('.'):
894 8 : RET('.');
895 : break;
896 36 : case CHR('^'):
897 36 : if (LASTTYPE(EMPTY))
898 28 : RET('^');
899 8 : if (LASTTYPE('('))
900 : {
901 2 : NOTE(REG_UUNSPEC);
902 2 : RET('^');
903 : }
904 6 : RETV(PLAIN, c);
905 : break;
906 30 : case CHR('$'):
907 30 : if (v->cflags & REG_EXPANDED)
908 0 : skip(v);
909 30 : if (ATEOS())
910 22 : RET('$');
911 8 : if (NEXT2('\\', ')'))
912 : {
913 2 : NOTE(REG_UUNSPEC);
914 2 : RET('$');
915 : }
916 6 : RETV(PLAIN, c);
917 : break;
918 52 : case CHR('\\'):
919 52 : break; /* see below */
920 324 : default:
921 324 : RETV(PLAIN, c);
922 : break;
923 : }
924 :
925 : assert(c == CHR('\\'));
926 :
927 52 : if (ATEOS())
928 2 : FAILW(REG_EESCAPE);
929 :
930 50 : c = *v->now++;
931 50 : switch (c)
932 : {
933 6 : case CHR('{'):
934 6 : INTOCON(L_BBND);
935 6 : NOTE(REG_UBOUNDS);
936 6 : RET('{');
937 : break;
938 12 : case CHR('('):
939 12 : RETV('(', 1);
940 : break;
941 12 : case CHR(')'):
942 12 : RETV(')', c);
943 : break;
944 6 : case CHR('<'):
945 6 : NOTE(REG_UNONPOSIX);
946 6 : RET('<');
947 : break;
948 6 : case CHR('>'):
949 6 : NOTE(REG_UNONPOSIX);
950 6 : RET('>');
951 : break;
952 4 : case CHR('1'):
953 : case CHR('2'):
954 : case CHR('3'):
955 : case CHR('4'):
956 : case CHR('5'):
957 : case CHR('6'):
958 : case CHR('7'):
959 : case CHR('8'):
960 : case CHR('9'):
961 4 : NOTE(REG_UBACKREF);
962 4 : RETV(BACKREF, (chr) DIGITVAL(c));
963 : break;
964 4 : default:
965 4 : if (iscalnum(c))
966 : {
967 4 : NOTE(REG_UBSALNUM);
968 4 : NOTE(REG_UUNSPEC);
969 : }
970 4 : RETV(PLAIN, c);
971 : break;
972 : }
973 :
974 : assert(NOTREACHED);
975 : return 0;
976 : }
977 :
978 : /*
979 : * skip - skip white space and comments in expanded form
980 : */
981 : static void
982 1658 : skip(struct vars *v)
983 : {
984 1658 : const chr *start = v->now;
985 :
986 : assert(v->cflags & REG_EXPANDED);
987 :
988 : for (;;)
989 : {
990 2684 : while (!ATEOS() && iscspace(*v->now))
991 886 : v->now++;
992 1798 : if (ATEOS() || *v->now != CHR('#'))
993 : break; /* NOTE BREAK OUT */
994 : assert(NEXT1('#'));
995 1408 : while (!ATEOS() && *v->now != CHR('\n'))
996 1268 : v->now++;
997 : /* leave the newline to be picked up by the iscspace loop */
998 : }
999 :
1000 1658 : if (v->now != start)
1001 206 : NOTE(REG_UNONPOSIX);
1002 1658 : }
1003 :
1004 : /*
1005 : * newline - return the chr for a newline
1006 : *
1007 : * This helps confine use of CHR to this source file.
1008 : */
1009 : static chr
1010 572 : newline(void)
1011 : {
1012 572 : return CHR('\n');
1013 : }
1014 :
1015 : /*
1016 : * chrnamed - return the chr known by a given (chr string) name
1017 : *
1018 : * The code is a bit clumsy, but this routine gets only such specialized
1019 : * use that it hardly matters.
1020 : */
1021 : static chr
1022 4 : chrnamed(struct vars *v,
1023 : const chr *startp, /* start of name */
1024 : const chr *endp, /* just past end of name */
1025 : chr lastresort) /* what to return if name lookup fails */
1026 : {
1027 : chr c;
1028 : int errsave;
1029 : int e;
1030 : struct cvec *cv;
1031 :
1032 4 : errsave = v->err;
1033 4 : v->err = 0;
1034 4 : c = element(v, startp, endp);
1035 4 : e = v->err;
1036 4 : v->err = errsave;
1037 :
1038 4 : if (e != 0)
1039 0 : return lastresort;
1040 :
1041 4 : cv = range(v, c, c, 0);
1042 4 : if (cv->nchrs == 0)
1043 4 : return lastresort;
1044 0 : return cv->chrs[0];
1045 : }
|