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

Generated by: LCOV version 1.14