Coverage Report

Created: 2026-08-14 06:37

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