Age Owner Branch data 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
2489 tgl@sss.pgh.pa.us 70 :CBC 3610 : lexstart(struct vars *v)
71 : : {
7559 bruce@momjian.us 72 : 3610 : prefixes(v); /* may turn on new type bits etc. */
7739 tgl@sss.pgh.pa.us 73 [ + + ]: 3610 : NOERR();
74 : :
7559 bruce@momjian.us 75 [ + + ]: 3607 : if (v->cflags & REG_QUOTE)
76 : : {
77 [ - + ]: 48 : assert(!(v->cflags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)));
7739 tgl@sss.pgh.pa.us 78 : 48 : INTOCON(L_Q);
79 : : }
7559 bruce@momjian.us 80 [ + + ]: 3559 : else if (v->cflags & REG_EXTENDED)
81 : : {
82 [ - + ]: 3431 : assert(!(v->cflags & REG_QUOTE));
7739 tgl@sss.pgh.pa.us 83 : 3431 : INTOCON(L_ERE);
84 : : }
85 : : else
86 : : {
7559 bruce@momjian.us 87 [ - + ]: 128 : assert(!(v->cflags & (REG_QUOTE | REG_ADVF)));
7739 tgl@sss.pgh.pa.us 88 : 128 : INTOCON(L_BRE);
89 : : }
90 : :
91 : 3607 : v->nexttype = EMPTY; /* remember we were at the start */
7559 bruce@momjian.us 92 : 3607 : next(v); /* set up the first token */
93 : : }
94 : :
95 : : /*
96 : : * prefixes - implement various special prefixes
97 : : */
98 : : static void
2489 tgl@sss.pgh.pa.us 99 : 3610 : prefixes(struct vars *v)
100 : : {
101 : : /* literal string doesn't get any of this stuff */
7559 bruce@momjian.us 102 [ + + ]: 3610 : if (v->cflags & REG_QUOTE)
7739 tgl@sss.pgh.pa.us 103 : 41 : return;
104 : :
105 : : /* initial "***" gets special things */
106 [ + + + - : 3569 : if (HAVE(4) && NEXT3('*', '*', '*'))
+ + + - +
- ]
7559 bruce@momjian.us 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;
7559 bruce@momjian.us 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 */
7559 bruce@momjian.us 132 [ + + ]:CBC 3565 : if ((v->cflags & REG_ADVANCED) != REG_ADVANCED)
7739 tgl@sss.pgh.pa.us 133 : 133 : return;
134 : :
135 : : /* embedded options (AREs only) */
7559 bruce@momjian.us 136 [ + + + - : 3432 : if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2)))
+ + + + +
+ ]
137 : : {
7739 tgl@sss.pgh.pa.us 138 : 28 : NOTE(REG_UNONPOSIX);
139 : 28 : v->now += 2;
140 [ + - + + ]: 60 : for (; !ATEOS() && iscalpha(*v->now); v->now++)
7559 bruce@momjian.us 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 : : {
7739 tgl@sss.pgh.pa.us 187 [ # # ]:UBC 0 : ERR(REG_BADOPT);
188 : 0 : return;
189 : : }
7739 tgl@sss.pgh.pa.us 190 :CBC 27 : v->now++;
7559 bruce@momjian.us 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 */
2489 tgl@sss.pgh.pa.us 200 : 67865 : next(struct vars *v)
201 : : {
202 : : chr c;
203 : :
599 204 : 67866 : next_restart: /* loop here after eating a comment */
205 : :
206 : : /* errors yield an infinite sequence of failures */
7739 207 [ + + ]: 67866 : if (ISERR())
7559 bruce@momjian.us 208 : 68 : return 0; /* the error has set nexttype to EOS */
209 : :
210 : : /* remember flavor of last token */
7739 tgl@sss.pgh.pa.us 211 : 67798 : v->lasttype = v->nexttype;
212 : :
213 : : /* REG_BOSONLY */
7559 bruce@momjian.us 214 [ + + + + ]: 67798 : if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
215 : : {
216 : : /* at start of a REG_BOSONLY RE */
7739 tgl@sss.pgh.pa.us 217 : 2 : RETV(SBEGIN, 0); /* same as \A */
218 : : }
219 : :
220 : : /* skip white space etc. if appropriate (not in literal or []) */
7559 bruce@momjian.us 221 [ + + ]: 67796 : 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 [ + + ]: 67796 : if (ATEOS())
234 : : {
235 [ + + + - ]: 3515 : switch (v->lexcon)
236 : : {
237 : 3499 : case L_ERE:
238 : : case L_BRE:
239 : : case L_Q:
240 : 3499 : 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 : : }
7739 tgl@sss.pgh.pa.us 253 :UBC 0 : assert(NOTREACHED);
254 : : }
255 : :
256 : : /* okay, time to actually get a character */
7739 tgl@sss.pgh.pa.us 257 :CBC 64281 : c = *v->now++;
258 : :
259 : : /* deal with the easy contexts, punt EREs to code below */
7559 bruce@momjian.us 260 [ + + + + : 64281 : switch (v->lexcon)
+ + + +
- ]
261 : : {
262 : 322 : case L_BRE: /* punt BREs to separate function */
263 : 322 : return brenext(v, c);
264 : : break;
265 : 60097 : case L_ERE: /* see below */
7739 tgl@sss.pgh.pa.us 266 : 60097 : break;
7559 bruce@momjian.us 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
7559 bruce@momjian.us 302 [ # # ]:UBC 0 : FAILW(REG_BADBR);
303 : : break;
2489 tgl@sss.pgh.pa.us 304 :CBC 3 : case CHR('\\'): /* BRE bound ends with \} */
7559 bruce@momjian.us 305 [ + + + - : 3 : if (INCON(L_BBND) && NEXT1('}'))
+ - ]
306 : : {
307 : 2 : v->now++;
308 : 2 : INTOCON(L_BRE);
1151 tgl@sss.pgh.pa.us 309 : 2 : RETV('}', 1);
310 : : }
311 : : else
7559 bruce@momjian.us 312 [ - + ]: 1 : FAILW(REG_BADBR);
313 : : break;
314 : 1 : default:
315 [ - + ]: 1 : FAILW(REG_BADBR);
316 : : break;
317 : : }
318 : : assert(NOTREACHED);
319 : : break;
320 [ + + + + : 2075 : case L_BRACK: /* brackets are not too hard */
+ ]
321 : : switch (c)
322 : : {
323 : 586 : case CHR(']'):
324 [ + + ]: 586 : if (LASTTYPE('['))
325 : 2 : RETV(PLAIN, c);
326 : : else
327 : : {
328 [ + + ]: 584 : INTOCON((v->cflags & REG_EXTENDED) ?
329 : : L_ERE : L_BRE);
330 : 584 : 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())
7559 bruce@momjian.us 339 [ # # ]:UBC 0 : FAILW(REG_EESCAPE);
1144 tgl@sss.pgh.pa.us 340 [ - + ]:CBC 57 : if (!lexescape(v))
1144 tgl@sss.pgh.pa.us 341 :UBC 0 : return 0;
7559 bruce@momjian.us 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 : 296 : case CHR('-'):
354 [ + + + + : 296 : if (LASTTYPE('[') || NEXT1(']'))
+ + ]
355 : 8 : RETV(PLAIN, c);
356 : : else
357 : 288 : RETV(RANGE, c);
358 : : break;
359 : 151 : case CHR('['):
360 [ - + ]: 151 : if (ATEOS())
7559 bruce@momjian.us 361 [ # # ]:UBC 0 : FAILW(REG_EBRACK);
7559 bruce@momjian.us 362 [ + + + + ]:CBC 151 : 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 : 121 : case CHR(':'):
375 : 121 : INTOCON(L_CCL);
376 : 121 : NOTE(REG_ULOCALE);
377 : 121 : RET(CCLASS);
378 : : break;
2489 tgl@sss.pgh.pa.us 379 : 2 : default: /* oops */
7559 bruce@momjian.us 380 : 2 : v->now--;
381 : 2 : RETV(PLAIN, c);
382 : : break;
383 : : }
384 : : assert(NOTREACHED);
385 : : break;
7739 tgl@sss.pgh.pa.us 386 : 978 : default:
7559 bruce@momjian.us 387 : 978 : 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
7739 tgl@sss.pgh.pa.us 410 : 12 : RETV(PLAIN, c);
411 : : break;
7559 bruce@momjian.us 412 : 693 : case L_CCL: /* ditto character classes */
413 [ + + + - : 693 : if (c == CHR(':') && NEXT1(']'))
+ - ]
414 : : {
415 : 116 : v->now++;
416 : 116 : INTOCON(L_BRACK);
417 : 116 : RETV(END, ':');
418 : : }
419 : : else
420 : 577 : RETV(PLAIN, c);
421 : : break;
7739 tgl@sss.pgh.pa.us 422 :UBC 0 : default:
7559 bruce@momjian.us 423 : 0 : assert(NOTREACHED);
424 : : break;
425 : : }
426 : :
427 : : /* that got rid of everything except EREs and AREs */
7739 tgl@sss.pgh.pa.us 428 [ - + ]:CBC 60097 : assert(INCON(L_ERE));
429 : :
430 : : /* deal with EREs and AREs, except for backslashes */
7559 bruce@momjian.us 431 [ + + + + : 60097 : switch (c)
+ + + + +
+ + + + ]
432 : : {
433 : 309 : case CHR('|'):
434 : 309 : RET('|');
435 : : break;
436 : 10561 : case CHR('*'):
437 [ + - + + : 10561 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
+ + ]
438 : : {
439 : 27 : v->now++;
440 : 27 : NOTE(REG_UNONPOSIX);
441 : 27 : RETV('*', 0);
442 : : }
443 : 10534 : RETV('*', 1);
444 : : break;
445 : 442 : case CHR('+'):
446 [ + + + + : 442 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
+ + ]
447 : : {
448 : 22 : v->now++;
449 : 22 : NOTE(REG_UNONPOSIX);
450 : 22 : RETV('+', 0);
451 : : }
452 : 420 : 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 : 2578 : case CHR('('): /* parenthesis, or advanced extension */
481 [ + + + - : 2578 : if ((v->cflags & REG_ADVF) && NEXT1('?'))
+ + ]
482 : : {
483 : 242 : NOTE(REG_UNONPOSIX);
484 : 242 : v->now++;
3089 tgl@sss.pgh.pa.us 485 [ - + ]: 242 : if (ATEOS())
3089 tgl@sss.pgh.pa.us 486 [ # # ]:UBC 0 : FAILW(REG_BADRPT);
7559 bruce@momjian.us 487 [ + + + + :CBC 242 : switch (*v->now++)
+ + ]
488 : : {
2489 tgl@sss.pgh.pa.us 489 : 106 : case CHR(':'): /* non-capturing paren */
7559 bruce@momjian.us 490 : 106 : RETV('(', 0);
491 : : break;
2489 tgl@sss.pgh.pa.us 492 : 1 : case CHR('#'): /* comment */
7559 bruce@momjian.us 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);
599 tgl@sss.pgh.pa.us 498 : 1 : goto next_restart;
2489 499 : 42 : case CHR('='): /* positive lookahead */
3089 500 : 42 : NOTE(REG_ULOOKAROUND);
501 : 42 : RETV(LACON, LATYPE_AHEAD_POS);
502 : : break;
2489 503 : 39 : case CHR('!'): /* negative lookahead */
3089 504 : 39 : NOTE(REG_ULOOKAROUND);
505 : 39 : RETV(LACON, LATYPE_AHEAD_NEG);
506 : : break;
507 : 53 : case CHR('<'):
508 [ - + ]: 53 : if (ATEOS())
3089 tgl@sss.pgh.pa.us 509 [ # # ]:UBC 0 : FAILW(REG_BADRPT);
3089 tgl@sss.pgh.pa.us 510 [ + + - ]:CBC 53 : switch (*v->now++)
511 : : {
2489 512 : 39 : case CHR('='): /* positive lookbehind */
3089 513 : 39 : NOTE(REG_ULOOKAROUND);
514 : 39 : RETV(LACON, LATYPE_BEHIND_POS);
515 : : break;
2489 516 : 14 : case CHR('!'): /* negative lookbehind */
3089 517 : 14 : NOTE(REG_ULOOKAROUND);
518 : 14 : RETV(LACON, LATYPE_BEHIND_NEG);
519 : : break;
3089 tgl@sss.pgh.pa.us 520 :UBC 0 : default:
521 [ # # ]: 0 : FAILW(REG_BADRPT);
522 : : break;
523 : : }
524 : : assert(NOTREACHED);
525 : : break;
7559 bruce@momjian.us 526 :CBC 1 : default:
527 [ - + ]: 1 : FAILW(REG_BADRPT);
528 : : break;
529 : : }
530 : : assert(NOTREACHED);
531 : : }
979 tgl@sss.pgh.pa.us 532 : 2336 : RETV('(', 1);
533 : : break;
7559 bruce@momjian.us 534 : 2545 : case CHR(')'):
535 [ + + ]: 2545 : if (LASTTYPE('('))
536 : 23 : NOTE(REG_UUNSPEC);
537 : 2545 : RETV(')', c);
538 : : break;
539 : 553 : case CHR('['): /* easy except for [[:<:]] and [[:>:]] */
540 [ + + + + ]: 553 : if (HAVE(6) && *(v->now + 0) == CHR('[') &&
541 [ + + ]: 132 : *(v->now + 1) == CHR(':') &&
542 [ + + ]: 122 : (*(v->now + 2) == CHR('<') ||
543 [ + + ]: 117 : *(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 : 543 : INTOCON(L_BRACK);
554 [ + + + + ]: 543 : if (NEXT1('^'))
555 : : {
556 : 108 : v->now++;
557 : 108 : RETV('[', 0);
558 : : }
559 : 435 : RETV('[', 1);
560 : : break;
561 : 1521 : case CHR('.'):
562 : 1521 : RET('.');
563 : : break;
564 : 2270 : case CHR('^'):
565 : 2270 : RET('^');
566 : : break;
567 : 1995 : case CHR('$'):
568 : 1995 : RET('$');
569 : : break;
2489 tgl@sss.pgh.pa.us 570 : 1056 : case CHR('\\'): /* mostly punt backslashes to code below */
7559 bruce@momjian.us 571 [ + + ]: 1056 : if (ATEOS())
572 [ - + ]: 1 : FAILW(REG_EESCAPE);
573 : 1055 : break;
574 : 35948 : default: /* ordinary character */
575 : 35948 : RETV(PLAIN, c);
576 : : break;
577 : : }
578 : :
579 : : /* ERE/ARE backslash handling; backslash already eaten */
7739 tgl@sss.pgh.pa.us 580 [ - + ]: 1055 : assert(!ATEOS());
7559 bruce@momjian.us 581 [ + + ]: 1055 : if (!(v->cflags & REG_ADVF))
582 : : { /* only AREs have non-trivial escapes */
583 [ + + ]: 4 : if (iscalnum(*v->now))
584 : : {
7739 tgl@sss.pgh.pa.us 585 : 3 : NOTE(REG_UBSALNUM);
586 : 3 : NOTE(REG_UUNSPEC);
587 : : }
588 : 4 : RETV(PLAIN, *v->now++);
589 : : }
1144 590 : 1051 : 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
2489 601 : 1108 : 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 : :
7559 bruce@momjian.us 612 [ - + ]: 1108 : assert(v->cflags & REG_ADVF);
613 : :
7739 tgl@sss.pgh.pa.us 614 [ - + ]: 1108 : assert(!ATEOS());
615 : 1108 : c = *v->now++;
616 : :
617 : : /* if it's not alphanumeric ASCII, treat it as a plain character */
359 jdavis@postgresql.or 618 [ + + + + : 1108 : if (!('a' <= c && c <= 'z') &&
+ + ]
619 [ + + + + ]: 843 : !('A' <= c && c <= 'Z') &&
620 [ + + ]: 302 : !('0' <= c && c <= '9'))
7739 tgl@sss.pgh.pa.us 621 : 620 : RETV(PLAIN, c);
622 : :
623 : 488 : NOTE(REG_UNONPOSIX);
7559 bruce@momjian.us 624 [ + + + + : 488 : switch (c)
+ + + + +
+ + + + +
+ + + + +
+ + + + +
+ + + + ]
625 : : {
626 : 1 : case CHR('a'):
627 : 1 : RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
628 : : break;
629 : 11 : case CHR('A'):
630 : 11 : RETV(SBEGIN, 0);
631 : : break;
632 : 13 : case CHR('b'):
633 : 13 : RETV(PLAIN, CHR('\b'));
634 : : break;
635 : 5 : case CHR('B'):
636 : 5 : RETV(PLAIN, CHR('\\'));
637 : : break;
638 : 2 : case CHR('c'):
639 : 2 : NOTE(REG_UUNPORT);
640 [ - + ]: 2 : if (ATEOS())
7559 bruce@momjian.us 641 [ # # ]:UBC 0 : FAILW(REG_EESCAPE);
7559 bruce@momjian.us 642 :CBC 2 : RETV(PLAIN, (chr) (*v->now++ & 037));
643 : : break;
644 : 94 : case CHR('d'):
645 : 94 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 646 : 94 : RETV(CCLASSS, CC_DIGIT);
647 : : break;
7559 bruce@momjian.us 648 : 12 : case CHR('D'):
649 : 12 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 650 : 12 : RETV(CCLASSC, CC_DIGIT);
651 : : break;
7559 bruce@momjian.us 652 : 1 : case CHR('e'):
653 : 1 : NOTE(REG_UUNPORT);
654 : 1 : RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
655 : : break;
656 : 1 : case CHR('f'):
657 : 1 : RETV(PLAIN, CHR('\f'));
658 : : break;
659 : 17 : case CHR('m'):
660 : 17 : RET('<');
661 : : break;
662 : 14 : case CHR('M'):
663 : 14 : RET('>');
664 : : break;
665 : 6 : case CHR('n'):
666 : 6 : RETV(PLAIN, CHR('\n'));
667 : : break;
668 : 5 : case CHR('r'):
669 : 5 : RETV(PLAIN, CHR('\r'));
670 : : break;
671 : 28 : case CHR('s'):
672 : 28 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 673 : 28 : RETV(CCLASSS, CC_SPACE);
674 : : break;
7559 bruce@momjian.us 675 : 17 : case CHR('S'):
676 : 17 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 677 : 17 : RETV(CCLASSC, CC_SPACE);
678 : : break;
7559 bruce@momjian.us 679 : 2 : case CHR('t'):
680 : 2 : RETV(PLAIN, CHR('\t'));
681 : : break;
682 : 28 : case CHR('u'):
683 : 28 : c = lexdigits(v, 16, 4, 4);
2981 tgl@sss.pgh.pa.us 684 [ + + - + ]: 28 : if (ISERR() || !CHR_IS_IN_RANGE(c))
7559 bruce@momjian.us 685 [ + - ]: 1 : FAILW(REG_EESCAPE);
686 : 27 : RETV(PLAIN, c);
687 : : break;
688 : 10 : case CHR('U'):
689 : 10 : c = lexdigits(v, 16, 8, 8);
2981 tgl@sss.pgh.pa.us 690 [ + + - + ]: 10 : if (ISERR() || !CHR_IS_IN_RANGE(c))
7559 bruce@momjian.us 691 [ + - ]: 5 : FAILW(REG_EESCAPE);
692 : 5 : RETV(PLAIN, c);
693 : : break;
694 : 1 : case CHR('v'):
695 : 1 : RETV(PLAIN, CHR('\v'));
696 : : break;
697 : 50 : case CHR('w'):
698 : 50 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 699 : 50 : RETV(CCLASSS, CC_WORD);
700 : : break;
7559 bruce@momjian.us 701 : 8 : case CHR('W'):
702 : 8 : NOTE(REG_ULOCALE);
1144 tgl@sss.pgh.pa.us 703 : 8 : RETV(CCLASSC, CC_WORD);
704 : : break;
7559 bruce@momjian.us 705 : 6 : case CHR('x'):
706 : 6 : NOTE(REG_UUNPORT);
2489 tgl@sss.pgh.pa.us 707 : 6 : c = lexdigits(v, 16, 1, 255); /* REs >255 long outside spec */
2981 708 [ + + + + ]: 6 : if (ISERR() || !CHR_IS_IN_RANGE(c))
7559 bruce@momjian.us 709 [ + + ]: 4 : FAILW(REG_EESCAPE);
710 : 2 : RETV(PLAIN, c);
711 : : break;
712 : 9 : case CHR('y'):
713 : 9 : NOTE(REG_ULOCALE);
714 : 9 : RETV(WBDRY, 0);
715 : : break;
716 : 19 : case CHR('Y'):
717 : 19 : NOTE(REG_ULOCALE);
718 : 19 : RETV(NWBDRY, 0);
719 : : break;
720 : 6 : case CHR('Z'):
721 : 6 : RETV(SEND, 0);
722 : : break;
723 : 116 : 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 : 116 : save = v->now;
733 : 116 : v->now--; /* put first digit back */
2489 tgl@sss.pgh.pa.us 734 : 116 : c = lexdigits(v, 10, 1, 255); /* REs >255 long outside spec */
7559 bruce@momjian.us 735 [ - + ]: 116 : if (ISERR())
7559 bruce@momjian.us 736 [ # # ]:UBC 0 : FAILW(REG_EESCAPE);
737 : : /* ugly heuristic (first test is "exactly 1 digit?") */
4916 tgl@sss.pgh.pa.us 738 [ + + + + :CBC 116 : if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
+ + ]
739 : : {
7559 bruce@momjian.us 740 : 111 : NOTE(REG_UBACKREF);
2795 tgl@sss.pgh.pa.us 741 : 111 : RETV(BACKREF, c);
742 : : }
743 : : /* oops, doesn't look like it's a backref after all... */
7559 bruce@momjian.us 744 : 5 : v->now = save;
745 : : /* and fall through into octal number */
746 : : /* FALLTHROUGH */
747 : 10 : case CHR('0'):
748 : 10 : NOTE(REG_UUNPORT);
749 : 10 : v->now--; /* put first digit back */
750 : 10 : c = lexdigits(v, 8, 1, 3);
751 [ - + ]: 10 : if (ISERR())
7559 bruce@momjian.us 752 [ # # ]:UBC 0 : FAILW(REG_EESCAPE);
3133 tgl@sss.pgh.pa.us 753 [ + + ]:CBC 10 : if (c > 0xff)
754 : : {
755 : : /* out of range, so we handled one digit too much */
756 : 1 : v->now--;
757 : 1 : c >>= 3;
758 : : }
7559 bruce@momjian.us 759 : 10 : RETV(PLAIN, c);
760 : : break;
761 : 1 : default:
762 : :
763 : : /*
764 : : * Throw an error for unrecognized ASCII alpha escape sequences,
765 : : * which reserves them for future use if needed.
766 : : */
359 jdavis@postgresql.or 767 [ - + ]: 1 : 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 */
2489 tgl@sss.pgh.pa.us 780 : 170 : 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;
7559 bruce@momjian.us 789 : 170 : const uchr ub = (uchr) base;
790 : :
7739 tgl@sss.pgh.pa.us 791 : 170 : n = 0;
7559 bruce@momjian.us 792 [ + + + + ]: 543 : for (len = 0; len < maxlen && !ATEOS(); len++)
793 : : {
7739 tgl@sss.pgh.pa.us 794 : 460 : c = *v->now++;
7559 bruce@momjian.us 795 [ + - + + : 460 : switch (c)
- + + + ]
796 : : {
797 : 343 : 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 : 343 : d = DIGITVAL(c);
808 : 343 : break;
7559 bruce@momjian.us 809 :UBC 0 : case CHR('a'):
810 : : case CHR('A'):
811 : 0 : d = 10;
812 : 0 : break;
7559 bruce@momjian.us 813 :CBC 8 : case CHR('b'):
814 : : case CHR('B'):
815 : 8 : d = 11;
816 : 8 : break;
817 : 2 : case CHR('c'):
818 : : case CHR('C'):
819 : 2 : d = 12;
820 : 2 : break;
7559 bruce@momjian.us 821 :UBC 0 : case CHR('d'):
822 : : case CHR('D'):
823 : 0 : d = 13;
824 : 0 : break;
7559 bruce@momjian.us 825 :CBC 2 : case CHR('e'):
826 : : case CHR('E'):
827 : 2 : d = 14;
828 : 2 : break;
829 : 29 : case CHR('f'):
830 : : case CHR('F'):
831 : 29 : d = 15;
832 : 29 : break;
833 : 76 : default:
834 : 76 : v->now--; /* oops, not a digit at all */
835 : 76 : d = -1;
836 : 76 : break;
837 : : }
838 : :
839 [ + + ]: 460 : if (d >= base)
840 : : { /* not a plausible digit */
7739 tgl@sss.pgh.pa.us 841 : 11 : v->now--;
842 : 11 : d = -1;
843 : : }
844 [ + + ]: 460 : if (d < 0)
7559 bruce@momjian.us 845 : 87 : break; /* NOTE BREAK OUT */
846 : 373 : n = n * ub + (uchr) d;
847 : : }
7739 tgl@sss.pgh.pa.us 848 [ + + ]: 170 : if (len < minlen)
849 [ - + ]: 7 : ERR(REG_EESCAPE);
850 : :
7559 bruce@momjian.us 851 : 170 : 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 */
2489 tgl@sss.pgh.pa.us 861 : 322 : brenext(struct vars *v,
862 : : chr c)
863 : : {
7559 bruce@momjian.us 864 [ + + + + : 322 : switch (c)
+ + + ]
865 : : {
866 : 23 : case CHR('*'):
867 [ + + + + : 23 : if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
+ + ]
868 : 6 : RETV(PLAIN, c);
1192 tgl@sss.pgh.pa.us 869 : 17 : RETV('*', 1);
870 : : break;
7559 bruce@momjian.us 871 : 74 : case CHR('['):
872 [ + + + + ]: 74 : if (HAVE(6) && *(v->now + 0) == CHR('[') &&
873 [ + + ]: 22 : *(v->now + 1) == CHR(':') &&
874 [ + + ]: 12 : (*(v->now + 2) == CHR('<') ||
875 [ + + ]: 8 : *(v->now + 2) == CHR('>')) &&
876 [ + - ]: 8 : *(v->now + 3) == CHR(':') &&
877 [ + - ]: 8 : *(v->now + 4) == CHR(']') &&
878 [ + - ]: 8 : *(v->now + 5) == CHR(']'))
879 : : {
880 : 8 : c = *(v->now + 2);
881 : 8 : v->now += 6;
882 : 8 : NOTE(REG_UNONPOSIX);
883 [ + + ]: 8 : RET((c == CHR('<')) ? '<' : '>');
884 : : }
885 : 66 : INTOCON(L_BRACK);
886 [ + + + + ]: 66 : if (NEXT1('^'))
887 : : {
888 : 6 : v->now++;
889 : 6 : RETV('[', 0);
890 : : }
891 : 60 : RETV('[', 1);
892 : : break;
893 : 4 : case CHR('.'):
894 : 4 : RET('.');
895 : : break;
896 : 18 : case CHR('^'):
897 [ + + ]: 18 : if (LASTTYPE(EMPTY))
898 : 14 : RET('^');
899 [ + + ]: 4 : if (LASTTYPE('('))
900 : : {
901 : 1 : NOTE(REG_UUNSPEC);
902 : 1 : RET('^');
903 : : }
7739 tgl@sss.pgh.pa.us 904 : 3 : RETV(PLAIN, c);
905 : : break;
7559 bruce@momjian.us 906 : 15 : case CHR('$'):
907 [ - + ]: 15 : if (v->cflags & REG_EXPANDED)
7559 bruce@momjian.us 908 :UBC 0 : skip(v);
7559 bruce@momjian.us 909 [ + + ]:CBC 15 : if (ATEOS())
910 : 11 : RET('$');
911 [ + + + - : 4 : if (NEXT2('\\', ')'))
+ - ]
912 : : {
913 : 1 : NOTE(REG_UUNSPEC);
914 : 1 : RET('$');
915 : : }
916 : 3 : RETV(PLAIN, c);
917 : : break;
918 : 26 : case CHR('\\'):
919 : 26 : break; /* see below */
920 : 162 : default:
921 : 162 : RETV(PLAIN, c);
922 : : break;
923 : : }
924 : :
7739 tgl@sss.pgh.pa.us 925 [ - + ]: 26 : assert(c == CHR('\\'));
926 : :
927 [ + + ]: 26 : if (ATEOS())
928 [ - + ]: 1 : FAILW(REG_EESCAPE);
929 : :
930 : 25 : c = *v->now++;
7559 bruce@momjian.us 931 [ + + + + : 25 : switch (c)
+ + + ]
932 : : {
933 : 3 : case CHR('{'):
934 : 3 : INTOCON(L_BBND);
935 : 3 : NOTE(REG_UBOUNDS);
936 : 3 : RET('{');
937 : : break;
938 : 6 : case CHR('('):
939 : 6 : RETV('(', 1);
940 : : break;
941 : 6 : case CHR(')'):
942 : 6 : RETV(')', c);
943 : : break;
944 : 3 : case CHR('<'):
945 : 3 : NOTE(REG_UNONPOSIX);
946 : 3 : RET('<');
947 : : break;
948 : 3 : case CHR('>'):
949 : 3 : NOTE(REG_UNONPOSIX);
950 : 3 : RET('>');
951 : : break;
952 : 2 : 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 : 2 : NOTE(REG_UBACKREF);
962 : 2 : RETV(BACKREF, (chr) DIGITVAL(c));
963 : : break;
964 : 2 : default:
965 [ + - ]: 2 : if (iscalnum(c))
966 : : {
967 : 2 : NOTE(REG_UBSALNUM);
968 : 2 : NOTE(REG_UUNSPEC);
969 : : }
970 : 2 : 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
2489 tgl@sss.pgh.pa.us 982 : 829 : skip(struct vars *v)
983 : : {
5904 984 : 829 : const chr *start = v->now;
985 : :
7559 bruce@momjian.us 986 [ + - ]: 829 : assert(v->cflags & REG_EXPANDED);
987 : :
988 : : for (;;)
989 : : {
7739 tgl@sss.pgh.pa.us 990 [ + + + + ]: 1342 : while (!ATEOS() && iscspace(*v->now))
991 : 443 : v->now++;
992 [ + + + + ]: 899 : if (ATEOS() || *v->now != CHR('#'))
993 : : break; /* NOTE BREAK OUT */
994 [ + - - + ]: 70 : assert(NEXT1('#'));
995 [ + - + + ]: 704 : while (!ATEOS() && *v->now != CHR('\n'))
996 : 634 : v->now++;
997 : : /* leave the newline to be picked up by the iscspace loop */
998 : : }
999 : :
1000 [ + + ]: 829 : if (v->now != start)
1001 : 103 : NOTE(REG_UNONPOSIX);
1002 : 829 : }
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 : 272 : newline(void)
1011 : : {
1012 : 272 : 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
2489 1022 : 2 : 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 : :
7739 1032 : 2 : errsave = v->err;
1033 : 2 : v->err = 0;
1034 : 2 : c = element(v, startp, endp);
1035 : 2 : e = v->err;
1036 : 2 : v->err = errsave;
1037 : :
1038 [ - + ]: 2 : if (e != 0)
2795 tgl@sss.pgh.pa.us 1039 :UBC 0 : return lastresort;
1040 : :
7739 tgl@sss.pgh.pa.us 1041 :CBC 2 : cv = range(v, c, c, 0);
1042 [ + - ]: 2 : if (cv->nchrs == 0)
2795 1043 : 2 : return lastresort;
7739 tgl@sss.pgh.pa.us 1044 :UBC 0 : return cv->chrs[0];
1045 : : }
|