LCOV - code coverage report
Current view: top level - src/backend/regex - regc_lex.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 95.0 % 543 516
Test Date: 2026-02-28 05:14:31 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            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         4182 : lexstart(struct vars *v)
      71              : {
      72         4182 :     prefixes(v);                /* may turn on new type bits etc. */
      73         4182 :     NOERR();
      74              : 
      75         4179 :     if (v->cflags & REG_QUOTE)
      76              :     {
      77              :         assert(!(v->cflags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)));
      78           48 :         INTOCON(L_Q);
      79              :     }
      80         4131 :     else if (v->cflags & REG_EXTENDED)
      81              :     {
      82              :         assert(!(v->cflags & REG_QUOTE));
      83         4003 :         INTOCON(L_ERE);
      84              :     }
      85              :     else
      86              :     {
      87              :         assert(!(v->cflags & (REG_QUOTE | REG_ADVF)));
      88          128 :         INTOCON(L_BRE);
      89              :     }
      90              : 
      91         4179 :     v->nexttype = EMPTY;     /* remember we were at the start */
      92         4179 :     next(v);                    /* set up the first token */
      93              : }
      94              : 
      95              : /*
      96              :  * prefixes - implement various special prefixes
      97              :  */
      98              : static void
      99         4182 : prefixes(struct vars *v)
     100              : {
     101              :     /* literal string doesn't get any of this stuff */
     102         4182 :     if (v->cflags & REG_QUOTE)
     103           41 :         return;
     104              : 
     105              :     /* initial "***" gets special things */
     106         4141 :     if (HAVE(4) && NEXT3('*', '*', '*'))
     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;
     125            0 :             default:            /* otherwise *** is just an error */
     126            0 :                 ERR(REG_BADRPT);
     127            0 :                 return;
     128              :                 break;
     129              :         }
     130              : 
     131              :     /* BREs and EREs don't get embedded options */
     132         4137 :     if ((v->cflags & REG_ADVANCED) != REG_ADVANCED)
     133          133 :         return;
     134              : 
     135              :     /* embedded options (AREs only) */
     136         4004 :     if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2)))
     137              :     {
     138           28 :         NOTE(REG_UNONPOSIX);
     139           28 :         v->now += 2;
     140           60 :         for (; !ATEOS() && iscalpha(*v->now); v->now++)
     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              :         {
     187            0 :             ERR(REG_BADOPT);
     188            0 :             return;
     189              :         }
     190           27 :         v->now++;
     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 */
     200        75236 : next(struct vars *v)
     201              : {
     202              :     chr         c;
     203              : 
     204        75237 : next_restart:                   /* loop here after eating a comment */
     205              : 
     206              :     /* errors yield an infinite sequence of failures */
     207        75237 :     if (ISERR())
     208           68 :         return 0;               /* the error has set nexttype to EOS */
     209              : 
     210              :     /* remember flavor of last token */
     211        75169 :     v->lasttype = v->nexttype;
     212              : 
     213              :     /* REG_BOSONLY */
     214        75169 :     if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
     215              :     {
     216              :         /* at start of a REG_BOSONLY RE */
     217            2 :         RETV(SBEGIN, 0);        /* same as \A */
     218              :     }
     219              : 
     220              :     /* skip white space etc. if appropriate (not in literal or []) */
     221        75167 :     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        75167 :     if (ATEOS())
     234              :     {
     235         4087 :         switch (v->lexcon)
     236              :         {
     237         4071 :             case L_ERE:
     238              :             case L_BRE:
     239              :             case L_Q:
     240         4071 :                 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              :         }
     253              :         assert(NOTREACHED);
     254              :     }
     255              : 
     256              :     /* okay, time to actually get a character */
     257        71080 :     c = *v->now++;
     258              : 
     259              :     /* deal with the easy contexts, punt EREs to code below */
     260        71080 :     switch (v->lexcon)
     261              :     {
     262          322 :         case L_BRE:             /* punt BREs to separate function */
     263          322 :             return brenext(v, c);
     264              :             break;
     265        66371 :         case L_ERE:             /* see below */
     266        66371 :             break;
     267          247 :         case L_Q:               /* literal strings are easy */
     268          247 :             RETV(PLAIN, c);
     269              :             break;
     270          801 :         case L_BBND:            /* bounds are fairly simple */
     271              :         case L_EBND:
     272          801 :             switch (c)
     273              :             {
     274          419 :                 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          419 :                     RETV(DIGIT, (chr) DIGITVAL(c));
     285              :                     break;
     286          123 :                 case CHR(','):
     287          123 :                     RET(',');
     288              :                     break;
     289          255 :                 case CHR('}'):  /* ERE bound ends with } */
     290          255 :                     if (INCON(L_EBND))
     291              :                     {
     292          255 :                         INTOCON(L_ERE);
     293          255 :                         if ((v->cflags & REG_ADVF) && NEXT1('?'))
     294              :                         {
     295           45 :                             v->now++;
     296           45 :                             NOTE(REG_UNONPOSIX);
     297           45 :                             RETV('}', 0);
     298              :                         }
     299          210 :                         RETV('}', 1);
     300              :                     }
     301              :                     else
     302            0 :                         FAILW(REG_BADBR);
     303              :                     break;
     304            3 :                 case CHR('\\'): /* BRE bound ends with \} */
     305            3 :                     if (INCON(L_BBND) && NEXT1('}'))
     306              :                     {
     307            2 :                         v->now++;
     308            2 :                         INTOCON(L_BRE);
     309            2 :                         RETV('}', 1);
     310              :                     }
     311              :                     else
     312            1 :                         FAILW(REG_BADBR);
     313              :                     break;
     314            1 :                 default:
     315            1 :                     FAILW(REG_BADBR);
     316              :                     break;
     317              :             }
     318              :             assert(NOTREACHED);
     319              :             break;
     320         2392 :         case L_BRACK:           /* brackets are not too hard */
     321         2392 :             switch (c)
     322              :             {
     323          685 :                 case CHR(']'):
     324          685 :                     if (LASTTYPE('['))
     325            8 :                         RETV(PLAIN, c);
     326              :                     else
     327              :                     {
     328          677 :                         INTOCON((v->cflags & REG_EXTENDED) ?
     329              :                                 L_ERE : L_BRE);
     330          677 :                         RET(']');
     331              :                     }
     332              :                     break;
     333           77 :                 case CHR('\\'):
     334           77 :                     NOTE(REG_UBBS);
     335           77 :                     if (!(v->cflags & REG_ADVF))
     336            7 :                         RETV(PLAIN, c);
     337           70 :                     NOTE(REG_UNONPOSIX);
     338           70 :                     if (ATEOS())
     339            0 :                         FAILW(REG_EESCAPE);
     340           70 :                     if (!lexescape(v))
     341            0 :                         return 0;
     342           70 :                     switch (v->nexttype)
     343              :                     {           /* not all escapes okay here */
     344           69 :                         case PLAIN:
     345              :                         case CCLASSS:
     346              :                         case CCLASSC:
     347           69 :                             return 1;
     348              :                             break;
     349              :                     }
     350              :                     /* not one of the acceptable escapes */
     351            1 :                     FAILW(REG_EESCAPE);
     352              :                     break;
     353          327 :                 case CHR('-'):
     354          327 :                     if (LASTTYPE('[') || NEXT1(']'))
     355            8 :                         RETV(PLAIN, c);
     356              :                     else
     357          319 :                         RETV(RANGE, c);
     358              :                     break;
     359          193 :                 case CHR('['):
     360          193 :                     if (ATEOS())
     361            0 :                         FAILW(REG_EBRACK);
     362          193 :                     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          154 :                         case CHR(':'):
     375          154 :                             INTOCON(L_CCL);
     376          154 :                             NOTE(REG_ULOCALE);
     377          154 :                             RET(CCLASS);
     378              :                             break;
     379           11 :                         default:    /* oops */
     380           11 :                             v->now--;
     381           11 :                             RETV(PLAIN, c);
     382              :                             break;
     383              :                     }
     384              :                     assert(NOTREACHED);
     385              :                     break;
     386         1110 :                 default:
     387         1110 :                     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
     410           12 :                 RETV(PLAIN, c);
     411              :             break;
     412          891 :         case L_CCL:             /* ditto character classes */
     413          891 :             if (c == CHR(':') && NEXT1(']'))
     414              :             {
     415          149 :                 v->now++;
     416          149 :                 INTOCON(L_BRACK);
     417          149 :                 RETV(END, ':');
     418              :             }
     419              :             else
     420          742 :                 RETV(PLAIN, c);
     421              :             break;
     422            0 :         default:
     423              :             assert(NOTREACHED);
     424            0 :             break;
     425              :     }
     426              : 
     427              :     /* that got rid of everything except EREs and AREs */
     428              :     assert(INCON(L_ERE));
     429              : 
     430              :     /* deal with EREs and AREs, except for backslashes */
     431        66371 :     switch (c)
     432              :     {
     433          314 :         case CHR('|'):
     434          314 :             RET('|');
     435              :             break;
     436        10674 :         case CHR('*'):
     437        10674 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     438              :             {
     439           27 :                 v->now++;
     440           27 :                 NOTE(REG_UNONPOSIX);
     441           27 :                 RETV('*', 0);
     442              :             }
     443        10647 :             RETV('*', 1);
     444              :             break;
     445          477 :         case CHR('+'):
     446          477 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     447              :             {
     448           22 :                 v->now++;
     449           22 :                 NOTE(REG_UNONPOSIX);
     450           22 :                 RETV('+', 0);
     451              :             }
     452          455 :             RETV('+', 1);
     453              :             break;
     454           68 :         case CHR('?'):
     455           68 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     456              :             {
     457            2 :                 v->now++;
     458            2 :                 NOTE(REG_UNONPOSIX);
     459            2 :                 RETV('?', 0);
     460              :             }
     461           66 :             RETV('?', 1);
     462              :             break;
     463          263 :         case CHR('{'):          /* bounds start or plain character */
     464          263 :             if (v->cflags & REG_EXPANDED)
     465           16 :                 skip(v);
     466          263 :             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          259 :                 NOTE(REG_UBOUNDS);
     475          259 :                 INTOCON(L_EBND);
     476          259 :                 RET('{');
     477              :             }
     478              :             assert(NOTREACHED);
     479              :             break;
     480         2810 :         case CHR('('):          /* parenthesis, or advanced extension */
     481         2810 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     482              :             {
     483          282 :                 NOTE(REG_UNONPOSIX);
     484          282 :                 v->now++;
     485          282 :                 if (ATEOS())
     486            0 :                     FAILW(REG_BADRPT);
     487          282 :                 switch (*v->now++)
     488              :                 {
     489          146 :                     case CHR(':'):  /* non-capturing paren */
     490          146 :                         RETV('(', 0);
     491              :                         break;
     492            1 :                     case CHR('#'):  /* comment */
     493            8 :                         while (!ATEOS() && *v->now != CHR(')'))
     494            7 :                             v->now++;
     495            1 :                         if (!ATEOS())
     496            1 :                             v->now++;
     497              :                         assert(v->nexttype == v->lasttype);
     498            1 :                         goto next_restart;
     499           42 :                     case CHR('='):  /* positive lookahead */
     500           42 :                         NOTE(REG_ULOOKAROUND);
     501           42 :                         RETV(LACON, LATYPE_AHEAD_POS);
     502              :                         break;
     503           39 :                     case CHR('!'):  /* negative lookahead */
     504           39 :                         NOTE(REG_ULOOKAROUND);
     505           39 :                         RETV(LACON, LATYPE_AHEAD_NEG);
     506              :                         break;
     507           53 :                     case CHR('<'):
     508           53 :                         if (ATEOS())
     509            0 :                             FAILW(REG_BADRPT);
     510           53 :                         switch (*v->now++)
     511              :                         {
     512           39 :                             case CHR('='):  /* positive lookbehind */
     513           39 :                                 NOTE(REG_ULOOKAROUND);
     514           39 :                                 RETV(LACON, LATYPE_BEHIND_POS);
     515              :                                 break;
     516           14 :                             case CHR('!'):  /* negative lookbehind */
     517           14 :                                 NOTE(REG_ULOOKAROUND);
     518           14 :                                 RETV(LACON, LATYPE_BEHIND_NEG);
     519              :                                 break;
     520            0 :                             default:
     521            0 :                                 FAILW(REG_BADRPT);
     522              :                                 break;
     523              :                         }
     524              :                         assert(NOTREACHED);
     525              :                         break;
     526            1 :                     default:
     527            1 :                         FAILW(REG_BADRPT);
     528              :                         break;
     529              :                 }
     530              :                 assert(NOTREACHED);
     531              :             }
     532         2528 :             RETV('(', 1);
     533              :             break;
     534         2777 :         case CHR(')'):
     535         2777 :             if (LASTTYPE('('))
     536           29 :                 NOTE(REG_UUNSPEC);
     537         2777 :             RETV(')', c);
     538              :             break;
     539          646 :         case CHR('['):          /* easy except for [[:<:]] and [[:>:]] */
     540          646 :             if (HAVE(6) && *(v->now + 0) == CHR('[') &&
     541          153 :                 *(v->now + 1) == CHR(':') &&
     542          137 :                 (*(v->now + 2) == CHR('<') ||
     543          132 :                  *(v->now + 2) == CHR('>')) &&
     544           10 :                 *(v->now + 3) == CHR(':') &&
     545           10 :                 *(v->now + 4) == CHR(']') &&
     546           10 :                 *(v->now + 5) == CHR(']'))
     547              :             {
     548           10 :                 c = *(v->now + 2);
     549           10 :                 v->now += 6;
     550           10 :                 NOTE(REG_UNONPOSIX);
     551           10 :                 RET((c == CHR('<')) ? '<' : '>');
     552              :             }
     553          636 :             INTOCON(L_BRACK);
     554          636 :             if (NEXT1('^'))
     555              :             {
     556          135 :                 v->now++;
     557          135 :                 RETV('[', 0);
     558              :             }
     559          501 :             RETV('[', 1);
     560              :             break;
     561         1622 :         case CHR('.'):
     562         1622 :             RET('.');
     563              :             break;
     564         2766 :         case CHR('^'):
     565         2766 :             RET('^');
     566              :             break;
     567         2270 :         case CHR('$'):
     568         2270 :             RET('$');
     569              :             break;
     570         1216 :         case CHR('\\'):         /* mostly punt backslashes to code below */
     571         1216 :             if (ATEOS())
     572            1 :                 FAILW(REG_EESCAPE);
     573         1215 :             break;
     574        40468 :         default:                /* ordinary character */
     575        40468 :             RETV(PLAIN, c);
     576              :             break;
     577              :     }
     578              : 
     579              :     /* ERE/ARE backslash handling; backslash already eaten */
     580              :     assert(!ATEOS());
     581         1215 :     if (!(v->cflags & REG_ADVF))
     582              :     {                           /* only AREs have non-trivial escapes */
     583            4 :         if (iscalnum(*v->now))
     584              :         {
     585            3 :             NOTE(REG_UBSALNUM);
     586            3 :             NOTE(REG_UUNSPEC);
     587              :         }
     588            4 :         RETV(PLAIN, *v->now++);
     589              :     }
     590         1211 :     return lexescape(v);
     591              : }
     592              : 
     593              : /*
     594              :  * lexescape - parse an ARE backslash escape (backslash already eaten)
     595              :  *
     596              :  * This is used for ARE backslashes both normally and inside bracket
     597              :  * expressions.  In the latter case, not all escape types are allowed,
     598              :  * but the caller must reject unwanted ones after we return.
     599              :  */
     600              : static int
     601         1281 : lexescape(struct vars *v)
     602              : {
     603              :     chr         c;
     604              :     static const chr alert[] = {
     605              :         CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
     606              :     };
     607              :     static const chr esc[] = {
     608              :         CHR('E'), CHR('S'), CHR('C')
     609              :     };
     610              :     const chr  *save;
     611              : 
     612              :     assert(v->cflags & REG_ADVF);
     613              : 
     614              :     assert(!ATEOS());
     615         1281 :     c = *v->now++;
     616              : 
     617              :     /* if it's not alphanumeric ASCII, treat it as a plain character */
     618         1281 :     if (!('a' <= c && c <= 'z') &&
     619          960 :         !('A' <= c && c <= 'Z') &&
     620          383 :         !('0' <= c && c <= '9'))
     621          733 :         RETV(PLAIN, c);
     622              : 
     623          548 :     NOTE(REG_UNONPOSIX);
     624          548 :     switch (c)
     625              :     {
     626            4 :         case CHR('a'):
     627            4 :             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())
     641            0 :                 FAILW(REG_EESCAPE);
     642            2 :             RETV(PLAIN, (chr) (*v->now++ & 037));
     643              :             break;
     644          145 :         case CHR('d'):
     645          145 :             NOTE(REG_ULOCALE);
     646          145 :             RETV(CCLASSS, CC_DIGIT);
     647              :             break;
     648           14 :         case CHR('D'):
     649           14 :             NOTE(REG_ULOCALE);
     650           14 :             RETV(CCLASSC, CC_DIGIT);
     651              :             break;
     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           19 :         case CHR('m'):
     660           19 :             RET('<');
     661              :             break;
     662           16 :         case CHR('M'):
     663           16 :             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);
     673           28 :             RETV(CCLASSS, CC_SPACE);
     674              :             break;
     675           17 :         case CHR('S'):
     676           17 :             NOTE(REG_ULOCALE);
     677           17 :             RETV(CCLASSC, CC_SPACE);
     678              :             break;
     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);
     684           28 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     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);
     690           10 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     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);
     699           50 :             RETV(CCLASSS, CC_WORD);
     700              :             break;
     701            8 :         case CHR('W'):
     702            8 :             NOTE(REG_ULOCALE);
     703            8 :             RETV(CCLASSC, CC_WORD);
     704              :             break;
     705            6 :         case CHR('x'):
     706            6 :             NOTE(REG_UUNPORT);
     707            6 :             c = lexdigits(v, 16, 1, 255);   /* REs >255 long outside spec */
     708            6 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     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 */
     734          116 :             c = lexdigits(v, 10, 1, 255);   /* REs >255 long outside spec */
     735          116 :             if (ISERR())
     736            0 :                 FAILW(REG_EESCAPE);
     737              :             /* ugly heuristic (first test is "exactly 1 digit?") */
     738          116 :             if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
     739              :             {
     740          111 :                 NOTE(REG_UBACKREF);
     741          111 :                 RETV(BACKREF, c);
     742              :             }
     743              :             /* oops, doesn't look like it's a backref after all... */
     744            5 :             v->now = save;
     745              :             /* and fall through into octal number */
     746              :             pg_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())
     752            0 :                 FAILW(REG_EESCAPE);
     753           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              :             }
     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              :              */
     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 */
     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;
     789          170 :     const uchr  ub = (uchr) base;
     790              : 
     791          170 :     n = 0;
     792          543 :     for (len = 0; len < maxlen && !ATEOS(); len++)
     793              :     {
     794          460 :         c = *v->now++;
     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;
     809            0 :             case CHR('a'):
     810              :             case CHR('A'):
     811            0 :                 d = 10;
     812            0 :                 break;
     813            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;
     821            0 :             case CHR('d'):
     822              :             case CHR('D'):
     823            0 :                 d = 13;
     824            0 :                 break;
     825            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 */
     841           11 :             v->now--;
     842           11 :             d = -1;
     843              :         }
     844          460 :         if (d < 0)
     845           87 :             break;              /* NOTE BREAK OUT */
     846          373 :         n = n * ub + (uchr) d;
     847              :     }
     848          170 :     if (len < minlen)
     849            7 :         ERR(REG_EESCAPE);
     850              : 
     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 */
     861          322 : brenext(struct vars *v,
     862              :         chr c)
     863              : {
     864          322 :     switch (c)
     865              :     {
     866           23 :         case CHR('*'):
     867           23 :             if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
     868            6 :                 RETV(PLAIN, c);
     869           17 :             RETV('*', 1);
     870              :             break;
     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              :             }
     904            3 :             RETV(PLAIN, c);
     905              :             break;
     906           15 :         case CHR('$'):
     907           15 :             if (v->cflags & REG_EXPANDED)
     908            0 :                 skip(v);
     909           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              : 
     925              :     assert(c == CHR('\\'));
     926              : 
     927           26 :     if (ATEOS())
     928            1 :         FAILW(REG_EESCAPE);
     929              : 
     930           25 :     c = *v->now++;
     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
     982          829 : skip(struct vars *v)
     983              : {
     984          829 :     const chr  *start = v->now;
     985              : 
     986              :     assert(v->cflags & REG_EXPANDED);
     987              : 
     988              :     for (;;)
     989              :     {
     990         1342 :         while (!ATEOS() && iscspace(*v->now))
     991          443 :             v->now++;
     992          899 :         if (ATEOS() || *v->now != CHR('#'))
     993              :             break;              /* NOTE BREAK OUT */
     994              :         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          335 : newline(void)
    1011              : {
    1012          335 :     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            5 : chrnamed(struct vars *v,
    1023              :          const chr *startp,     /* start of name */
    1024              :          const chr *endp,       /* just past end of name */
    1025              :          chr lastresort)        /* what to return if name lookup fails */
    1026              : {
    1027              :     chr         c;
    1028              :     int         errsave;
    1029              :     int         e;
    1030              :     struct cvec *cv;
    1031              : 
    1032            5 :     errsave = v->err;
    1033            5 :     v->err = 0;
    1034            5 :     c = element(v, startp, endp);
    1035            5 :     e = v->err;
    1036            5 :     v->err = errsave;
    1037              : 
    1038            5 :     if (e != 0)
    1039            0 :         return lastresort;
    1040              : 
    1041            5 :     cv = range(v, c, c, 0);
    1042            5 :     if (cv->nchrs == 0)
    1043            5 :         return lastresort;
    1044            0 :     return cv->chrs[0];
    1045              : }
        

Generated by: LCOV version 2.0-1