LCOV - code coverage report
Current view: top level - src/backend/regex - regc_color.c (source / functions) Hit Total Coverage
Test: PostgreSQL 15devel Lines: 396 429 92.3 %
Date: 2021-12-09 03:08:47 Functions: 21 21 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * colorings of characters
       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_color.c
      32             :  *
      33             :  *
      34             :  * Note that there are some incestuous relationships between this code and
      35             :  * NFA arc maintenance, which perhaps ought to be cleaned up sometime.
      36             :  */
      37             : 
      38             : 
      39             : 
      40             : #define CISERR()    VISERR(cm->v)
      41             : #define CERR(e)     VERR(cm->v, (e))
      42             : 
      43             : 
      44             : 
      45             : /*
      46             :  * initcm - set up new colormap
      47             :  */
      48             : static void
      49        5404 : initcm(struct vars *v,
      50             :        struct colormap *cm)
      51             : {
      52             :     struct colordesc *cd;
      53             : 
      54        5404 :     cm->magic = CMMAGIC;
      55        5404 :     cm->v = v;
      56             : 
      57        5404 :     cm->ncds = NINLINECDS;
      58        5404 :     cm->cd = cm->cdspace;
      59        5404 :     cm->max = 0;
      60        5404 :     cm->free = 0;
      61             : 
      62        5404 :     cd = cm->cd;             /* cm->cd[WHITE] */
      63        5404 :     cd->nschrs = MAX_SIMPLE_CHR - CHR_MIN + 1;
      64        5404 :     cd->nuchrs = 1;
      65        5404 :     cd->sub = NOSUB;
      66        5404 :     cd->arcs = NULL;
      67        5404 :     cd->firstchr = CHR_MIN;
      68        5404 :     cd->flags = 0;
      69             : 
      70        5404 :     cm->locolormap = (color *)
      71        5404 :         MALLOC((MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color));
      72        5404 :     if (cm->locolormap == NULL)
      73             :     {
      74           0 :         CERR(REG_ESPACE);
      75           0 :         cm->cmranges = NULL; /* prevent failure during freecm */
      76           0 :         cm->hicolormap = NULL;
      77           0 :         return;
      78             :     }
      79             :     /* this memset relies on WHITE being zero: */
      80        5404 :     memset(cm->locolormap, WHITE,
      81             :            (MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color));
      82             : 
      83        5404 :     memset(cm->classbits, 0, sizeof(cm->classbits));
      84        5404 :     cm->numcmranges = 0;
      85        5404 :     cm->cmranges = NULL;
      86        5404 :     cm->maxarrayrows = 4;        /* arbitrary initial allocation */
      87        5404 :     cm->hiarrayrows = 1;     /* but we have only one row/col initially */
      88        5404 :     cm->hiarraycols = 1;
      89        5404 :     cm->hicolormap = (color *) MALLOC(cm->maxarrayrows * sizeof(color));
      90        5404 :     if (cm->hicolormap == NULL)
      91             :     {
      92           0 :         CERR(REG_ESPACE);
      93           0 :         return;
      94             :     }
      95             :     /* initialize the "all other characters" row to WHITE */
      96        5404 :     cm->hicolormap[0] = WHITE;
      97             : }
      98             : 
      99             : /*
     100             :  * freecm - free dynamically-allocated things in a colormap
     101             :  */
     102             : static void
     103        1912 : freecm(struct colormap *cm)
     104             : {
     105        1912 :     cm->magic = 0;
     106        1912 :     if (cm->cd != cm->cdspace)
     107         100 :         FREE(cm->cd);
     108        1912 :     if (cm->locolormap != NULL)
     109        1912 :         FREE(cm->locolormap);
     110        1912 :     if (cm->cmranges != NULL)
     111          16 :         FREE(cm->cmranges);
     112        1912 :     if (cm->hicolormap != NULL)
     113        1912 :         FREE(cm->hicolormap);
     114        1912 : }
     115             : 
     116             : /*
     117             :  * pg_reg_getcolor - slow case of GETCOLOR()
     118             :  */
     119             : color
     120         110 : pg_reg_getcolor(struct colormap *cm, chr c)
     121             : {
     122             :     int         rownum,
     123             :                 colnum,
     124             :                 low,
     125             :                 high;
     126             : 
     127             :     /* Should not be used for chrs in the locolormap */
     128             :     assert(c > MAX_SIMPLE_CHR);
     129             : 
     130             :     /*
     131             :      * Find which row it's in.  The colormapranges are in order, so we can use
     132             :      * binary search.
     133             :      */
     134         110 :     rownum = 0;                 /* if no match, use array row zero */
     135         110 :     low = 0;
     136         110 :     high = cm->numcmranges;
     137         176 :     while (low < high)
     138             :     {
     139         112 :         int         middle = low + (high - low) / 2;
     140         112 :         const colormaprange *cmr = &cm->cmranges[middle];
     141             : 
     142         112 :         if (c < cmr->cmin)
     143          56 :             high = middle;
     144          56 :         else if (c > cmr->cmax)
     145          10 :             low = middle + 1;
     146             :         else
     147             :         {
     148          46 :             rownum = cmr->rownum;    /* found a match */
     149          46 :             break;
     150             :         }
     151             :     }
     152             : 
     153             :     /*
     154             :      * Find which column it's in --- this is all locale-dependent.
     155             :      */
     156         110 :     if (cm->hiarraycols > 1)
     157             :     {
     158          64 :         colnum = cclass_column_index(cm, c);
     159          64 :         return cm->hicolormap[rownum * cm->hiarraycols + colnum];
     160             :     }
     161             :     else
     162             :     {
     163             :         /* fast path if no relevant cclasses */
     164          46 :         return cm->hicolormap[rownum];
     165             :     }
     166             : }
     167             : 
     168             : /*
     169             :  * maxcolor - report largest color number in use
     170             :  */
     171             : static color
     172       13410 : maxcolor(struct colormap *cm)
     173             : {
     174       13410 :     if (CISERR())
     175           0 :         return COLORLESS;
     176             : 
     177       13410 :     return (color) cm->max;
     178             : }
     179             : 
     180             : /*
     181             :  * newcolor - find a new color (must be assigned at once)
     182             :  * Beware:  may relocate the colordescs.
     183             :  */
     184             : static color                    /* COLORLESS for error */
     185       46424 : newcolor(struct colormap *cm)
     186             : {
     187             :     struct colordesc *cd;
     188             :     size_t      n;
     189             : 
     190       46424 :     if (CISERR())
     191           4 :         return COLORLESS;
     192             : 
     193       46420 :     if (cm->free != 0)
     194             :     {
     195             :         assert(cm->free > 0);
     196             :         assert((size_t) cm->free < cm->ncds);
     197         268 :         cd = &cm->cd[cm->free];
     198             :         assert(UNUSEDCOLOR(cd));
     199             :         assert(cd->arcs == NULL);
     200         268 :         cm->free = cd->sub;
     201             :     }
     202       46152 :     else if (cm->max < cm->ncds - 1)
     203             :     {
     204       43828 :         cm->max++;
     205       43828 :         cd = &cm->cd[cm->max];
     206             :     }
     207             :     else
     208             :     {
     209             :         /* oops, must allocate more */
     210             :         struct colordesc *newCd;
     211             : 
     212        2324 :         if (cm->max == MAX_COLOR)
     213             :         {
     214           0 :             CERR(REG_ECOLORS);
     215           0 :             return COLORLESS;   /* too many colors */
     216             :         }
     217             : 
     218        2324 :         n = cm->ncds * 2;
     219        2324 :         if (n > MAX_COLOR + 1)
     220           0 :             n = MAX_COLOR + 1;
     221        2324 :         if (cm->cd == cm->cdspace)
     222             :         {
     223        2284 :             newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc));
     224        2284 :             if (newCd != NULL)
     225        2284 :                 memcpy(VS(newCd), VS(cm->cdspace), cm->ncds *
     226             :                        sizeof(struct colordesc));
     227             :         }
     228             :         else
     229             :             newCd = (struct colordesc *)
     230          40 :                 REALLOC(cm->cd, n * sizeof(struct colordesc));
     231        2324 :         if (newCd == NULL)
     232             :         {
     233           0 :             CERR(REG_ESPACE);
     234           0 :             return COLORLESS;
     235             :         }
     236        2324 :         cm->cd = newCd;
     237        2324 :         cm->ncds = n;
     238             :         assert(cm->max < cm->ncds - 1);
     239        2324 :         cm->max++;
     240        2324 :         cd = &cm->cd[cm->max];
     241             :     }
     242             : 
     243       46420 :     cd->nschrs = 0;
     244       46420 :     cd->nuchrs = 0;
     245       46420 :     cd->sub = NOSUB;
     246       46420 :     cd->arcs = NULL;
     247       46420 :     cd->firstchr = CHR_MIN;      /* in case never set otherwise */
     248       46420 :     cd->flags = 0;
     249             : 
     250       46420 :     return (color) (cd - cm->cd);
     251             : }
     252             : 
     253             : /*
     254             :  * freecolor - free a color (must have no arcs or subcolor)
     255             :  */
     256             : static void
     257         346 : freecolor(struct colormap *cm,
     258             :           color co)
     259             : {
     260         346 :     struct colordesc *cd = &cm->cd[co];
     261             :     color       pco,
     262             :                 nco;            /* for freelist scan */
     263             : 
     264             :     assert(co >= 0);
     265         346 :     if (co == WHITE)
     266           0 :         return;
     267             : 
     268             :     assert(cd->arcs == NULL);
     269             :     assert(cd->sub == NOSUB);
     270             :     assert(cd->nschrs == 0);
     271             :     assert(cd->nuchrs == 0);
     272         346 :     cd->flags = FREECOL;
     273             : 
     274         346 :     if ((size_t) co == cm->max)
     275             :     {
     276         152 :         while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max]))
     277          78 :             cm->max--;
     278             :         assert(cm->free >= 0);
     279          78 :         while ((size_t) cm->free > cm->max)
     280           4 :             cm->free = cm->cd[cm->free].sub;
     281          74 :         if (cm->free > 0)
     282             :         {
     283             :             assert(cm->free < cm->max);
     284           4 :             pco = cm->free;
     285           4 :             nco = cm->cd[pco].sub;
     286           4 :             while (nco > 0)
     287           0 :                 if ((size_t) nco > cm->max)
     288             :                 {
     289             :                     /* take this one out of freelist */
     290           0 :                     nco = cm->cd[nco].sub;
     291           0 :                     cm->cd[pco].sub = nco;
     292             :                 }
     293             :                 else
     294             :                 {
     295             :                     assert(nco < cm->max);
     296           0 :                     pco = nco;
     297           0 :                     nco = cm->cd[pco].sub;
     298             :                 }
     299             :         }
     300             :     }
     301             :     else
     302             :     {
     303         272 :         cd->sub = cm->free;
     304         272 :         cm->free = (color) (cd - cm->cd);
     305             :     }
     306             : }
     307             : 
     308             : /*
     309             :  * pseudocolor - allocate a false color, to be managed by other means
     310             :  */
     311             : static color
     312       20712 : pseudocolor(struct colormap *cm)
     313             : {
     314             :     color       co;
     315             :     struct colordesc *cd;
     316             : 
     317       20712 :     co = newcolor(cm);
     318       20712 :     if (CISERR())
     319           0 :         return COLORLESS;
     320       20712 :     cd = &cm->cd[co];
     321       20712 :     cd->nschrs = 0;
     322       20712 :     cd->nuchrs = 1;              /* pretend it is in the upper map */
     323       20712 :     cd->sub = NOSUB;
     324       20712 :     cd->arcs = NULL;
     325       20712 :     cd->firstchr = CHR_MIN;
     326       20712 :     cd->flags = PSEUDO;
     327       20712 :     return co;
     328             : }
     329             : 
     330             : /*
     331             :  * subcolor - allocate a new subcolor (if necessary) to this chr
     332             :  *
     333             :  * This works only for chrs that map into the low color map.
     334             :  */
     335             : static color
     336      445226 : subcolor(struct colormap *cm, chr c)
     337             : {
     338             :     color       co;             /* current color of c */
     339             :     color       sco;            /* new subcolor */
     340             : 
     341             :     assert(c <= MAX_SIMPLE_CHR);
     342             : 
     343      445226 :     co = cm->locolormap[c - CHR_MIN];
     344      445226 :     sco = newsub(cm, co);
     345      445226 :     if (CISERR())
     346           4 :         return COLORLESS;
     347             :     assert(sco != COLORLESS);
     348             : 
     349      445222 :     if (co == sco)              /* already in an open subcolor */
     350       23396 :         return co;              /* rest is redundant */
     351      421826 :     cm->cd[co].nschrs--;
     352      421826 :     if (cm->cd[sco].nschrs == 0)
     353       25622 :         cm->cd[sco].firstchr = c;
     354      421826 :     cm->cd[sco].nschrs++;
     355      421826 :     cm->locolormap[c - CHR_MIN] = sco;
     356      421826 :     return sco;
     357             : }
     358             : 
     359             : /*
     360             :  * subcolorhi - allocate a new subcolor (if necessary) to this colormap entry
     361             :  *
     362             :  * This is the same processing as subcolor(), but for entries in the high
     363             :  * colormap, which do not necessarily correspond to exactly one chr code.
     364             :  */
     365             : static color
     366        1572 : subcolorhi(struct colormap *cm, color *pco)
     367             : {
     368             :     color       co;             /* current color of entry */
     369             :     color       sco;            /* new subcolor */
     370             : 
     371        1572 :     co = *pco;
     372        1572 :     sco = newsub(cm, co);
     373        1572 :     if (CISERR())
     374           0 :         return COLORLESS;
     375             :     assert(sco != COLORLESS);
     376             : 
     377        1572 :     if (co == sco)              /* already in an open subcolor */
     378          20 :         return co;              /* rest is redundant */
     379        1552 :     cm->cd[co].nuchrs--;
     380        1552 :     cm->cd[sco].nuchrs++;
     381        1552 :     *pco = sco;
     382        1552 :     return sco;
     383             : }
     384             : 
     385             : /*
     386             :  * newsub - allocate a new subcolor (if necessary) for a color
     387             :  */
     388             : static color
     389      446798 : newsub(struct colormap *cm,
     390             :        color co)
     391             : {
     392             :     color       sco;            /* new subcolor */
     393             : 
     394      446798 :     sco = cm->cd[co].sub;
     395      446798 :     if (sco == NOSUB)
     396             :     {                           /* color has no open subcolor */
     397             :         /* optimization: singly-referenced color need not be subcolored */
     398       49122 :         if ((cm->cd[co].nschrs + cm->cd[co].nuchrs) == 1)
     399       23410 :             return co;
     400       25712 :         sco = newcolor(cm);     /* must create subcolor */
     401       25712 :         if (sco == COLORLESS)
     402             :         {
     403             :             assert(CISERR());
     404           4 :             return COLORLESS;
     405             :         }
     406       25708 :         cm->cd[co].sub = sco;
     407       25708 :         cm->cd[sco].sub = sco;   /* open subcolor points to self */
     408             :     }
     409             :     assert(sco != NOSUB);
     410             : 
     411      423384 :     return sco;
     412             : }
     413             : 
     414             : /*
     415             :  * newhicolorrow - get a new row in the hicolormap, cloning it from oldrow
     416             :  *
     417             :  * Returns array index of new row.  Note the array might move.
     418             :  */
     419             : static int
     420         292 : newhicolorrow(struct colormap *cm,
     421             :               int oldrow)
     422             : {
     423         292 :     int         newrow = cm->hiarrayrows;
     424             :     color      *newrowptr;
     425             :     int         i;
     426             : 
     427             :     /* Assign a fresh array row index, enlarging storage if needed */
     428         292 :     if (newrow >= cm->maxarrayrows)
     429             :     {
     430             :         color      *newarray;
     431             : 
     432          14 :         if (cm->maxarrayrows >= INT_MAX / (cm->hiarraycols * 2))
     433             :         {
     434           0 :             CERR(REG_ESPACE);
     435           0 :             return 0;
     436             :         }
     437          14 :         newarray = (color *) REALLOC(cm->hicolormap,
     438             :                                      cm->maxarrayrows * 2 *
     439             :                                      cm->hiarraycols * sizeof(color));
     440          14 :         if (newarray == NULL)
     441             :         {
     442           0 :             CERR(REG_ESPACE);
     443           0 :             return 0;
     444             :         }
     445          14 :         cm->hicolormap = newarray;
     446          14 :         cm->maxarrayrows *= 2;
     447             :     }
     448         292 :     cm->hiarrayrows++;
     449             : 
     450             :     /* Copy old row data */
     451         292 :     newrowptr = &cm->hicolormap[newrow * cm->hiarraycols];
     452         292 :     memcpy(newrowptr,
     453         292 :            &cm->hicolormap[oldrow * cm->hiarraycols],
     454         292 :            cm->hiarraycols * sizeof(color));
     455             : 
     456             :     /* Increase color reference counts to reflect new colormap entries */
     457        1382 :     for (i = 0; i < cm->hiarraycols; i++)
     458        1090 :         cm->cd[newrowptr[i]].nuchrs++;
     459             : 
     460         292 :     return newrow;
     461             : }
     462             : 
     463             : /*
     464             :  * newhicolorcols - create a new set of columns in the high colormap
     465             :  *
     466             :  * Essentially, extends the 2-D array to the right with a copy of itself.
     467             :  */
     468             : static void
     469         436 : newhicolorcols(struct colormap *cm)
     470             : {
     471             :     color      *newarray;
     472             :     int         r,
     473             :                 c;
     474             : 
     475         436 :     if (cm->hiarraycols >= INT_MAX / (cm->maxarrayrows * 2))
     476             :     {
     477           0 :         CERR(REG_ESPACE);
     478           0 :         return;
     479             :     }
     480         436 :     newarray = (color *) REALLOC(cm->hicolormap,
     481             :                                  cm->maxarrayrows *
     482             :                                  cm->hiarraycols * 2 * sizeof(color));
     483         436 :     if (newarray == NULL)
     484             :     {
     485           0 :         CERR(REG_ESPACE);
     486           0 :         return;
     487             :     }
     488         436 :     cm->hicolormap = newarray;
     489             : 
     490             :     /* Duplicate existing columns to the right, and increase ref counts */
     491             :     /* Must work backwards in the array because we realloc'd in place */
     492         872 :     for (r = cm->hiarrayrows - 1; r >= 0; r--)
     493             :     {
     494         436 :         color      *oldrowptr = &newarray[r * cm->hiarraycols];
     495         436 :         color      *newrowptr = &newarray[r * cm->hiarraycols * 2];
     496         436 :         color      *newrowptr2 = newrowptr + cm->hiarraycols;
     497             : 
     498         890 :         for (c = 0; c < cm->hiarraycols; c++)
     499             :         {
     500         454 :             color       co = oldrowptr[c];
     501             : 
     502         454 :             newrowptr[c] = newrowptr2[c] = co;
     503         454 :             cm->cd[co].nuchrs++;
     504             :         }
     505             :     }
     506             : 
     507         436 :     cm->hiarraycols *= 2;
     508             : }
     509             : 
     510             : /*
     511             :  * subcolorcvec - allocate new subcolors to cvec members, fill in arcs
     512             :  *
     513             :  * For each chr "c" represented by the cvec, do the equivalent of
     514             :  * newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp);
     515             :  *
     516             :  * Note that in typical cases, many of the subcolors are the same.
     517             :  * While newarc() would discard duplicate arc requests, we can save
     518             :  * some cycles by not calling it repetitively to begin with.  This is
     519             :  * mechanized with the "lastsubcolor" state variable.
     520             :  */
     521             : static void
     522        2652 : subcolorcvec(struct vars *v,
     523             :              struct cvec *cv,
     524             :              struct state *lp,
     525             :              struct state *rp)
     526             : {
     527        2652 :     struct colormap *cm = v->cm;
     528        2652 :     color       lastsubcolor = COLORLESS;
     529             :     chr         ch,
     530             :                 from,
     531             :                 to;
     532             :     const chr  *p;
     533             :     int         i;
     534             : 
     535             :     /* ordinary characters */
     536       11314 :     for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--)
     537             :     {
     538        8662 :         ch = *p;
     539        8662 :         subcoloronechr(v, ch, lp, rp, &lastsubcolor);
     540        8662 :         NOERR();
     541             :     }
     542             : 
     543             :     /* and the ranges */
     544       12274 :     for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--)
     545             :     {
     546        9622 :         from = *p;
     547        9622 :         to = *(p + 1);
     548        9622 :         if (from <= MAX_SIMPLE_CHR)
     549             :         {
     550             :             /* deal with simple chars one at a time */
     551        9606 :             chr         lim = (to <= MAX_SIMPLE_CHR) ? to : MAX_SIMPLE_CHR;
     552             : 
     553      402176 :             while (from <= lim)
     554             :             {
     555      392570 :                 color       sco = subcolor(cm, from);
     556             : 
     557      392570 :                 NOERR();
     558      392570 :                 if (sco != lastsubcolor)
     559             :                 {
     560        3946 :                     newarc(v->nfa, PLAIN, sco, lp, rp);
     561        3946 :                     NOERR();
     562        3946 :                     lastsubcolor = sco;
     563             :                 }
     564      392570 :                 from++;
     565             :             }
     566             :         }
     567             :         /* deal with any part of the range that's above MAX_SIMPLE_CHR */
     568        9622 :         if (from < to)
     569          16 :             subcoloronerange(v, from, to, lp, rp, &lastsubcolor);
     570        9606 :         else if (from == to)
     571           0 :             subcoloronechr(v, from, lp, rp, &lastsubcolor);
     572        9622 :         NOERR();
     573             :     }
     574             : 
     575             :     /* and deal with cclass if any */
     576        2652 :     if (cv->cclasscode >= 0)
     577             :     {
     578             :         int         classbit;
     579             :         color      *pco;
     580             :         int         r,
     581             :                     c;
     582             : 
     583             :         /* Enlarge array if we don't have a column bit assignment for cclass */
     584         486 :         if (cm->classbits[cv->cclasscode] == 0)
     585             :         {
     586         436 :             cm->classbits[cv->cclasscode] = cm->hiarraycols;
     587         436 :             newhicolorcols(cm);
     588         436 :             NOERR();
     589             :         }
     590             :         /* Apply subcolorhi() and make arc for each entry in relevant cols */
     591         486 :         classbit = cm->classbits[cv->cclasscode];
     592         486 :         pco = cm->hicolormap;
     593         972 :         for (r = 0; r < cm->hiarrayrows; r++)
     594             :         {
     595        1494 :             for (c = 0; c < cm->hiarraycols; c++)
     596             :             {
     597        1008 :                 if (c & classbit)
     598             :                 {
     599         504 :                     color       sco = subcolorhi(cm, pco);
     600             : 
     601         504 :                     NOERR();
     602             :                     /* add the arc if needed */
     603         504 :                     if (sco != lastsubcolor)
     604             :                     {
     605          58 :                         newarc(v->nfa, PLAIN, sco, lp, rp);
     606          58 :                         NOERR();
     607          58 :                         lastsubcolor = sco;
     608             :                     }
     609             :                 }
     610        1008 :                 pco++;
     611             :             }
     612             :         }
     613             :     }
     614             : }
     615             : 
     616             : /*
     617             :  * subcoloronechr - do subcolorcvec's work for a singleton chr
     618             :  *
     619             :  * We could just let subcoloronerange do this, but it's a bit more efficient
     620             :  * if we exploit the single-chr case.  Also, callers find it useful for this
     621             :  * to be able to handle both low and high chr codes.
     622             :  */
     623             : static void
     624       52110 : subcoloronechr(struct vars *v,
     625             :                chr ch,
     626             :                struct state *lp,
     627             :                struct state *rp,
     628             :                color *lastsubcolor)
     629             : {
     630       52110 :     struct colormap *cm = v->cm;
     631             :     colormaprange *newranges;
     632             :     int         numnewranges;
     633             :     colormaprange *oldrange;
     634             :     int         oldrangen;
     635             :     int         newrow;
     636             : 
     637             :     /* Easy case for low chr codes */
     638       52110 :     if (ch <= MAX_SIMPLE_CHR)
     639             :     {
     640       51844 :         color       sco = subcolor(cm, ch);
     641             : 
     642       51844 :         NOERR();
     643       51840 :         if (sco != *lastsubcolor)
     644             :         {
     645       45032 :             newarc(v->nfa, PLAIN, sco, lp, rp);
     646       45032 :             *lastsubcolor = sco;
     647             :         }
     648       51840 :         return;
     649             :     }
     650             : 
     651             :     /*
     652             :      * Potentially, we could need two more colormapranges than we have now, if
     653             :      * the given chr is in the middle of some existing range.
     654             :      */
     655             :     newranges = (colormaprange *)
     656         266 :         MALLOC((cm->numcmranges + 2) * sizeof(colormaprange));
     657         266 :     if (newranges == NULL)
     658             :     {
     659           0 :         CERR(REG_ESPACE);
     660           0 :         return;
     661             :     }
     662         266 :     numnewranges = 0;
     663             : 
     664             :     /* Ranges before target are unchanged */
     665         266 :     for (oldrange = cm->cmranges, oldrangen = 0;
     666       14800 :          oldrangen < cm->numcmranges;
     667       14534 :          oldrange++, oldrangen++)
     668             :     {
     669       14552 :         if (oldrange->cmax >= ch)
     670          18 :             break;
     671       14534 :         newranges[numnewranges++] = *oldrange;
     672             :     }
     673             : 
     674             :     /* Match target chr against current range */
     675         266 :     if (oldrangen >= cm->numcmranges || oldrange->cmin > ch)
     676             :     {
     677             :         /* chr does not belong to any existing range, make a new one */
     678         256 :         newranges[numnewranges].cmin = ch;
     679         256 :         newranges[numnewranges].cmax = ch;
     680             :         /* row state should be cloned from the "all others" row */
     681         256 :         newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0);
     682         256 :         numnewranges++;
     683             :     }
     684          10 :     else if (oldrange->cmin == oldrange->cmax)
     685             :     {
     686             :         /* we have an existing singleton range matching the chr */
     687           2 :         newranges[numnewranges++] = *oldrange;
     688           2 :         newrow = oldrange->rownum;
     689             :         /* we've now fully processed this old range */
     690           2 :         oldrange++, oldrangen++;
     691             :     }
     692             :     else
     693             :     {
     694             :         /* chr is a subset of this existing range, must split it */
     695           8 :         if (ch > oldrange->cmin)
     696             :         {
     697             :             /* emit portion of old range before chr */
     698           8 :             newranges[numnewranges].cmin = oldrange->cmin;
     699           8 :             newranges[numnewranges].cmax = ch - 1;
     700           8 :             newranges[numnewranges].rownum = oldrange->rownum;
     701           8 :             numnewranges++;
     702             :         }
     703             :         /* emit chr as singleton range, initially cloning from range */
     704           8 :         newranges[numnewranges].cmin = ch;
     705           8 :         newranges[numnewranges].cmax = ch;
     706           8 :         newranges[numnewranges].rownum = newrow =
     707           8 :             newhicolorrow(cm, oldrange->rownum);
     708           8 :         numnewranges++;
     709           8 :         if (ch < oldrange->cmax)
     710             :         {
     711             :             /* emit portion of old range after chr */
     712           8 :             newranges[numnewranges].cmin = ch + 1;
     713           8 :             newranges[numnewranges].cmax = oldrange->cmax;
     714             :             /* must clone the row if we are making two new ranges from old */
     715           8 :             newranges[numnewranges].rownum =
     716           8 :                 (ch > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) :
     717             :                 oldrange->rownum;
     718           8 :             numnewranges++;
     719             :         }
     720             :         /* we've now fully processed this old range */
     721           8 :         oldrange++, oldrangen++;
     722             :     }
     723             : 
     724             :     /* Update colors in newrow and create arcs as needed */
     725         266 :     subcoloronerow(v, newrow, lp, rp, lastsubcolor);
     726             : 
     727             :     /* Ranges after target are unchanged */
     728        1260 :     for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++)
     729             :     {
     730         994 :         newranges[numnewranges++] = *oldrange;
     731             :     }
     732             : 
     733             :     /* Assert our original space estimate was adequate */
     734             :     assert(numnewranges <= (cm->numcmranges + 2));
     735             : 
     736             :     /* And finally, store back the updated list of ranges */
     737         266 :     if (cm->cmranges != NULL)
     738         256 :         FREE(cm->cmranges);
     739         266 :     cm->cmranges = newranges;
     740         266 :     cm->numcmranges = numnewranges;
     741             : }
     742             : 
     743             : /*
     744             :  * subcoloronerange - do subcolorcvec's work for a high range
     745             :  */
     746             : static void
     747          16 : subcoloronerange(struct vars *v,
     748             :                  chr from,
     749             :                  chr to,
     750             :                  struct state *lp,
     751             :                  struct state *rp,
     752             :                  color *lastsubcolor)
     753             : {
     754          16 :     struct colormap *cm = v->cm;
     755             :     colormaprange *newranges;
     756             :     int         numnewranges;
     757             :     colormaprange *oldrange;
     758             :     int         oldrangen;
     759             :     int         newrow;
     760             : 
     761             :     /* Caller should take care of non-high-range cases */
     762             :     assert(from > MAX_SIMPLE_CHR);
     763             :     assert(from < to);
     764             : 
     765             :     /*
     766             :      * Potentially, if we have N non-adjacent ranges, we could need as many as
     767             :      * 2N+1 result ranges (consider case where new range spans 'em all).
     768             :      */
     769             :     newranges = (colormaprange *)
     770          16 :         MALLOC((cm->numcmranges * 2 + 1) * sizeof(colormaprange));
     771          16 :     if (newranges == NULL)
     772             :     {
     773           0 :         CERR(REG_ESPACE);
     774           0 :         return;
     775             :     }
     776          16 :     numnewranges = 0;
     777             : 
     778             :     /* Ranges before target are unchanged */
     779          16 :     for (oldrange = cm->cmranges, oldrangen = 0;
     780          28 :          oldrangen < cm->numcmranges;
     781          12 :          oldrange++, oldrangen++)
     782             :     {
     783          20 :         if (oldrange->cmax >= from)
     784           8 :             break;
     785          12 :         newranges[numnewranges++] = *oldrange;
     786             :     }
     787             : 
     788             :     /*
     789             :      * Deal with ranges that (partially) overlap the target.  As we process
     790             :      * each such range, increase "from" to remove the dealt-with characters
     791             :      * from the target range.
     792             :      */
     793          22 :     while (oldrangen < cm->numcmranges && oldrange->cmin <= to)
     794             :     {
     795           6 :         if (from < oldrange->cmin)
     796             :         {
     797             :             /* Handle portion of new range that corresponds to no old range */
     798           2 :             newranges[numnewranges].cmin = from;
     799           2 :             newranges[numnewranges].cmax = oldrange->cmin - 1;
     800             :             /* row state should be cloned from the "all others" row */
     801           2 :             newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0);
     802           2 :             numnewranges++;
     803             :             /* Update colors in newrow and create arcs as needed */
     804           2 :             subcoloronerow(v, newrow, lp, rp, lastsubcolor);
     805             :             /* We've now fully processed the part of new range before old */
     806           2 :             from = oldrange->cmin;
     807             :         }
     808             : 
     809           6 :         if (from <= oldrange->cmin && to >= oldrange->cmax)
     810             :         {
     811             :             /* old range is fully contained in new, process it in-place */
     812           2 :             newranges[numnewranges++] = *oldrange;
     813           2 :             newrow = oldrange->rownum;
     814           2 :             from = oldrange->cmax + 1;
     815             :         }
     816             :         else
     817             :         {
     818             :             /* some part of old range does not overlap new range */
     819           4 :             if (from > oldrange->cmin)
     820             :             {
     821             :                 /* emit portion of old range before new range */
     822           2 :                 newranges[numnewranges].cmin = oldrange->cmin;
     823           2 :                 newranges[numnewranges].cmax = from - 1;
     824           2 :                 newranges[numnewranges].rownum = oldrange->rownum;
     825           2 :                 numnewranges++;
     826             :             }
     827             :             /* emit common subrange, initially cloning from old range */
     828           4 :             newranges[numnewranges].cmin = from;
     829           4 :             newranges[numnewranges].cmax =
     830           4 :                 (to < oldrange->cmax) ? to : oldrange->cmax;
     831           4 :             newranges[numnewranges].rownum = newrow =
     832           4 :                 newhicolorrow(cm, oldrange->rownum);
     833           4 :             numnewranges++;
     834           4 :             if (to < oldrange->cmax)
     835             :             {
     836             :                 /* emit portion of old range after new range */
     837           2 :                 newranges[numnewranges].cmin = to + 1;
     838           2 :                 newranges[numnewranges].cmax = oldrange->cmax;
     839             :                 /* must clone the row if we are making two new ranges from old */
     840           2 :                 newranges[numnewranges].rownum =
     841           2 :                     (from > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) :
     842             :                     oldrange->rownum;
     843           2 :                 numnewranges++;
     844             :             }
     845           4 :             from = oldrange->cmax + 1;
     846             :         }
     847             :         /* Update colors in newrow and create arcs as needed */
     848           6 :         subcoloronerow(v, newrow, lp, rp, lastsubcolor);
     849             :         /* we've now fully processed this old range */
     850           6 :         oldrange++, oldrangen++;
     851             :     }
     852             : 
     853          16 :     if (from <= to)
     854             :     {
     855             :         /* Handle portion of new range that corresponds to no old range */
     856          14 :         newranges[numnewranges].cmin = from;
     857          14 :         newranges[numnewranges].cmax = to;
     858             :         /* row state should be cloned from the "all others" row */
     859          14 :         newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0);
     860          14 :         numnewranges++;
     861             :         /* Update colors in newrow and create arcs as needed */
     862          14 :         subcoloronerow(v, newrow, lp, rp, lastsubcolor);
     863             :     }
     864             : 
     865             :     /* Ranges after target are unchanged */
     866         270 :     for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++)
     867             :     {
     868         254 :         newranges[numnewranges++] = *oldrange;
     869             :     }
     870             : 
     871             :     /* Assert our original space estimate was adequate */
     872             :     assert(numnewranges <= (cm->numcmranges * 2 + 1));
     873             : 
     874             :     /* And finally, store back the updated list of ranges */
     875          16 :     if (cm->cmranges != NULL)
     876          10 :         FREE(cm->cmranges);
     877          16 :     cm->cmranges = newranges;
     878          16 :     cm->numcmranges = numnewranges;
     879             : }
     880             : 
     881             : /*
     882             :  * subcoloronerow - do subcolorcvec's work for one new row in the high colormap
     883             :  */
     884             : static void
     885         288 : subcoloronerow(struct vars *v,
     886             :                int rownum,
     887             :                struct state *lp,
     888             :                struct state *rp,
     889             :                color *lastsubcolor)
     890             : {
     891         288 :     struct colormap *cm = v->cm;
     892             :     color      *pco;
     893             :     int         i;
     894             : 
     895             :     /* Apply subcolorhi() and make arc for each entry in row */
     896         288 :     pco = &cm->hicolormap[rownum * cm->hiarraycols];
     897        1356 :     for (i = 0; i < cm->hiarraycols; pco++, i++)
     898             :     {
     899        1068 :         color       sco = subcolorhi(cm, pco);
     900             : 
     901        1068 :         NOERR();
     902             :         /* make the arc if needed */
     903        1068 :         if (sco != *lastsubcolor)
     904             :         {
     905        1068 :             newarc(v->nfa, PLAIN, sco, lp, rp);
     906        1068 :             NOERR();
     907        1068 :             *lastsubcolor = sco;
     908             :         }
     909             :     }
     910             : }
     911             : 
     912             : /*
     913             :  * okcolors - promote subcolors to full colors
     914             :  */
     915             : static void
     916       46460 : okcolors(struct nfa *nfa,
     917             :          struct colormap *cm)
     918             : {
     919             :     struct colordesc *cd;
     920       46460 :     struct colordesc *end = CDEND(cm);
     921             :     struct colordesc *scd;
     922             :     struct arc *a;
     923             :     color       co;
     924             :     color       sco;
     925             : 
     926      372448 :     for (cd = cm->cd, co = 0; cd < end; cd++, co++)
     927             :     {
     928      325988 :         sco = cd->sub;
     929      325988 :         if (UNUSEDCOLOR(cd) || sco == NOSUB)
     930             :         {
     931             :             /* has no subcolor, no further action */
     932             :         }
     933       25812 :         else if (sco == co)
     934             :         {
     935             :             /* is subcolor, let parent deal with it */
     936             :         }
     937       25708 :         else if (cd->nschrs == 0 && cd->nuchrs == 0)
     938             :         {
     939             :             /*
     940             :              * Parent is now empty, so just change all its arcs to the
     941             :              * subcolor, then free the parent.
     942             :              *
     943             :              * It is not obvious that simply relabeling the arcs like this is
     944             :              * OK; it appears to risk creating duplicate arcs.  We are
     945             :              * basically relying on the assumption that processing of a
     946             :              * bracket expression can't create arcs of both a color and its
     947             :              * subcolor between the bracket's endpoints.
     948             :              */
     949         346 :             cd->sub = NOSUB;
     950         346 :             scd = &cm->cd[sco];
     951             :             assert(scd->nschrs > 0 || scd->nuchrs > 0);
     952             :             assert(scd->sub == sco);
     953         346 :             scd->sub = NOSUB;
     954        2646 :             while ((a = cd->arcs) != NULL)
     955             :             {
     956             :                 assert(a->co == co);
     957        2300 :                 uncolorchain(cm, a);
     958        2300 :                 a->co = sco;
     959        2300 :                 colorchain(cm, a);
     960             :             }
     961         346 :             freecolor(cm, co);
     962             :         }
     963             :         else
     964             :         {
     965             :             /* parent's arcs must gain parallel subcolor arcs */
     966       25362 :             cd->sub = NOSUB;
     967       25362 :             scd = &cm->cd[sco];
     968             :             assert(scd->nschrs > 0 || scd->nuchrs > 0);
     969             :             assert(scd->sub == sco);
     970       25362 :             scd->sub = NOSUB;
     971       26268 :             for (a = cd->arcs; a != NULL; a = a->colorchain)
     972             :             {
     973             :                 assert(a->co == co);
     974         906 :                 newarc(nfa, a->type, sco, a->from, a->to);
     975             :             }
     976             :         }
     977             :     }
     978       46460 : }
     979             : 
     980             : /*
     981             :  * colorchain - add this arc to the color chain of its color
     982             :  */
     983             : static void
     984     1497702 : colorchain(struct colormap *cm,
     985             :            struct arc *a)
     986             : {
     987     1497702 :     struct colordesc *cd = &cm->cd[a->co];
     988             : 
     989             :     assert(a->co >= 0);
     990     1497702 :     if (cd->arcs != NULL)
     991     1455002 :         cd->arcs->colorchainRev = a;
     992     1497702 :     a->colorchain = cd->arcs;
     993     1497702 :     a->colorchainRev = NULL;
     994     1497702 :     cd->arcs = a;
     995     1497702 : }
     996             : 
     997             : /*
     998             :  * uncolorchain - delete this arc from the color chain of its color
     999             :  */
    1000             : static void
    1001      684328 : uncolorchain(struct colormap *cm,
    1002             :              struct arc *a)
    1003             : {
    1004      684328 :     struct colordesc *cd = &cm->cd[a->co];
    1005      684328 :     struct arc *aa = a->colorchainRev;
    1006             : 
    1007             :     assert(a->co >= 0);
    1008      684328 :     if (aa == NULL)
    1009             :     {
    1010             :         assert(cd->arcs == a);
    1011      173110 :         cd->arcs = a->colorchain;
    1012             :     }
    1013             :     else
    1014             :     {
    1015             :         assert(aa->colorchain == a);
    1016      511218 :         aa->colorchain = a->colorchain;
    1017             :     }
    1018      684328 :     if (a->colorchain != NULL)
    1019      648450 :         a->colorchain->colorchainRev = aa;
    1020      684328 :     a->colorchain = NULL;        /* paranoia */
    1021      684328 :     a->colorchainRev = NULL;
    1022      684328 : }
    1023             : 
    1024             : /*
    1025             :  * rainbow - add arcs of all full colors (but one) between specified states
    1026             :  *
    1027             :  * If there isn't an exception color, we now generate just a single arc
    1028             :  * labeled RAINBOW, saving lots of arc-munging later on.
    1029             :  */
    1030             : static void
    1031       32344 : rainbow(struct nfa *nfa,
    1032             :         struct colormap *cm,
    1033             :         int type,
    1034             :         color but,              /* COLORLESS if no exceptions */
    1035             :         struct state *from,
    1036             :         struct state *to)
    1037             : {
    1038             :     struct colordesc *cd;
    1039       32344 :     struct colordesc *end = CDEND(cm);
    1040             :     color       co;
    1041             : 
    1042       32344 :     if (but == COLORLESS)
    1043             :     {
    1044       31644 :         newarc(nfa, type, RAINBOW, from, to);
    1045       31644 :         return;
    1046             :     }
    1047             : 
    1048             :     /* Gotta do it the hard way.  Skip subcolors, pseudocolors, and "but" */
    1049        5458 :     for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++)
    1050        4758 :         if (!UNUSEDCOLOR(cd) && cd->sub != co && co != but &&
    1051        4058 :             !(cd->flags & PSEUDO))
    1052        4058 :             newarc(nfa, type, co, from, to);
    1053             : }
    1054             : 
    1055             : /*
    1056             :  * colorcomplement - add arcs of complementary colors
    1057             :  *
    1058             :  * We add arcs of all colors that are not pseudocolors and do not match
    1059             :  * any of the "of" state's PLAIN outarcs.
    1060             :  *
    1061             :  * The calling sequence ought to be reconciled with cloneouts().
    1062             :  */
    1063             : static void
    1064         912 : colorcomplement(struct nfa *nfa,
    1065             :                 struct colormap *cm,
    1066             :                 int type,
    1067             :                 struct state *of,
    1068             :                 struct state *from,
    1069             :                 struct state *to)
    1070             : {
    1071             :     struct colordesc *cd;
    1072         912 :     struct colordesc *end = CDEND(cm);
    1073             :     color       co;
    1074             :     struct arc *a;
    1075             : 
    1076             :     assert(of != from);
    1077             : 
    1078             :     /* A RAINBOW arc matches all colors, making the complement empty */
    1079         912 :     if (findarc(of, PLAIN, RAINBOW) != NULL)
    1080           2 :         return;
    1081             : 
    1082             :     /* Otherwise, transiently mark the colors that appear in of's out-arcs */
    1083        2318 :     for (a = of->outs; a != NULL; a = a->outchain)
    1084             :     {
    1085        1408 :         if (a->type == PLAIN)
    1086             :         {
    1087             :             assert(a->co >= 0);
    1088        1408 :             cd = &cm->cd[a->co];
    1089             :             assert(!UNUSEDCOLOR(cd));
    1090        1408 :             cd->flags |= COLMARK;
    1091             :         }
    1092             :     }
    1093             : 
    1094             :     /* Scan colors, clear transient marks, add arcs for unmarked colors */
    1095        3562 :     for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++)
    1096             :     {
    1097        2652 :         if (cd->flags & COLMARK)
    1098        1408 :             cd->flags &= ~COLMARK;
    1099        1244 :         else if (!UNUSEDCOLOR(cd) && !(cd->flags & PSEUDO))
    1100        1224 :             newarc(nfa, type, co, from, to);
    1101             :     }
    1102             : }
    1103             : 
    1104             : 
    1105             : #ifdef REG_DEBUG
    1106             : 
    1107             : /*
    1108             :  * dumpcolors - debugging output
    1109             :  */
    1110             : static void
    1111             : dumpcolors(struct colormap *cm,
    1112             :            FILE *f)
    1113             : {
    1114             :     struct colordesc *cd;
    1115             :     struct colordesc *end;
    1116             :     color       co;
    1117             :     chr         c;
    1118             : 
    1119             :     fprintf(f, "max %ld\n", (long) cm->max);
    1120             :     end = CDEND(cm);
    1121             :     for (cd = cm->cd + 1, co = 1; cd < end; cd++, co++) /* skip 0 */
    1122             :     {
    1123             :         if (!UNUSEDCOLOR(cd))
    1124             :         {
    1125             :             assert(cd->nschrs > 0 || cd->nuchrs > 0);
    1126             :             if (cd->flags & PSEUDO)
    1127             :                 fprintf(f, "#%2ld(ps): ", (long) co);
    1128             :             else
    1129             :                 fprintf(f, "#%2ld(%2d): ", (long) co, cd->nschrs + cd->nuchrs);
    1130             : 
    1131             :             /*
    1132             :              * Unfortunately, it's hard to do this next bit more efficiently.
    1133             :              */
    1134             :             for (c = CHR_MIN; c <= MAX_SIMPLE_CHR; c++)
    1135             :                 if (GETCOLOR(cm, c) == co)
    1136             :                     dumpchr(c, f);
    1137             :             fprintf(f, "\n");
    1138             :         }
    1139             :     }
    1140             :     /* dump the high colormap if it contains anything interesting */
    1141             :     if (cm->hiarrayrows > 1 || cm->hiarraycols > 1)
    1142             :     {
    1143             :         int         r,
    1144             :                     c;
    1145             :         const color *rowptr;
    1146             : 
    1147             :         fprintf(f, "other:\t");
    1148             :         for (c = 0; c < cm->hiarraycols; c++)
    1149             :         {
    1150             :             fprintf(f, "\t%ld", (long) cm->hicolormap[c]);
    1151             :         }
    1152             :         fprintf(f, "\n");
    1153             :         for (r = 0; r < cm->numcmranges; r++)
    1154             :         {
    1155             :             dumpchr(cm->cmranges[r].cmin, f);
    1156             :             fprintf(f, "..");
    1157             :             dumpchr(cm->cmranges[r].cmax, f);
    1158             :             fprintf(f, ":");
    1159             :             rowptr = &cm->hicolormap[cm->cmranges[r].rownum * cm->hiarraycols];
    1160             :             for (c = 0; c < cm->hiarraycols; c++)
    1161             :             {
    1162             :                 fprintf(f, "\t%ld", (long) rowptr[c]);
    1163             :             }
    1164             :             fprintf(f, "\n");
    1165             :         }
    1166             :     }
    1167             : }
    1168             : 
    1169             : /*
    1170             :  * dumpchr - print a chr
    1171             :  *
    1172             :  * Kind of char-centric but works well enough for debug use.
    1173             :  */
    1174             : static void
    1175             : dumpchr(chr c,
    1176             :         FILE *f)
    1177             : {
    1178             :     if (c == '\\')
    1179             :         fprintf(f, "\\\\");
    1180             :     else if (c > ' ' && c <= '~')
    1181             :         putc((char) c, f);
    1182             :     else
    1183             :         fprintf(f, "\\u%04lx", (long) c);
    1184             : }
    1185             : 
    1186             : #endif                          /* REG_DEBUG */

Generated by: LCOV version 1.14