LCOV - differential code coverage report
Current view: top level - src/backend/regex - regc_lex.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 94.9 % 553 525 28 525
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 9 9 9
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * lexical analyzer
       3                 :  * This file is #included by regcomp.c.
       4                 :  *
       5                 :  * Copyright (c) 1998, 1999 Henry Spencer.  All rights reserved.
       6                 :  *
       7                 :  * Development of this software was funded, in part, by Cray Research Inc.,
       8                 :  * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
       9                 :  * Corporation, none of whom are responsible for the results.  The author
      10                 :  * thanks all of them.
      11                 :  *
      12                 :  * Redistribution and use in source and binary forms -- with or without
      13                 :  * modification -- are permitted for any purpose, provided that
      14                 :  * redistributions in source form retain this entire copyright notice and
      15                 :  * indicate the origin and nature of any modifications.
      16                 :  *
      17                 :  * I'd appreciate being given credit for this package in the documentation
      18                 :  * of software which uses it, but that is not a requirement.
      19                 :  *
      20                 :  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
      21                 :  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
      22                 :  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
      23                 :  * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
      24                 :  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
      25                 :  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
      26                 :  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
      27                 :  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
      28                 :  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
      29                 :  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      30                 :  *
      31                 :  * src/backend/regex/regc_lex.c
      32                 :  *
      33                 :  */
      34                 : 
      35                 : /* scanning macros (know about v) */
      36                 : #define ATEOS()     (v->now >= v->stop)
      37                 : #define HAVE(n)     (v->stop - v->now >= (n))
      38                 : #define NEXT1(c)    (!ATEOS() && *v->now == CHR(c))
      39                 : #define NEXT2(a,b)  (HAVE(2) && *v->now == CHR(a) && *(v->now+1) == CHR(b))
      40                 : #define NEXT3(a,b,c)    (HAVE(3) && *v->now == CHR(a) && \
      41                 :                         *(v->now+1) == CHR(b) && \
      42                 :                         *(v->now+2) == CHR(c))
      43                 : #define SET(c)      (v->nexttype = (c))
      44                 : #define SETV(c, n)  (v->nexttype = (c), v->nextvalue = (n))
      45                 : #define RET(c)      return (SET(c), 1)
      46                 : #define RETV(c, n)  return (SETV(c, n), 1)
      47                 : #define FAILW(e)    return (ERR(e), 0)  /* ERR does SET(EOS) */
      48                 : #define LASTTYPE(t) (v->lasttype == (t))
      49                 : 
      50                 : /* lexical contexts */
      51                 : #define L_ERE   1               /* mainline ERE/ARE */
      52                 : #define L_BRE   2               /* mainline BRE */
      53                 : #define L_Q 3                   /* REG_QUOTE */
      54                 : #define L_EBND  4               /* ERE/ARE bound */
      55                 : #define L_BBND  5               /* BRE bound */
      56                 : #define L_BRACK 6               /* brackets */
      57                 : #define L_CEL   7               /* collating element */
      58                 : #define L_ECL   8               /* equivalence class */
      59                 : #define L_CCL   9               /* character class */
      60                 : #define INTOCON(c)  (v->lexcon = (c))
      61                 : #define INCON(con)  (v->lexcon == (con))
      62                 : 
      63                 : /* construct pointer past end of chr array */
      64                 : #define ENDOF(array)    ((array) + sizeof(array)/sizeof(chr))
      65                 : 
      66                 : /*
      67                 :  * lexstart - set up lexical stuff, scan leading options
      68                 :  */
      69                 : static void
      70 CBC        3933 : lexstart(struct vars *v)
      71                 : {
      72            3933 :     prefixes(v);                /* may turn on new type bits etc. */
      73            3933 :     NOERR();
      74                 : 
      75            3930 :     if (v->cflags & REG_QUOTE)
      76                 :     {
      77              48 :         assert(!(v->cflags & (REG_ADVANCED | REG_EXPANDED | REG_NEWLINE)));
      78              48 :         INTOCON(L_Q);
      79                 :     }
      80            3882 :     else if (v->cflags & REG_EXTENDED)
      81                 :     {
      82            3754 :         assert(!(v->cflags & REG_QUOTE));
      83            3754 :         INTOCON(L_ERE);
      84                 :     }
      85                 :     else
      86                 :     {
      87             128 :         assert(!(v->cflags & (REG_QUOTE | REG_ADVF)));
      88             128 :         INTOCON(L_BRE);
      89                 :     }
      90                 : 
      91            3930 :     v->nexttype = EMPTY;     /* remember we were at the start */
      92            3930 :     next(v);                    /* set up the first token */
      93                 : }
      94                 : 
      95                 : /*
      96                 :  * prefixes - implement various special prefixes
      97                 :  */
      98                 : static void
      99            3933 : prefixes(struct vars *v)
     100                 : {
     101                 :     /* literal string doesn't get any of this stuff */
     102            3933 :     if (v->cflags & REG_QUOTE)
     103              41 :         return;
     104                 : 
     105                 :     /* initial "***" gets special things */
     106            3892 :     if (HAVE(4) && NEXT3('*', '*', '*'))
     107              10 :         switch (*(v->now + 3))
     108                 :         {
     109               2 :             case CHR('?'):      /* "***?" error, msg shows version */
     110               2 :                 ERR(REG_BADPAT);
     111               2 :                 return;         /* proceed no further */
     112                 :                 break;
     113               2 :             case CHR('='):      /* "***=" shifts to literal string */
     114               2 :                 NOTE(REG_UNONPOSIX);
     115               2 :                 v->cflags |= REG_QUOTE;
     116               2 :                 v->cflags &= ~(REG_ADVANCED | REG_EXPANDED | REG_NEWLINE);
     117               2 :                 v->now += 4;
     118               2 :                 return;         /* and there can be no more prefixes */
     119                 :                 break;
     120               6 :             case CHR(':'):      /* "***:" shifts to AREs */
     121               6 :                 NOTE(REG_UNONPOSIX);
     122               6 :                 v->cflags |= REG_ADVANCED;
     123               6 :                 v->now += 4;
     124               6 :                 break;
     125 UBC           0 :             default:            /* otherwise *** is just an error */
     126               0 :                 ERR(REG_BADRPT);
     127               0 :                 return;
     128                 :                 break;
     129                 :         }
     130                 : 
     131                 :     /* BREs and EREs don't get embedded options */
     132 CBC        3888 :     if ((v->cflags & REG_ADVANCED) != REG_ADVANCED)
     133             133 :         return;
     134                 : 
     135                 :     /* embedded options (AREs only) */
     136            3755 :     if (HAVE(3) && NEXT2('(', '?') && iscalpha(*(v->now + 2)))
     137                 :     {
     138              28 :         NOTE(REG_UNONPOSIX);
     139              28 :         v->now += 2;
     140              60 :         for (; !ATEOS() && iscalpha(*v->now); v->now++)
     141              33 :             switch (*v->now)
     142                 :             {
     143               3 :                 case CHR('b'):  /* BREs (but why???) */
     144               3 :                     v->cflags &= ~(REG_ADVANCED | REG_QUOTE);
     145               3 :                     break;
     146               3 :                 case CHR('c'):  /* case sensitive */
     147               3 :                     v->cflags &= ~REG_ICASE;
     148               3 :                     break;
     149               2 :                 case CHR('e'):  /* plain EREs */
     150               2 :                     v->cflags |= REG_EXTENDED;
     151               2 :                     v->cflags &= ~(REG_ADVF | REG_QUOTE);
     152               2 :                     break;
     153               5 :                 case CHR('i'):  /* case insensitive */
     154               5 :                     v->cflags |= REG_ICASE;
     155               5 :                     break;
     156               5 :                 case CHR('m'):  /* Perloid synonym for n */
     157                 :                 case CHR('n'):  /* \n affects ^ $ . [^ */
     158               5 :                     v->cflags |= REG_NEWLINE;
     159               5 :                     break;
     160               2 :                 case CHR('p'):  /* ~Perl, \n affects . [^ */
     161               2 :                     v->cflags |= REG_NLSTOP;
     162               2 :                     v->cflags &= ~REG_NLANCH;
     163               2 :                     break;
     164               6 :                 case CHR('q'):  /* literal string */
     165               6 :                     v->cflags |= REG_QUOTE;
     166               6 :                     v->cflags &= ~REG_ADVANCED;
     167               6 :                     break;
     168               1 :                 case CHR('s'):  /* single line, \n ordinary */
     169               1 :                     v->cflags &= ~REG_NEWLINE;
     170               1 :                     break;
     171               1 :                 case CHR('t'):  /* tight syntax */
     172               1 :                     v->cflags &= ~REG_EXPANDED;
     173               1 :                     break;
     174               2 :                 case CHR('w'):  /* weird, \n affects ^ $ only */
     175               2 :                     v->cflags &= ~REG_NLSTOP;
     176               2 :                     v->cflags |= REG_NLANCH;
     177               2 :                     break;
     178               2 :                 case CHR('x'):  /* expanded syntax */
     179               2 :                     v->cflags |= REG_EXPANDED;
     180               2 :                     break;
     181               1 :                 default:
     182               1 :                     ERR(REG_BADOPT);
     183               1 :                     return;
     184                 :             }
     185              27 :         if (!NEXT1(')'))
     186                 :         {
     187 UBC           0 :             ERR(REG_BADOPT);
     188               0 :             return;
     189                 :         }
     190 CBC          27 :         v->now++;
     191              27 :         if (v->cflags & REG_QUOTE)
     192               5 :             v->cflags &= ~(REG_EXPANDED | REG_NEWLINE);
     193                 :     }
     194                 : }
     195                 : 
     196                 : /*
     197                 :  * next - get next token
     198                 :  */
     199                 : static int                      /* 1 normal, 0 failure */
     200           69330 : next(struct vars *v)
     201                 : {
     202                 :     chr         c;
     203                 : 
     204           69331 : next_restart:                   /* loop here after eating a comment */
     205                 : 
     206                 :     /* errors yield an infinite sequence of failures */
     207           69331 :     if (ISERR())
     208              68 :         return 0;               /* the error has set nexttype to EOS */
     209                 : 
     210                 :     /* remember flavor of last token */
     211           69263 :     v->lasttype = v->nexttype;
     212                 : 
     213                 :     /* REG_BOSONLY */
     214           69263 :     if (v->nexttype == EMPTY && (v->cflags & REG_BOSONLY))
     215                 :     {
     216                 :         /* at start of a REG_BOSONLY RE */
     217               2 :         RETV(SBEGIN, 0);        /* same as \A */
     218                 :     }
     219                 : 
     220                 :     /* skip white space etc. if appropriate (not in literal or []) */
     221           69261 :     if (v->cflags & REG_EXPANDED)
     222            1233 :         switch (v->lexcon)
     223                 :         {
     224             813 :             case L_ERE:
     225                 :             case L_BRE:
     226                 :             case L_EBND:
     227                 :             case L_BBND:
     228             813 :                 skip(v);
     229             813 :                 break;
     230                 :         }
     231                 : 
     232                 :     /* handle EOS, depending on context */
     233           69261 :     if (ATEOS())
     234                 :     {
     235            3838 :         switch (v->lexcon)
     236                 :         {
     237            3822 :             case L_ERE:
     238                 :             case L_BRE:
     239                 :             case L_Q:
     240            3822 :                 RET(EOS);
     241                 :                 break;
     242               2 :             case L_EBND:
     243                 :             case L_BBND:
     244               2 :                 FAILW(REG_EBRACE);
     245                 :                 break;
     246              14 :             case L_BRACK:
     247                 :             case L_CEL:
     248                 :             case L_ECL:
     249                 :             case L_CCL:
     250              14 :                 FAILW(REG_EBRACK);
     251                 :                 break;
     252                 :         }
     253 UBC           0 :         assert(NOTREACHED);
     254                 :     }
     255                 : 
     256                 :     /* okay, time to actually get a character */
     257 CBC       65423 :     c = *v->now++;
     258                 : 
     259                 :     /* deal with the easy contexts, punt EREs to code below */
     260           65423 :     switch (v->lexcon)
     261                 :     {
     262             322 :         case L_BRE:             /* punt BREs to separate function */
     263             322 :             return brenext(v, c);
     264                 :             break;
     265           60107 :         case L_ERE:             /* see below */
     266           60107 :             break;
     267             247 :         case L_Q:               /* literal strings are easy */
     268             247 :             RETV(PLAIN, c);
     269                 :             break;
     270             791 :         case L_BBND:            /* bounds are fairly simple */
     271                 :         case L_EBND:
     272             791 :             switch (c)
     273                 :             {
     274             414 :                 case CHR('0'):
     275                 :                 case CHR('1'):
     276                 :                 case CHR('2'):
     277                 :                 case CHR('3'):
     278                 :                 case CHR('4'):
     279                 :                 case CHR('5'):
     280                 :                 case CHR('6'):
     281                 :                 case CHR('7'):
     282                 :                 case CHR('8'):
     283                 :                 case CHR('9'):
     284             414 :                     RETV(DIGIT, (chr) DIGITVAL(c));
     285                 :                     break;
     286             122 :                 case CHR(','):
     287             122 :                     RET(',');
     288                 :                     break;
     289             251 :                 case CHR('}'):  /* ERE bound ends with } */
     290             251 :                     if (INCON(L_EBND))
     291                 :                     {
     292             251 :                         INTOCON(L_ERE);
     293             251 :                         if ((v->cflags & REG_ADVF) && NEXT1('?'))
     294                 :                         {
     295              45 :                             v->now++;
     296              45 :                             NOTE(REG_UNONPOSIX);
     297              45 :                             RETV('}', 0);
     298                 :                         }
     299             206 :                         RETV('}', 1);
     300                 :                     }
     301                 :                     else
     302 UBC           0 :                         FAILW(REG_BADBR);
     303                 :                     break;
     304 CBC           3 :                 case CHR('\\'): /* BRE bound ends with \} */
     305               3 :                     if (INCON(L_BBND) && NEXT1('}'))
     306                 :                     {
     307               2 :                         v->now++;
     308               2 :                         INTOCON(L_BRE);
     309               2 :                         RETV('}', 1);
     310                 :                     }
     311                 :                     else
     312               1 :                         FAILW(REG_BADBR);
     313                 :                     break;
     314               1 :                 default:
     315               1 :                     FAILW(REG_BADBR);
     316                 :                     break;
     317                 :             }
     318                 :             assert(NOTREACHED);
     319                 :             break;
     320            3117 :         case L_BRACK:           /* brackets are not too hard */
     321                 :             switch (c)
     322                 :             {
     323             854 :                 case CHR(']'):
     324             854 :                     if (LASTTYPE('['))
     325               2 :                         RETV(PLAIN, c);
     326                 :                     else
     327                 :                     {
     328             852 :                         INTOCON((v->cflags & REG_EXTENDED) ?
     329                 :                                 L_ERE : L_BRE);
     330             852 :                         RET(']');
     331                 :                     }
     332                 :                     break;
     333              64 :                 case CHR('\\'):
     334              64 :                     NOTE(REG_UBBS);
     335              64 :                     if (!(v->cflags & REG_ADVF))
     336               7 :                         RETV(PLAIN, c);
     337              57 :                     NOTE(REG_UNONPOSIX);
     338              57 :                     if (ATEOS())
     339 UBC           0 :                         FAILW(REG_EESCAPE);
     340 CBC          57 :                     if (!lexescape(v))
     341 UBC           0 :                         return 0;
     342 CBC          57 :                     switch (v->nexttype)
     343                 :                     {           /* not all escapes okay here */
     344              56 :                         case PLAIN:
     345                 :                         case CCLASSS:
     346                 :                         case CCLASSC:
     347              56 :                             return 1;
     348                 :                             break;
     349                 :                     }
     350                 :                     /* not one of the acceptable escapes */
     351               1 :                     FAILW(REG_EESCAPE);
     352                 :                     break;
     353             549 :                 case CHR('-'):
     354             549 :                     if (LASTTYPE('[') || NEXT1(']'))
     355               8 :                         RETV(PLAIN, c);
     356                 :                     else
     357             541 :                         RETV(RANGE, c);
     358                 :                     break;
     359             166 :                 case CHR('['):
     360             166 :                     if (ATEOS())
     361 UBC           0 :                         FAILW(REG_EBRACK);
     362 CBC         166 :                     switch (*v->now++)
     363                 :                     {
     364              12 :                         case CHR('.'):
     365              12 :                             INTOCON(L_CEL);
     366                 :                             /* might or might not be locale-specific */
     367              12 :                             RET(COLLEL);
     368                 :                             break;
     369              16 :                         case CHR('='):
     370              16 :                             INTOCON(L_ECL);
     371              16 :                             NOTE(REG_ULOCALE);
     372              16 :                             RET(ECLASS);
     373                 :                             break;
     374             136 :                         case CHR(':'):
     375             136 :                             INTOCON(L_CCL);
     376             136 :                             NOTE(REG_ULOCALE);
     377             136 :                             RET(CCLASS);
     378                 :                             break;
     379               2 :                         default:    /* oops */
     380               2 :                             v->now--;
     381               2 :                             RETV(PLAIN, c);
     382                 :                             break;
     383                 :                     }
     384                 :                     assert(NOTREACHED);
     385                 :                     break;
     386            1484 :                 default:
     387            1484 :                     RETV(PLAIN, c);
     388                 :                     break;
     389                 :             }
     390                 :             assert(NOTREACHED);
     391                 :             break;
     392              32 :         case L_CEL:             /* collating elements are easy */
     393              32 :             if (c == CHR('.') && NEXT1(']'))
     394                 :             {
     395              10 :                 v->now++;
     396              10 :                 INTOCON(L_BRACK);
     397              10 :                 RETV(END, '.');
     398                 :             }
     399                 :             else
     400              22 :                 RETV(PLAIN, c);
     401                 :             break;
     402              24 :         case L_ECL:             /* ditto equivalence classes */
     403              24 :             if (c == CHR('=') && NEXT1(']'))
     404                 :             {
     405              12 :                 v->now++;
     406              12 :                 INTOCON(L_BRACK);
     407              12 :                 RETV(END, '=');
     408                 :             }
     409                 :             else
     410              12 :                 RETV(PLAIN, c);
     411                 :             break;
     412             783 :         case L_CCL:             /* ditto character classes */
     413             783 :             if (c == CHR(':') && NEXT1(']'))
     414                 :             {
     415             131 :                 v->now++;
     416             131 :                 INTOCON(L_BRACK);
     417             131 :                 RETV(END, ':');
     418                 :             }
     419                 :             else
     420             652 :                 RETV(PLAIN, c);
     421                 :             break;
     422 UBC           0 :         default:
     423               0 :             assert(NOTREACHED);
     424                 :             break;
     425                 :     }
     426                 : 
     427                 :     /* that got rid of everything except EREs and AREs */
     428 CBC       60107 :     assert(INCON(L_ERE));
     429                 : 
     430                 :     /* deal with EREs and AREs, except for backslashes */
     431           60107 :     switch (c)
     432                 :     {
     433             309 :         case CHR('|'):
     434             309 :             RET('|');
     435                 :             break;
     436           11053 :         case CHR('*'):
     437           11053 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     438                 :             {
     439              26 :                 v->now++;
     440              26 :                 NOTE(REG_UNONPOSIX);
     441              26 :                 RETV('*', 0);
     442                 :             }
     443           11027 :             RETV('*', 1);
     444                 :             break;
     445             469 :         case CHR('+'):
     446             469 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     447                 :             {
     448              22 :                 v->now++;
     449              22 :                 NOTE(REG_UNONPOSIX);
     450              22 :                 RETV('+', 0);
     451                 :             }
     452             447 :             RETV('+', 1);
     453                 :             break;
     454              60 :         case CHR('?'):
     455              60 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     456                 :             {
     457               2 :                 v->now++;
     458               2 :                 NOTE(REG_UNONPOSIX);
     459               2 :                 RETV('?', 0);
     460                 :             }
     461              58 :             RETV('?', 1);
     462                 :             break;
     463             259 :         case CHR('{'):          /* bounds start or plain character */
     464             259 :             if (v->cflags & REG_EXPANDED)
     465              16 :                 skip(v);
     466             259 :             if (ATEOS() || !iscdigit(*v->now))
     467                 :             {
     468               4 :                 NOTE(REG_UBRACES);
     469               4 :                 NOTE(REG_UUNSPEC);
     470               4 :                 RETV(PLAIN, c);
     471                 :             }
     472                 :             else
     473                 :             {
     474             255 :                 NOTE(REG_UBOUNDS);
     475             255 :                 INTOCON(L_EBND);
     476             255 :                 RET('{');
     477                 :             }
     478                 :             assert(NOTREACHED);
     479                 :             break;
     480            2430 :         case CHR('('):          /* parenthesis, or advanced extension */
     481            2430 :             if ((v->cflags & REG_ADVF) && NEXT1('?'))
     482                 :             {
     483             242 :                 NOTE(REG_UNONPOSIX);
     484             242 :                 v->now++;
     485             242 :                 if (ATEOS())
     486 UBC           0 :                     FAILW(REG_BADRPT);
     487 CBC         242 :                 switch (*v->now++)
     488                 :                 {
     489             106 :                     case CHR(':'):  /* non-capturing paren */
     490             106 :                         RETV('(', 0);
     491                 :                         break;
     492               1 :                     case CHR('#'):  /* comment */
     493               8 :                         while (!ATEOS() && *v->now != CHR(')'))
     494               7 :                             v->now++;
     495               1 :                         if (!ATEOS())
     496               1 :                             v->now++;
     497               1 :                         assert(v->nexttype == v->lasttype);
     498               1 :                         goto next_restart;
     499              42 :                     case CHR('='):  /* positive lookahead */
     500              42 :                         NOTE(REG_ULOOKAROUND);
     501              42 :                         RETV(LACON, LATYPE_AHEAD_POS);
     502                 :                         break;
     503              39 :                     case CHR('!'):  /* negative lookahead */
     504              39 :                         NOTE(REG_ULOOKAROUND);
     505              39 :                         RETV(LACON, LATYPE_AHEAD_NEG);
     506                 :                         break;
     507              53 :                     case CHR('<'):
     508              53 :                         if (ATEOS())
     509 UBC           0 :                             FAILW(REG_BADRPT);
     510 CBC          53 :                         switch (*v->now++)
     511                 :                         {
     512              39 :                             case CHR('='):  /* positive lookbehind */
     513              39 :                                 NOTE(REG_ULOOKAROUND);
     514              39 :                                 RETV(LACON, LATYPE_BEHIND_POS);
     515                 :                                 break;
     516              14 :                             case CHR('!'):  /* negative lookbehind */
     517              14 :                                 NOTE(REG_ULOOKAROUND);
     518              14 :                                 RETV(LACON, LATYPE_BEHIND_NEG);
     519                 :                                 break;
     520 UBC           0 :                             default:
     521               0 :                                 FAILW(REG_BADRPT);
     522                 :                                 break;
     523                 :                         }
     524                 :                         assert(NOTREACHED);
     525                 :                         break;
     526 CBC           1 :                     default:
     527               1 :                         FAILW(REG_BADRPT);
     528                 :                         break;
     529                 :                 }
     530                 :                 assert(NOTREACHED);
     531                 :             }
     532            2188 :             RETV('(', 1);
     533                 :             break;
     534            2397 :         case CHR(')'):
     535            2397 :             if (LASTTYPE('('))
     536              23 :                 NOTE(REG_UUNSPEC);
     537            2397 :             RETV(')', c);
     538                 :             break;
     539             821 :         case CHR('['):          /* easy except for [[:<:]] and [[:>:]] */
     540             821 :             if (HAVE(6) && *(v->now + 0) == CHR('[') &&
     541             147 :                 *(v->now + 1) == CHR(':') &&
     542             137 :                 (*(v->now + 2) == CHR('<') ||
     543             132 :                  *(v->now + 2) == CHR('>')) &&
     544              10 :                 *(v->now + 3) == CHR(':') &&
     545              10 :                 *(v->now + 4) == CHR(']') &&
     546              10 :                 *(v->now + 5) == CHR(']'))
     547                 :             {
     548              10 :                 c = *(v->now + 2);
     549              10 :                 v->now += 6;
     550              10 :                 NOTE(REG_UNONPOSIX);
     551              10 :                 RET((c == CHR('<')) ? '<' : '>');
     552                 :             }
     553             811 :             INTOCON(L_BRACK);
     554             811 :             if (NEXT1('^'))
     555                 :             {
     556             374 :                 v->now++;
     557             374 :                 RETV('[', 0);
     558                 :             }
     559             437 :             RETV('[', 1);
     560                 :             break;
     561            1747 :         case CHR('.'):
     562            1747 :             RET('.');
     563                 :             break;
     564            2608 :         case CHR('^'):
     565            2608 :             RET('^');
     566                 :             break;
     567            2128 :         case CHR('$'):
     568            2128 :             RET('$');
     569                 :             break;
     570            1296 :         case CHR('\\'):         /* mostly punt backslashes to code below */
     571            1296 :             if (ATEOS())
     572               1 :                 FAILW(REG_EESCAPE);
     573            1295 :             break;
     574           34530 :         default:                /* ordinary character */
     575           34530 :             RETV(PLAIN, c);
     576                 :             break;
     577                 :     }
     578                 : 
     579                 :     /* ERE/ARE backslash handling; backslash already eaten */
     580            1295 :     assert(!ATEOS());
     581            1295 :     if (!(v->cflags & REG_ADVF))
     582                 :     {                           /* only AREs have non-trivial escapes */
     583               4 :         if (iscalnum(*v->now))
     584                 :         {
     585               3 :             NOTE(REG_UBSALNUM);
     586               3 :             NOTE(REG_UUNSPEC);
     587                 :         }
     588               4 :         RETV(PLAIN, *v->now++);
     589                 :     }
     590            1291 :     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            1348 : 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            1348 :     assert(v->cflags & REG_ADVF);
     613                 : 
     614            1348 :     assert(!ATEOS());
     615            1348 :     c = *v->now++;
     616            1348 :     if (!iscalnum(c))
     617             863 :         RETV(PLAIN, c);
     618                 : 
     619             485 :     NOTE(REG_UNONPOSIX);
     620             485 :     switch (c)
     621                 :     {
     622               1 :         case CHR('a'):
     623               1 :             RETV(PLAIN, chrnamed(v, alert, ENDOF(alert), CHR('\007')));
     624                 :             break;
     625              11 :         case CHR('A'):
     626              11 :             RETV(SBEGIN, 0);
     627                 :             break;
     628              13 :         case CHR('b'):
     629              13 :             RETV(PLAIN, CHR('\b'));
     630                 :             break;
     631               5 :         case CHR('B'):
     632               5 :             RETV(PLAIN, CHR('\\'));
     633                 :             break;
     634               2 :         case CHR('c'):
     635               2 :             NOTE(REG_UUNPORT);
     636               2 :             if (ATEOS())
     637 UBC           0 :                 FAILW(REG_EESCAPE);
     638 CBC           2 :             RETV(PLAIN, (chr) (*v->now++ & 037));
     639                 :             break;
     640              91 :         case CHR('d'):
     641              91 :             NOTE(REG_ULOCALE);
     642              91 :             RETV(CCLASSS, CC_DIGIT);
     643                 :             break;
     644              12 :         case CHR('D'):
     645              12 :             NOTE(REG_ULOCALE);
     646              12 :             RETV(CCLASSC, CC_DIGIT);
     647                 :             break;
     648               1 :         case CHR('e'):
     649               1 :             NOTE(REG_UUNPORT);
     650               1 :             RETV(PLAIN, chrnamed(v, esc, ENDOF(esc), CHR('\033')));
     651                 :             break;
     652               1 :         case CHR('f'):
     653               1 :             RETV(PLAIN, CHR('\f'));
     654                 :             break;
     655              17 :         case CHR('m'):
     656              17 :             RET('<');
     657                 :             break;
     658              14 :         case CHR('M'):
     659              14 :             RET('>');
     660                 :             break;
     661               6 :         case CHR('n'):
     662               6 :             RETV(PLAIN, CHR('\n'));
     663                 :             break;
     664               5 :         case CHR('r'):
     665               5 :             RETV(PLAIN, CHR('\r'));
     666                 :             break;
     667              28 :         case CHR('s'):
     668              28 :             NOTE(REG_ULOCALE);
     669              28 :             RETV(CCLASSS, CC_SPACE);
     670                 :             break;
     671              17 :         case CHR('S'):
     672              17 :             NOTE(REG_ULOCALE);
     673              17 :             RETV(CCLASSC, CC_SPACE);
     674                 :             break;
     675               2 :         case CHR('t'):
     676               2 :             RETV(PLAIN, CHR('\t'));
     677                 :             break;
     678              28 :         case CHR('u'):
     679              28 :             c = lexdigits(v, 16, 4, 4);
     680              28 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     681               1 :                 FAILW(REG_EESCAPE);
     682              27 :             RETV(PLAIN, c);
     683                 :             break;
     684              10 :         case CHR('U'):
     685              10 :             c = lexdigits(v, 16, 8, 8);
     686              10 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     687               5 :                 FAILW(REG_EESCAPE);
     688               5 :             RETV(PLAIN, c);
     689                 :             break;
     690               1 :         case CHR('v'):
     691               1 :             RETV(PLAIN, CHR('\v'));
     692                 :             break;
     693              50 :         case CHR('w'):
     694              50 :             NOTE(REG_ULOCALE);
     695              50 :             RETV(CCLASSS, CC_WORD);
     696                 :             break;
     697               8 :         case CHR('W'):
     698               8 :             NOTE(REG_ULOCALE);
     699               8 :             RETV(CCLASSC, CC_WORD);
     700                 :             break;
     701               6 :         case CHR('x'):
     702               6 :             NOTE(REG_UUNPORT);
     703               6 :             c = lexdigits(v, 16, 1, 255);   /* REs >255 long outside spec */
     704               6 :             if (ISERR() || !CHR_IS_IN_RANGE(c))
     705               4 :                 FAILW(REG_EESCAPE);
     706               2 :             RETV(PLAIN, c);
     707                 :             break;
     708               9 :         case CHR('y'):
     709               9 :             NOTE(REG_ULOCALE);
     710               9 :             RETV(WBDRY, 0);
     711                 :             break;
     712              19 :         case CHR('Y'):
     713              19 :             NOTE(REG_ULOCALE);
     714              19 :             RETV(NWBDRY, 0);
     715                 :             break;
     716               6 :         case CHR('Z'):
     717               6 :             RETV(SEND, 0);
     718                 :             break;
     719             116 :         case CHR('1'):
     720                 :         case CHR('2'):
     721                 :         case CHR('3'):
     722                 :         case CHR('4'):
     723                 :         case CHR('5'):
     724                 :         case CHR('6'):
     725                 :         case CHR('7'):
     726                 :         case CHR('8'):
     727                 :         case CHR('9'):
     728             116 :             save = v->now;
     729             116 :             v->now--;            /* put first digit back */
     730             116 :             c = lexdigits(v, 10, 1, 255);   /* REs >255 long outside spec */
     731             116 :             if (ISERR())
     732 UBC           0 :                 FAILW(REG_EESCAPE);
     733                 :             /* ugly heuristic (first test is "exactly 1 digit?") */
     734 CBC         116 :             if (v->now == save || ((int) c > 0 && (int) c <= v->nsubexp))
     735                 :             {
     736             111 :                 NOTE(REG_UBACKREF);
     737             111 :                 RETV(BACKREF, c);
     738                 :             }
     739                 :             /* oops, doesn't look like it's a backref after all... */
     740               5 :             v->now = save;
     741                 :             /* and fall through into octal number */
     742                 :             /* FALLTHROUGH */
     743              10 :         case CHR('0'):
     744              10 :             NOTE(REG_UUNPORT);
     745              10 :             v->now--;            /* put first digit back */
     746              10 :             c = lexdigits(v, 8, 1, 3);
     747              10 :             if (ISERR())
     748 UBC           0 :                 FAILW(REG_EESCAPE);
     749 CBC          10 :             if (c > 0xff)
     750                 :             {
     751                 :                 /* out of range, so we handled one digit too much */
     752               1 :                 v->now--;
     753               1 :                 c >>= 3;
     754                 :             }
     755              10 :             RETV(PLAIN, c);
     756                 :             break;
     757               1 :         default:
     758               1 :             assert(iscalpha(c));
     759               1 :             FAILW(REG_EESCAPE); /* unknown alphabetic escape */
     760                 :             break;
     761                 :     }
     762                 :     assert(NOTREACHED);
     763                 : }
     764                 : 
     765                 : /*
     766                 :  * lexdigits - slurp up digits and return chr value
     767                 :  *
     768                 :  * This does not account for overflow; callers should range-check the result
     769                 :  * if maxlen is large enough to make that possible.
     770                 :  */
     771                 : static chr                      /* chr value; errors signalled via ERR */
     772             170 : lexdigits(struct vars *v,
     773                 :           int base,
     774                 :           int minlen,
     775                 :           int maxlen)
     776                 : {
     777                 :     uchr        n;              /* unsigned to avoid overflow misbehavior */
     778                 :     int         len;
     779                 :     chr         c;
     780                 :     int         d;
     781             170 :     const uchr  ub = (uchr) base;
     782                 : 
     783             170 :     n = 0;
     784             543 :     for (len = 0; len < maxlen && !ATEOS(); len++)
     785                 :     {
     786             460 :         c = *v->now++;
     787             460 :         switch (c)
     788                 :         {
     789             343 :             case CHR('0'):
     790                 :             case CHR('1'):
     791                 :             case CHR('2'):
     792                 :             case CHR('3'):
     793                 :             case CHR('4'):
     794                 :             case CHR('5'):
     795                 :             case CHR('6'):
     796                 :             case CHR('7'):
     797                 :             case CHR('8'):
     798                 :             case CHR('9'):
     799             343 :                 d = DIGITVAL(c);
     800             343 :                 break;
     801 UBC           0 :             case CHR('a'):
     802                 :             case CHR('A'):
     803               0 :                 d = 10;
     804               0 :                 break;
     805 CBC           8 :             case CHR('b'):
     806                 :             case CHR('B'):
     807               8 :                 d = 11;
     808               8 :                 break;
     809               2 :             case CHR('c'):
     810                 :             case CHR('C'):
     811               2 :                 d = 12;
     812               2 :                 break;
     813 UBC           0 :             case CHR('d'):
     814                 :             case CHR('D'):
     815               0 :                 d = 13;
     816               0 :                 break;
     817 CBC           2 :             case CHR('e'):
     818                 :             case CHR('E'):
     819               2 :                 d = 14;
     820               2 :                 break;
     821              29 :             case CHR('f'):
     822                 :             case CHR('F'):
     823              29 :                 d = 15;
     824              29 :                 break;
     825              76 :             default:
     826              76 :                 v->now--;        /* oops, not a digit at all */
     827              76 :                 d = -1;
     828              76 :                 break;
     829                 :         }
     830                 : 
     831             460 :         if (d >= base)
     832                 :         {                       /* not a plausible digit */
     833              11 :             v->now--;
     834              11 :             d = -1;
     835                 :         }
     836             460 :         if (d < 0)
     837              87 :             break;              /* NOTE BREAK OUT */
     838             373 :         n = n * ub + (uchr) d;
     839                 :     }
     840             170 :     if (len < minlen)
     841               7 :         ERR(REG_EESCAPE);
     842                 : 
     843             170 :     return (chr) n;
     844                 : }
     845                 : 
     846                 : /*
     847                 :  * brenext - get next BRE token
     848                 :  *
     849                 :  * This is much like EREs except for all the stupid backslashes and the
     850                 :  * context-dependency of some things.
     851                 :  */
     852                 : static int                      /* 1 normal, 0 failure */
     853             322 : brenext(struct vars *v,
     854                 :         chr c)
     855                 : {
     856             322 :     switch (c)
     857                 :     {
     858              23 :         case CHR('*'):
     859              23 :             if (LASTTYPE(EMPTY) || LASTTYPE('(') || LASTTYPE('^'))
     860               6 :                 RETV(PLAIN, c);
     861              17 :             RETV('*', 1);
     862                 :             break;
     863              74 :         case CHR('['):
     864              74 :             if (HAVE(6) && *(v->now + 0) == CHR('[') &&
     865              22 :                 *(v->now + 1) == CHR(':') &&
     866              12 :                 (*(v->now + 2) == CHR('<') ||
     867               8 :                  *(v->now + 2) == CHR('>')) &&
     868               8 :                 *(v->now + 3) == CHR(':') &&
     869               8 :                 *(v->now + 4) == CHR(']') &&
     870               8 :                 *(v->now + 5) == CHR(']'))
     871                 :             {
     872               8 :                 c = *(v->now + 2);
     873               8 :                 v->now += 6;
     874               8 :                 NOTE(REG_UNONPOSIX);
     875               8 :                 RET((c == CHR('<')) ? '<' : '>');
     876                 :             }
     877              66 :             INTOCON(L_BRACK);
     878              66 :             if (NEXT1('^'))
     879                 :             {
     880               6 :                 v->now++;
     881               6 :                 RETV('[', 0);
     882                 :             }
     883              60 :             RETV('[', 1);
     884                 :             break;
     885               4 :         case CHR('.'):
     886               4 :             RET('.');
     887                 :             break;
     888              18 :         case CHR('^'):
     889              18 :             if (LASTTYPE(EMPTY))
     890              14 :                 RET('^');
     891               4 :             if (LASTTYPE('('))
     892                 :             {
     893               1 :                 NOTE(REG_UUNSPEC);
     894               1 :                 RET('^');
     895                 :             }
     896               3 :             RETV(PLAIN, c);
     897                 :             break;
     898              15 :         case CHR('$'):
     899              15 :             if (v->cflags & REG_EXPANDED)
     900 UBC           0 :                 skip(v);
     901 CBC          15 :             if (ATEOS())
     902              11 :                 RET('$');
     903               4 :             if (NEXT2('\\', ')'))
     904                 :             {
     905               1 :                 NOTE(REG_UUNSPEC);
     906               1 :                 RET('$');
     907                 :             }
     908               3 :             RETV(PLAIN, c);
     909                 :             break;
     910              26 :         case CHR('\\'):
     911              26 :             break;              /* see below */
     912             162 :         default:
     913             162 :             RETV(PLAIN, c);
     914                 :             break;
     915                 :     }
     916                 : 
     917              26 :     assert(c == CHR('\\'));
     918                 : 
     919              26 :     if (ATEOS())
     920               1 :         FAILW(REG_EESCAPE);
     921                 : 
     922              25 :     c = *v->now++;
     923              25 :     switch (c)
     924                 :     {
     925               3 :         case CHR('{'):
     926               3 :             INTOCON(L_BBND);
     927               3 :             NOTE(REG_UBOUNDS);
     928               3 :             RET('{');
     929                 :             break;
     930               6 :         case CHR('('):
     931               6 :             RETV('(', 1);
     932                 :             break;
     933               6 :         case CHR(')'):
     934               6 :             RETV(')', c);
     935                 :             break;
     936               3 :         case CHR('<'):
     937               3 :             NOTE(REG_UNONPOSIX);
     938               3 :             RET('<');
     939                 :             break;
     940               3 :         case CHR('>'):
     941               3 :             NOTE(REG_UNONPOSIX);
     942               3 :             RET('>');
     943                 :             break;
     944               2 :         case CHR('1'):
     945                 :         case CHR('2'):
     946                 :         case CHR('3'):
     947                 :         case CHR('4'):
     948                 :         case CHR('5'):
     949                 :         case CHR('6'):
     950                 :         case CHR('7'):
     951                 :         case CHR('8'):
     952                 :         case CHR('9'):
     953               2 :             NOTE(REG_UBACKREF);
     954               2 :             RETV(BACKREF, (chr) DIGITVAL(c));
     955                 :             break;
     956               2 :         default:
     957               2 :             if (iscalnum(c))
     958                 :             {
     959               2 :                 NOTE(REG_UBSALNUM);
     960               2 :                 NOTE(REG_UUNSPEC);
     961                 :             }
     962               2 :             RETV(PLAIN, c);
     963                 :             break;
     964                 :     }
     965                 : 
     966                 :     assert(NOTREACHED);
     967                 :     return 0;
     968                 : }
     969                 : 
     970                 : /*
     971                 :  * skip - skip white space and comments in expanded form
     972                 :  */
     973                 : static void
     974             829 : skip(struct vars *v)
     975                 : {
     976             829 :     const chr  *start = v->now;
     977                 : 
     978             829 :     assert(v->cflags & REG_EXPANDED);
     979                 : 
     980                 :     for (;;)
     981                 :     {
     982            1342 :         while (!ATEOS() && iscspace(*v->now))
     983             443 :             v->now++;
     984             899 :         if (ATEOS() || *v->now != CHR('#'))
     985                 :             break;              /* NOTE BREAK OUT */
     986              70 :         assert(NEXT1('#'));
     987             704 :         while (!ATEOS() && *v->now != CHR('\n'))
     988             634 :             v->now++;
     989                 :         /* leave the newline to be picked up by the iscspace loop */
     990                 :     }
     991                 : 
     992             829 :     if (v->now != start)
     993             103 :         NOTE(REG_UNONPOSIX);
     994             829 : }
     995                 : 
     996                 : /*
     997                 :  * newline - return the chr for a newline
     998                 :  *
     999                 :  * This helps confine use of CHR to this source file.
    1000                 :  */
    1001                 : static chr
    1002             519 : newline(void)
    1003                 : {
    1004             519 :     return CHR('\n');
    1005                 : }
    1006                 : 
    1007                 : /*
    1008                 :  * chrnamed - return the chr known by a given (chr string) name
    1009                 :  *
    1010                 :  * The code is a bit clumsy, but this routine gets only such specialized
    1011                 :  * use that it hardly matters.
    1012                 :  */
    1013                 : static chr
    1014               2 : chrnamed(struct vars *v,
    1015                 :          const chr *startp,     /* start of name */
    1016                 :          const chr *endp,       /* just past end of name */
    1017                 :          chr lastresort)        /* what to return if name lookup fails */
    1018                 : {
    1019                 :     chr         c;
    1020                 :     int         errsave;
    1021                 :     int         e;
    1022                 :     struct cvec *cv;
    1023                 : 
    1024               2 :     errsave = v->err;
    1025               2 :     v->err = 0;
    1026               2 :     c = element(v, startp, endp);
    1027               2 :     e = v->err;
    1028               2 :     v->err = errsave;
    1029                 : 
    1030               2 :     if (e != 0)
    1031 UBC           0 :         return lastresort;
    1032                 : 
    1033 CBC           2 :     cv = range(v, c, c, 0);
    1034               2 :     if (cv->nchrs == 0)
    1035               2 :         return lastresort;
    1036 UBC           0 :     return cv->chrs[0];
    1037                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a