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