LCOV - code coverage report
Current view: top level - src/backend/regex - regc_lex.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 513 540 95.0 %
Date: 2021-12-09 04:09:06 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        5400 : lexstart(struct vars *v)
      71             : {
      72        5400 :     prefixes(v);                /* may turn on new type bits etc. */
      73        5400 :     NOERR();
      74             : 
      75        5394 :     if (v->cflags & REG_QUOTE)
      76             :     {
      77             :         assert(!(v->cflags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)));
      78          42 :         INTOCON(L_Q);
      79             :     }
      80        5352 :     else if (v->cflags & REG_EXTENDED)
      81             :     {
      82             :         assert(!(v->cflags & REG_QUOTE));
      83        5096 :         INTOCON(L_ERE);
      84             :     }
      85             :     else
      86             :     {
      87             :         assert(!(v->cflags & (REG_QUOTE | REG_ADVF)));
      88         256 :         INTOCON(L_BRE);
      89             :     }
      90             : 
      91        5394 :     v->nexttype = EMPTY;     /* remember we were at the start */
      92        5394 :     next(v);                    /* set up the first token */
      93             : }
      94             : 
      95             : /*
      96             :  * prefixes - implement various special prefixes
      97             :  */
      98             : static void
      99        5400 : prefixes(struct vars *v)
     100             : {
     101             :     /* literal string doesn't get any of this stuff */
     102        5400 :     if (v->cflags & REG_QUOTE)
     103          28 :         return;
     104             : 
     105             :     /* initial "***" gets special things */
     106        5372 :     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        5364 :     if ((v->cflags & REG_ADVANCED) != REG_ADVANCED)
     133         266 :         return;
     134             : 
     135             :     /* embedded options (AREs only) */
     136        5098 :     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       90620 : next(struct vars *v)
     201             : {
     202             :     chr         c;
     203             : 
     204             :     /* errors yield an infinite sequence of failures */
     205       90620 :     if (ISERR())
     206         130 :         return 0;               /* the error has set nexttype to EOS */
     207             : 
     208             :     /* remember flavor of last token */
     209       90490 :     v->lasttype = v->nexttype;
     210             : 
     211             :     /* REG_BOSONLY */
     212       90490 :     if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
     213             :     {
     214             :         /* at start of a REG_BOSONLY RE */
     215           4 :         RETV(SBEGIN, 0);        /* same as \A */
     216             :     }
     217             : 
     218             :     /* skip white space etc. if appropriate (not in literal or []) */
     219       90486 :     if (v->cflags & REG_EXPANDED)
     220        2458 :         switch (v->lexcon)
     221             :         {
     222        1618 :             case L_ERE:
     223             :             case L_BRE:
     224             :             case L_EBND:
     225             :             case L_BBND:
     226        1618 :                 skip(v);
     227        1618 :                 break;
     228             :         }
     229             : 
     230             :     /* handle EOS, depending on context */
     231       90486 :     if (ATEOS())
     232             :     {
     233        5218 :         switch (v->lexcon)
     234             :         {
     235        5186 :             case L_ERE:
     236             :             case L_BRE:
     237             :             case L_Q:
     238        5186 :                 RET(EOS);
     239             :                 break;
     240           4 :             case L_EBND:
     241             :             case L_BBND:
     242           4 :                 FAILW(REG_EBRACE);
     243             :                 break;
     244          28 :             case L_BRACK:
     245             :             case L_CEL:
     246             :             case L_ECL:
     247             :             case L_CCL:
     248          28 :                 FAILW(REG_EBRACK);
     249             :                 break;
     250             :         }
     251             :         assert(NOTREACHED);
     252             :     }
     253             : 
     254             :     /* okay, time to actually get a character */
     255       85268 :     c = *v->now++;
     256             : 
     257             :     /* deal with the easy contexts, punt EREs to code below */
     258       85268 :     switch (v->lexcon)
     259             :     {
     260         644 :         case L_BRE:             /* punt BREs to separate function */
     261         644 :             return brenext(v, c);
     262             :             break;
     263       76848 :         case L_ERE:             /* see below */
     264       76848 :             break;
     265         196 :         case L_Q:               /* literal strings are easy */
     266         196 :             RETV(PLAIN, c);
     267             :             break;
     268        1282 :         case L_BBND:            /* bounds are fairly simple */
     269             :         case L_EBND:
     270        1282 :             switch (c)
     271             :             {
     272         676 :                 case CHR('0'):
     273             :                 case CHR('1'):
     274             :                 case CHR('2'):
     275             :                 case CHR('3'):
     276             :                 case CHR('4'):
     277             :                 case CHR('5'):
     278             :                 case CHR('6'):
     279             :                 case CHR('7'):
     280             :                 case CHR('8'):
     281             :                 case CHR('9'):
     282         676 :                     RETV(DIGIT, (chr) DIGITVAL(c));
     283             :                     break;
     284         194 :                 case CHR(','):
     285         194 :                     RET(',');
     286             :                     break;
     287         404 :                 case CHR('}'):  /* ERE bound ends with } */
     288         404 :                     if (INCON(L_EBND))
     289             :                     {
     290         404 :                         INTOCON(L_ERE);
     291         404 :                         if ((v->cflags & REG_ADVF) && NEXT1('?'))
     292             :                         {
     293          62 :                             v->now++;
     294          62 :                             NOTE(REG_UNONPOSIX);
     295          62 :                             RETV('}', 0);
     296             :                         }
     297         342 :                         RETV('}', 1);
     298             :                     }
     299             :                     else
     300           0 :                         FAILW(REG_BADBR);
     301             :                     break;
     302           6 :                 case CHR('\\'): /* BRE bound ends with \} */
     303           6 :                     if (INCON(L_BBND) && NEXT1('}'))
     304             :                     {
     305           4 :                         v->now++;
     306           4 :                         INTOCON(L_BRE);
     307           4 :                         RETV('}', 1);
     308             :                     }
     309             :                     else
     310           2 :                         FAILW(REG_BADBR);
     311             :                     break;
     312           2 :                 default:
     313           2 :                     FAILW(REG_BADBR);
     314             :                     break;
     315             :             }
     316             :             assert(NOTREACHED);
     317             :             break;
     318        5268 :         case L_BRACK:           /* brackets are not too hard */
     319             :             switch (c)
     320             :             {
     321        1426 :                 case CHR(']'):
     322        1426 :                     if (LASTTYPE('['))
     323           4 :                         RETV(PLAIN, c);
     324             :                     else
     325             :                     {
     326        1422 :                         INTOCON((v->cflags & REG_EXTENDED) ?
     327             :                                 L_ERE : L_BRE);
     328        1422 :                         RET(']');
     329             :                     }
     330             :                     break;
     331         128 :                 case CHR('\\'):
     332         128 :                     NOTE(REG_UBBS);
     333         128 :                     if (!(v->cflags & REG_ADVF))
     334          14 :                         RETV(PLAIN, c);
     335         114 :                     NOTE(REG_UNONPOSIX);
     336         114 :                     if (ATEOS())
     337           0 :                         FAILW(REG_EESCAPE);
     338         114 :                     if (!lexescape(v))
     339           0 :                         return 0;
     340         114 :                     switch (v->nexttype)
     341             :                     {           /* not all escapes okay here */
     342         112 :                         case PLAIN:
     343             :                         case CCLASSS:
     344             :                         case CCLASSC:
     345         112 :                             return 1;
     346             :                             break;
     347             :                     }
     348             :                     /* not one of the acceptable escapes */
     349           2 :                     FAILW(REG_EESCAPE);
     350             :                     break;
     351         942 :                 case CHR('-'):
     352         942 :                     if (LASTTYPE('[') || NEXT1(']'))
     353          16 :                         RETV(PLAIN, c);
     354             :                     else
     355         926 :                         RETV(RANGE, c);
     356             :                     break;
     357         224 :                 case CHR('['):
     358         224 :                     if (ATEOS())
     359           0 :                         FAILW(REG_EBRACK);
     360         224 :                     switch (*v->now++)
     361             :                     {
     362          24 :                         case CHR('.'):
     363          24 :                             INTOCON(L_CEL);
     364             :                             /* might or might not be locale-specific */
     365          24 :                             RET(COLLEL);
     366             :                             break;
     367          32 :                         case CHR('='):
     368          32 :                             INTOCON(L_ECL);
     369          32 :                             NOTE(REG_ULOCALE);
     370          32 :                             RET(ECLASS);
     371             :                             break;
     372         164 :                         case CHR(':'):
     373         164 :                             INTOCON(L_CCL);
     374         164 :                             NOTE(REG_ULOCALE);
     375         164 :                             RET(CCLASS);
     376             :                             break;
     377           4 :                         default:    /* oops */
     378           4 :                             v->now--;
     379           4 :                             RETV(PLAIN, c);
     380             :                             break;
     381             :                     }
     382             :                     assert(NOTREACHED);
     383             :                     break;
     384        2548 :                 default:
     385        2548 :                     RETV(PLAIN, c);
     386             :                     break;
     387             :             }
     388             :             assert(NOTREACHED);
     389             :             break;
     390          64 :         case L_CEL:             /* collating elements are easy */
     391          64 :             if (c == CHR('.') && NEXT1(']'))
     392             :             {
     393          20 :                 v->now++;
     394          20 :                 INTOCON(L_BRACK);
     395          20 :                 RETV(END, '.');
     396             :             }
     397             :             else
     398          44 :                 RETV(PLAIN, c);
     399             :             break;
     400          48 :         case L_ECL:             /* ditto equivalence classes */
     401          48 :             if (c == CHR('=') && NEXT1(']'))
     402             :             {
     403          24 :                 v->now++;
     404          24 :                 INTOCON(L_BRACK);
     405          24 :                 RETV(END, '=');
     406             :             }
     407             :             else
     408          24 :                 RETV(PLAIN, c);
     409             :             break;
     410         918 :         case L_CCL:             /* ditto character classes */
     411         918 :             if (c == CHR(':') && NEXT1(']'))
     412             :             {
     413         154 :                 v->now++;
     414         154 :                 INTOCON(L_BRACK);
     415         154 :                 RETV(END, ':');
     416             :             }
     417             :             else
     418         764 :                 RETV(PLAIN, c);
     419             :             break;
     420           0 :         default:
     421             :             assert(NOTREACHED);
     422           0 :             break;
     423             :     }
     424             : 
     425             :     /* that got rid of everything except EREs and AREs */
     426             :     assert(INCON(L_ERE));
     427             : 
     428             :     /* deal with EREs and AREs, except for backslashes */
     429       76848 :     switch (c)
     430             :     {
     431         506 :         case CHR('|'):
     432         506 :             RET('|');
     433             :             break;
     434       15418 :         case CHR('*'):
     435       15418 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     436             :             {
     437          40 :                 v->now++;
     438          40 :                 NOTE(REG_UNONPOSIX);
     439          40 :                 RETV('*', 0);
     440             :             }
     441       15378 :             RETV('*', 1);
     442             :             break;
     443         664 :         case CHR('+'):
     444         664 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     445             :             {
     446          38 :                 v->now++;
     447          38 :                 NOTE(REG_UNONPOSIX);
     448          38 :                 RETV('+', 0);
     449             :             }
     450         626 :             RETV('+', 1);
     451             :             break;
     452          98 :         case CHR('?'):
     453          98 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     454             :             {
     455           4 :                 v->now++;
     456           4 :                 NOTE(REG_UNONPOSIX);
     457           4 :                 RETV('?', 0);
     458             :             }
     459          94 :             RETV('?', 1);
     460             :             break;
     461         420 :         case CHR('{'):          /* bounds start or plain character */
     462         420 :             if (v->cflags & REG_EXPANDED)
     463          32 :                 skip(v);
     464         420 :             if (ATEOS() || !iscdigit(*v->now))
     465             :             {
     466           8 :                 NOTE(REG_UBRACES);
     467           8 :                 NOTE(REG_UUNSPEC);
     468           8 :                 RETV(PLAIN, c);
     469             :             }
     470             :             else
     471             :             {
     472         412 :                 NOTE(REG_UBOUNDS);
     473         412 :                 INTOCON(L_EBND);
     474         412 :                 RET('{');
     475             :             }
     476             :             assert(NOTREACHED);
     477             :             break;
     478        3212 :         case CHR('('):          /* parenthesis, or advanced extension */
     479        3212 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     480             :             {
     481         368 :                 NOTE(REG_UNONPOSIX);
     482         368 :                 v->now++;
     483         368 :                 if (ATEOS())
     484           0 :                     FAILW(REG_BADRPT);
     485         368 :                 switch (*v->now++)
     486             :                 {
     487         150 :                     case CHR(':'):  /* non-capturing paren */
     488         150 :                         RETV('(', 0);
     489             :                         break;
     490           2 :                     case CHR('#'):  /* comment */
     491          16 :                         while (!ATEOS() && *v->now != CHR(')'))
     492          14 :                             v->now++;
     493           2 :                         if (!ATEOS())
     494           2 :                             v->now++;
     495             :                         assert(v->nexttype == v->lasttype);
     496           2 :                         return next(v);
     497             :                         break;
     498          68 :                     case CHR('='):  /* positive lookahead */
     499          68 :                         NOTE(REG_ULOOKAROUND);
     500          68 :                         RETV(LACON, LATYPE_AHEAD_POS);
     501             :                         break;
     502          66 :                     case CHR('!'):  /* negative lookahead */
     503          66 :                         NOTE(REG_ULOOKAROUND);
     504          66 :                         RETV(LACON, LATYPE_AHEAD_NEG);
     505             :                         break;
     506          80 :                     case CHR('<'):
     507          80 :                         if (ATEOS())
     508           0 :                             FAILW(REG_BADRPT);
     509          80 :                         switch (*v->now++)
     510             :                         {
     511          60 :                             case CHR('='):  /* positive lookbehind */
     512          60 :                                 NOTE(REG_ULOOKAROUND);
     513          60 :                                 RETV(LACON, LATYPE_BEHIND_POS);
     514             :                                 break;
     515          20 :                             case CHR('!'):  /* negative lookbehind */
     516          20 :                                 NOTE(REG_ULOOKAROUND);
     517          20 :                                 RETV(LACON, LATYPE_BEHIND_NEG);
     518             :                                 break;
     519           0 :                             default:
     520           0 :                                 FAILW(REG_BADRPT);
     521             :                                 break;
     522             :                         }
     523             :                         assert(NOTREACHED);
     524             :                         break;
     525           2 :                     default:
     526           2 :                         FAILW(REG_BADRPT);
     527             :                         break;
     528             :                 }
     529        2844 :                 assert(NOTREACHED);
     530             :             }
     531        2844 :             RETV('(', 1);
     532             :             break;
     533        3156 :         case CHR(')'):
     534        3156 :             if (LASTTYPE('('))
     535          34 :                 NOTE(REG_UUNSPEC);
     536        3156 :             RETV(')', c);
     537             :             break;
     538        1360 :         case CHR('['):          /* easy except for [[:<:]] and [[:>:]] */
     539        1360 :             if (HAVE(6) && *(v->now + 0) == CHR('[') &&
     540         186 :                 *(v->now + 1) == CHR(':') &&
     541         166 :                 (*(v->now + 2) == CHR('<') ||
     542         156 :                  *(v->now + 2) == CHR('>')) &&
     543          20 :                 *(v->now + 3) == CHR(':') &&
     544          20 :                 *(v->now + 4) == CHR(']') &&
     545          20 :                 *(v->now + 5) == CHR(']'))
     546             :             {
     547          20 :                 c = *(v->now + 2);
     548          20 :                 v->now += 6;
     549          20 :                 NOTE(REG_UNONPOSIX);
     550          20 :                 RET((c == CHR('<')) ? '<' : '>');
     551             :             }
     552        1340 :             INTOCON(L_BRACK);
     553        1340 :             if (NEXT1('^'))
     554             :             {
     555         600 :                 v->now++;
     556         600 :                 RETV('[', 0);
     557             :             }
     558         740 :             RETV('[', 1);
     559             :             break;
     560        2430 :         case CHR('.'):
     561        2430 :             RET('.');
     562             :             break;
     563        3270 :         case CHR('^'):
     564        3270 :             RET('^');
     565             :             break;
     566        2576 :         case CHR('$'):
     567        2576 :             RET('$');
     568             :             break;
     569        1518 :         case CHR('\\'):         /* mostly punt backslashes to code below */
     570        1518 :             if (ATEOS())
     571           2 :                 FAILW(REG_EESCAPE);
     572        1516 :             break;
     573       42220 :         default:                /* ordinary character */
     574       42220 :             RETV(PLAIN, c);
     575             :             break;
     576             :     }
     577             : 
     578             :     /* ERE/ARE backslash handling; backslash already eaten */
     579             :     assert(!ATEOS());
     580        1516 :     if (!(v->cflags & REG_ADVF))
     581             :     {                           /* only AREs have non-trivial escapes */
     582           8 :         if (iscalnum(*v->now))
     583             :         {
     584           6 :             NOTE(REG_UBSALNUM);
     585           6 :             NOTE(REG_UUNSPEC);
     586             :         }
     587           8 :         RETV(PLAIN, *v->now++);
     588             :     }
     589        1508 :     return lexescape(v);
     590             : }
     591             : 
     592             : /*
     593             :  * lexescape - parse an ARE backslash escape (backslash already eaten)
     594             :  *
     595             :  * This is used for ARE backslashes both normally and inside bracket
     596             :  * expressions.  In the latter case, not all escape types are allowed,
     597             :  * but the caller must reject unwanted ones after we return.
     598             :  */
     599             : static int
     600        1622 : lexescape(struct vars *v)
     601             : {
     602             :     chr         c;
     603             :     static const chr alert[] = {
     604             :         CHR('a'), CHR('l'), CHR('e'), CHR('r'), CHR('t')
     605             :     };
     606             :     static const chr esc[] = {
     607             :         CHR('E'), CHR('S'), CHR('C')
     608             :     };
     609             :     const chr  *save;
     610             : 
     611             :     assert(v->cflags & REG_ADVF);
     612             : 
     613             :     assert(!ATEOS());
     614        1622 :     c = *v->now++;
     615        1622 :     if (!iscalnum(c))
     616         816 :         RETV(PLAIN, c);
     617             : 
     618         806 :     NOTE(REG_UNONPOSIX);
     619         806 :     switch (c)
     620             :     {
     621           2 :         case CHR('a'):
     622           2 :             RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
     623             :             break;
     624          22 :         case CHR('A'):
     625          22 :             RETV(SBEGIN, 0);
     626             :             break;
     627          10 :         case CHR('b'):
     628          10 :             RETV(PLAIN, CHR('\b'));
     629             :             break;
     630          10 :         case CHR('B'):
     631          10 :             RETV(PLAIN, CHR('\\'));
     632             :             break;
     633           4 :         case CHR('c'):
     634           4 :             NOTE(REG_UUNPORT);
     635           4 :             if (ATEOS())
     636           0 :                 FAILW(REG_EESCAPE);
     637           4 :             RETV(PLAIN, (chr) (*v->now++ & 037));
     638             :             break;
     639         124 :         case CHR('d'):
     640         124 :             NOTE(REG_ULOCALE);
     641         124 :             RETV(CCLASSS, CC_DIGIT);
     642             :             break;
     643          24 :         case CHR('D'):
     644          24 :             NOTE(REG_ULOCALE);
     645          24 :             RETV(CCLASSC, CC_DIGIT);
     646             :             break;
     647           2 :         case CHR('e'):
     648           2 :             NOTE(REG_UUNPORT);
     649           2 :             RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
     650             :             break;
     651           2 :         case CHR('f'):
     652           2 :             RETV(PLAIN, CHR('\f'));
     653             :             break;
     654          26 :         case CHR('m'):
     655          26 :             RET('<');
     656             :             break;
     657          22 :         case CHR('M'):
     658          22 :             RET('>');
     659             :             break;
     660          12 :         case CHR('n'):
     661          12 :             RETV(PLAIN, CHR('\n'));
     662             :             break;
     663          10 :         case CHR('r'):
     664          10 :             RETV(PLAIN, CHR('\r'));
     665             :             break;
     666          50 :         case CHR('s'):
     667          50 :             NOTE(REG_ULOCALE);
     668          50 :             RETV(CCLASSS, CC_SPACE);
     669             :             break;
     670          24 :         case CHR('S'):
     671          24 :             NOTE(REG_ULOCALE);
     672          24 :             RETV(CCLASSC, CC_SPACE);
     673             :             break;
     674           4 :         case CHR('t'):
     675           4 :             RETV(PLAIN, CHR('\t'));
     676             :             break;
     677          56 :         case CHR('u'):
     678          56 :             c = lexdigits(v, 16, 4, 4);
     679          56 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     680           2 :                 FAILW(REG_EESCAPE);
     681          54 :             RETV(PLAIN, c);
     682             :             break;
     683          20 :         case CHR('U'):
     684          20 :             c = lexdigits(v, 16, 8, 8);
     685          20 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     686          10 :                 FAILW(REG_EESCAPE);
     687          10 :             RETV(PLAIN, c);
     688             :             break;
     689           2 :         case CHR('v'):
     690           2 :             RETV(PLAIN, CHR('\v'));
     691             :             break;
     692          86 :         case CHR('w'):
     693          86 :             NOTE(REG_ULOCALE);
     694          86 :             RETV(CCLASSS, CC_WORD);
     695             :             break;
     696          16 :         case CHR('W'):
     697          16 :             NOTE(REG_ULOCALE);
     698          16 :             RETV(CCLASSC, CC_WORD);
     699             :             break;
     700          10 :         case CHR('x'):
     701          10 :             NOTE(REG_UUNPORT);
     702          10 :             c = lexdigits(v, 16, 1, 255);   /* REs >255 long outside spec */
     703          10 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     704           6 :                 FAILW(REG_EESCAPE);
     705           4 :             RETV(PLAIN, c);
     706             :             break;
     707          18 :         case CHR('y'):
     708          18 :             NOTE(REG_ULOCALE);
     709          18 :             RETV(WBDRY, 0);
     710             :             break;
     711          34 :         case CHR('Y'):
     712          34 :             NOTE(REG_ULOCALE);
     713          34 :             RETV(NWBDRY, 0);
     714             :             break;
     715          12 :         case CHR('Z'):
     716          12 :             RETV(SEND, 0);
     717             :             break;
     718         192 :         case CHR('1'):
     719             :         case CHR('2'):
     720             :         case CHR('3'):
     721             :         case CHR('4'):
     722             :         case CHR('5'):
     723             :         case CHR('6'):
     724             :         case CHR('7'):
     725             :         case CHR('8'):
     726             :         case CHR('9'):
     727         192 :             save = v->now;
     728         192 :             v->now--;            /* put first digit back */
     729         192 :             c = lexdigits(v, 10, 1, 255);   /* REs >255 long outside spec */
     730         192 :             if (ISERR())
     731           0 :                 FAILW(REG_EESCAPE);
     732             :             /* ugly heuristic (first test is "exactly 1 digit?") */
     733         192 :             if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
     734             :             {
     735         182 :                 NOTE(REG_UBACKREF);
     736         182 :                 RETV(BACKREF, c);
     737             :             }
     738             :             /* oops, doesn't look like it's a backref after all... */
     739          10 :             v->now = save;
     740             :             /* and fall through into octal number */
     741             :             /* FALLTHROUGH */
     742          20 :         case CHR('0'):
     743          20 :             NOTE(REG_UUNPORT);
     744          20 :             v->now--;            /* put first digit back */
     745          20 :             c = lexdigits(v, 8, 1, 3);
     746          20 :             if (ISERR())
     747           0 :                 FAILW(REG_EESCAPE);
     748          20 :             if (c > 0xff)
     749             :             {
     750             :                 /* out of range, so we handled one digit too much */
     751           2 :                 v->now--;
     752           2 :                 c >>= 3;
     753             :             }
     754          20 :             RETV(PLAIN, c);
     755             :             break;
     756           2 :         default:
     757             :             assert(iscalpha(c));
     758           2 :             FAILW(REG_EESCAPE); /* unknown alphabetic escape */
     759             :             break;
     760             :     }
     761             :     assert(NOTREACHED);
     762             : }
     763             : 
     764             : /*
     765             :  * lexdigits - slurp up digits and return chr value
     766             :  *
     767             :  * This does not account for overflow; callers should range-check the result
     768             :  * if maxlen is large enough to make that possible.
     769             :  */
     770             : static chr                      /* chr value; errors signalled via ERR */
     771         298 : lexdigits(struct vars *v,
     772             :           int base,
     773             :           int minlen,
     774             :           int maxlen)
     775             : {
     776             :     uchr        n;              /* unsigned to avoid overflow misbehavior */
     777             :     int         len;
     778             :     chr         c;
     779             :     int         d;
     780         298 :     const uchr  ub = (uchr) base;
     781             : 
     782         298 :     n = 0;
     783         988 :     for (len = 0; len < maxlen && !ATEOS(); len++)
     784             :     {
     785         840 :         c = *v->now++;
     786         840 :         switch (c)
     787             :         {
     788         644 :             case CHR('0'):
     789             :             case CHR('1'):
     790             :             case CHR('2'):
     791             :             case CHR('3'):
     792             :             case CHR('4'):
     793             :             case CHR('5'):
     794             :             case CHR('6'):
     795             :             case CHR('7'):
     796             :             case CHR('8'):
     797             :             case CHR('9'):
     798         644 :                 d = DIGITVAL(c);
     799         644 :                 break;
     800           0 :             case CHR('a'):
     801             :             case CHR('A'):
     802           0 :                 d = 10;
     803           0 :                 break;
     804          16 :             case CHR('b'):
     805             :             case CHR('B'):
     806          16 :                 d = 11;
     807          16 :                 break;
     808           4 :             case CHR('c'):
     809             :             case CHR('C'):
     810           4 :                 d = 12;
     811           4 :                 break;
     812           0 :             case CHR('d'):
     813             :             case CHR('D'):
     814           0 :                 d = 13;
     815           0 :                 break;
     816           4 :             case CHR('e'):
     817             :             case CHR('E'):
     818           4 :                 d = 14;
     819           4 :                 break;
     820          44 :             case CHR('f'):
     821             :             case CHR('F'):
     822          44 :                 d = 15;
     823          44 :                 break;
     824         128 :             default:
     825         128 :                 v->now--;        /* oops, not a digit at all */
     826         128 :                 d = -1;
     827         128 :                 break;
     828             :         }
     829             : 
     830         840 :         if (d >= base)
     831             :         {                       /* not a plausible digit */
     832          22 :             v->now--;
     833          22 :             d = -1;
     834             :         }
     835         840 :         if (d < 0)
     836         150 :             break;              /* NOTE BREAK OUT */
     837         690 :         n = n * ub + (uchr) d;
     838             :     }
     839         298 :     if (len < minlen)
     840          14 :         ERR(REG_EESCAPE);
     841             : 
     842         298 :     return (chr) n;
     843             : }
     844             : 
     845             : /*
     846             :  * brenext - get next BRE token
     847             :  *
     848             :  * This is much like EREs except for all the stupid backslashes and the
     849             :  * context-dependency of some things.
     850             :  */
     851             : static int                      /* 1 normal, 0 failure */
     852         644 : brenext(struct vars *v,
     853             :         chr c)
     854             : {
     855         644 :     switch (c)
     856             :     {
     857          46 :         case CHR('*'):
     858          46 :             if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
     859          12 :                 RETV(PLAIN, c);
     860          34 :             RETV('*', 1);
     861             :             break;
     862         148 :         case CHR('['):
     863         148 :             if (HAVE(6) && *(v->now + 0) == CHR('[') &&
     864          44 :                 *(v->now + 1) == CHR(':') &&
     865          24 :                 (*(v->now + 2) == CHR('<') ||
     866          16 :                  *(v->now + 2) == CHR('>')) &&
     867          16 :                 *(v->now + 3) == CHR(':') &&
     868          16 :                 *(v->now + 4) == CHR(']') &&
     869          16 :                 *(v->now + 5) == CHR(']'))
     870             :             {
     871          16 :                 c = *(v->now + 2);
     872          16 :                 v->now += 6;
     873          16 :                 NOTE(REG_UNONPOSIX);
     874          16 :                 RET((c == CHR('<')) ? '<' : '>');
     875             :             }
     876         132 :             INTOCON(L_BRACK);
     877         132 :             if (NEXT1('^'))
     878             :             {
     879          12 :                 v->now++;
     880          12 :                 RETV('[', 0);
     881             :             }
     882         120 :             RETV('[', 1);
     883             :             break;
     884           8 :         case CHR('.'):
     885           8 :             RET('.');
     886             :             break;
     887          36 :         case CHR('^'):
     888          36 :             if (LASTTYPE(EMPTY))
     889          28 :                 RET('^');
     890           8 :             if (LASTTYPE('('))
     891             :             {
     892           2 :                 NOTE(REG_UUNSPEC);
     893           2 :                 RET('^');
     894             :             }
     895           6 :             RETV(PLAIN, c);
     896             :             break;
     897          30 :         case CHR('$'):
     898          30 :             if (v->cflags & REG_EXPANDED)
     899           0 :                 skip(v);
     900          30 :             if (ATEOS())
     901          22 :                 RET('$');
     902           8 :             if (NEXT2('\\', ')'))
     903             :             {
     904           2 :                 NOTE(REG_UUNSPEC);
     905           2 :                 RET('$');
     906             :             }
     907           6 :             RETV(PLAIN, c);
     908             :             break;
     909          52 :         case CHR('\\'):
     910          52 :             break;              /* see below */
     911         324 :         default:
     912         324 :             RETV(PLAIN, c);
     913             :             break;
     914             :     }
     915             : 
     916             :     assert(c == CHR('\\'));
     917             : 
     918          52 :     if (ATEOS())
     919           2 :         FAILW(REG_EESCAPE);
     920             : 
     921          50 :     c = *v->now++;
     922          50 :     switch (c)
     923             :     {
     924           6 :         case CHR('{'):
     925           6 :             INTOCON(L_BBND);
     926           6 :             NOTE(REG_UBOUNDS);
     927           6 :             RET('{');
     928             :             break;
     929          12 :         case CHR('('):
     930          12 :             RETV('(', 1);
     931             :             break;
     932          12 :         case CHR(')'):
     933          12 :             RETV(')', c);
     934             :             break;
     935           6 :         case CHR('<'):
     936           6 :             NOTE(REG_UNONPOSIX);
     937           6 :             RET('<');
     938             :             break;
     939           6 :         case CHR('>'):
     940           6 :             NOTE(REG_UNONPOSIX);
     941           6 :             RET('>');
     942             :             break;
     943           4 :         case CHR('1'):
     944             :         case CHR('2'):
     945             :         case CHR('3'):
     946             :         case CHR('4'):
     947             :         case CHR('5'):
     948             :         case CHR('6'):
     949             :         case CHR('7'):
     950             :         case CHR('8'):
     951             :         case CHR('9'):
     952           4 :             NOTE(REG_UBACKREF);
     953           4 :             RETV(BACKREF, (chr) DIGITVAL(c));
     954             :             break;
     955           4 :         default:
     956           4 :             if (iscalnum(c))
     957             :             {
     958           4 :                 NOTE(REG_UBSALNUM);
     959           4 :                 NOTE(REG_UUNSPEC);
     960             :             }
     961           4 :             RETV(PLAIN, c);
     962             :             break;
     963             :     }
     964             : 
     965             :     assert(NOTREACHED);
     966             :     return 0;
     967             : }
     968             : 
     969             : /*
     970             :  * skip - skip white space and comments in expanded form
     971             :  */
     972             : static void
     973        1650 : skip(struct vars *v)
     974             : {
     975        1650 :     const chr  *start = v->now;
     976             : 
     977             :     assert(v->cflags & REG_EXPANDED);
     978             : 
     979             :     for (;;)
     980             :     {
     981        2668 :         while (!ATEOS() && iscspace(*v->now))
     982         878 :             v->now++;
     983        1790 :         if (ATEOS() || *v->now != CHR('#'))
     984             :             break;              /* NOTE BREAK OUT */
     985             :         assert(NEXT1('#'));
     986        1408 :         while (!ATEOS() && *v->now != CHR('\n'))
     987        1268 :             v->now++;
     988             :         /* leave the newline to be picked up by the iscspace loop */
     989             :     }
     990             : 
     991        1650 :     if (v->now != start)
     992         198 :         NOTE(REG_UNONPOSIX);
     993        1650 : }
     994             : 
     995             : /*
     996             :  * newline - return the chr for a newline
     997             :  *
     998             :  * This helps confine use of CHR to this source file.
     999             :  */
    1000             : static chr
    1001         812 : newline(void)
    1002             : {
    1003         812 :     return CHR('\n');
    1004             : }
    1005             : 
    1006             : /*
    1007             :  * chrnamed - return the chr known by a given (chr string) name
    1008             :  *
    1009             :  * The code is a bit clumsy, but this routine gets only such specialized
    1010             :  * use that it hardly matters.
    1011             :  */
    1012             : static chr
    1013           4 : chrnamed(struct vars *v,
    1014             :          const chr *startp,     /* start of name */
    1015             :          const chr *endp,       /* just past end of name */
    1016             :          chr lastresort)        /* what to return if name lookup fails */
    1017             : {
    1018             :     chr         c;
    1019             :     int         errsave;
    1020             :     int         e;
    1021             :     struct cvec *cv;
    1022             : 
    1023           4 :     errsave = v->err;
    1024           4 :     v->err = 0;
    1025           4 :     c = element(v, startp, endp);
    1026           4 :     e = v->err;
    1027           4 :     v->err = errsave;
    1028             : 
    1029           4 :     if (e != 0)
    1030           0 :         return lastresort;
    1031             : 
    1032           4 :     cv = range(v, c, c, 0);
    1033           4 :     if (cv->nchrs == 0)
    1034           4 :         return lastresort;
    1035           0 :     return cv->chrs[0];
    1036             : }

Generated by: LCOV version 1.14