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