/* * colorings of characters * This file is #included by regcomp.c. * * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved. * * Development of this software was funded, in part, by Cray Research Inc., * UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics * Corporation, none of whom are responsible for the results. The author * thanks all of them. * * Redistribution and use in source and binary forms -- with or without * modification -- are permitted for any purpose, provided that * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * * I'd appreciate being given credit for this package in the documentation * of software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * src/backend/regex/regc_color.c * * * Note that there are some incestuous relationships between this code and * NFA arc maintenance, which perhaps ought to be cleaned up sometime. */ #define CISERR() VISERR(cm->v) #define CERR(e) VERR(cm->v, (e)) /* * initcm - set up new colormap */ static void initcm(struct vars *v, struct colormap *cm) { struct colordesc *cd; cm->magic = CMMAGIC; cm->v = v; cm->ncds = NINLINECDS; cm->cd = cm->cdspace; cm->max = 0; cm->free = 0; cd = cm->cd; /* cm->cd[WHITE] */ cd->nschrs = MAX_SIMPLE_CHR - CHR_MIN + 1; cd->nuchrs = 1; cd->sub = NOSUB; cd->arcs = NULL; cd->firstchr = CHR_MIN; cd->flags = 0; cm->locolormap = (color *) MALLOC((MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); if (cm->locolormap == NULL) { CERR(REG_ESPACE); cm->cmranges = NULL; /* prevent failure during freecm */ cm->hicolormap = NULL; return; } /* this memset relies on WHITE being zero: */ memset(cm->locolormap, WHITE, (MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); memset(cm->classbits, 0, sizeof(cm->classbits)); cm->numcmranges = 0; cm->cmranges = NULL; cm->maxarrayrows = 4; /* arbitrary initial allocation */ cm->hiarrayrows = 1; /* but we have only one row/col initially */ cm->hiarraycols = 1; cm->hicolormap = (color *) MALLOC(cm->maxarrayrows * sizeof(color)); if (cm->hicolormap == NULL) { CERR(REG_ESPACE); return; } /* initialize the "all other characters" row to WHITE */ cm->hicolormap[0] = WHITE; } /* * freecm - free dynamically-allocated things in a colormap */ static void freecm(struct colormap *cm) { cm->magic = 0; if (cm->cd != cm->cdspace) FREE(cm->cd); if (cm->locolormap != NULL) FREE(cm->locolormap); if (cm->cmranges != NULL) FREE(cm->cmranges); if (cm->hicolormap != NULL) FREE(cm->hicolormap); } /* * pg_reg_getcolor - slow case of GETCOLOR() */ color pg_reg_getcolor(struct colormap *cm, chr c) { int rownum, colnum, low, high; /* Should not be used for chrs in the locolormap */ assert(c > MAX_SIMPLE_CHR); /* * Find which row it's in. The colormapranges are in order, so we can use * binary search. */ rownum = 0; /* if no match, use array row zero */ low = 0; high = cm->numcmranges; while (low < high) { int middle = low + (high - low) / 2; const colormaprange *cmr = &cm->cmranges[middle]; if (c < cmr->cmin) high = middle; else if (c > cmr->cmax) low = middle + 1; else { rownum = cmr->rownum; /* found a match */ break; } } /* * Find which column it's in --- this is all locale-dependent. */ if (cm->hiarraycols > 1) { colnum = cclass_column_index(cm, c); return cm->hicolormap[rownum * cm->hiarraycols + colnum]; } else { /* fast path if no relevant cclasses */ return cm->hicolormap[rownum]; } } /* * maxcolor - report largest color number in use */ static color maxcolor(struct colormap *cm) { if (CISERR()) return COLORLESS; return (color) cm->max; } /* * newcolor - find a new color (must be assigned at once) * Beware: may relocate the colordescs. */ static color /* COLORLESS for error */ newcolor(struct colormap *cm) { struct colordesc *cd; size_t n; if (CISERR()) return COLORLESS; if (cm->free != 0) { assert(cm->free > 0); assert((size_t) cm->free < cm->ncds); cd = &cm->cd[cm->free]; assert(UNUSEDCOLOR(cd)); assert(cd->arcs == NULL); cm->free = cd->sub; } else if (cm->max < cm->ncds - 1) { cm->max++; cd = &cm->cd[cm->max]; } else { /* oops, must allocate more */ struct colordesc *newCd; if (cm->max == MAX_COLOR) { CERR(REG_ECOLORS); return COLORLESS; /* too many colors */ } n = cm->ncds * 2; if (n > MAX_COLOR + 1) n = MAX_COLOR + 1; if (cm->cd == cm->cdspace) { newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc)); if (newCd != NULL) memcpy(VS(newCd), VS(cm->cdspace), cm->ncds * sizeof(struct colordesc)); } else newCd = (struct colordesc *) REALLOC(cm->cd, n * sizeof(struct colordesc)); if (newCd == NULL) { CERR(REG_ESPACE); return COLORLESS; } cm->cd = newCd; cm->ncds = n; assert(cm->max < cm->ncds - 1); cm->max++; cd = &cm->cd[cm->max]; } cd->nschrs = 0; cd->nuchrs = 0; cd->sub = NOSUB; cd->arcs = NULL; cd->firstchr = CHR_MIN; /* in case never set otherwise */ cd->flags = 0; return (color) (cd - cm->cd); } /* * freecolor - free a color (must have no arcs or subcolor) */ static void freecolor(struct colormap *cm, color co) { struct colordesc *cd = &cm->cd[co]; color pco, nco; /* for freelist scan */ assert(co >= 0); if (co == WHITE) return; assert(cd->arcs == NULL); assert(cd->sub == NOSUB); assert(cd->nschrs == 0); assert(cd->nuchrs == 0); cd->flags = FREECOL; if ((size_t) co == cm->max) { while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max])) cm->max--; assert(cm->free >= 0); while ((size_t) cm->free > cm->max) cm->free = cm->cd[cm->free].sub; if (cm->free > 0) { assert(cm->free < cm->max); pco = cm->free; nco = cm->cd[pco].sub; while (nco > 0) if ((size_t) nco > cm->max) { /* take this one out of freelist */ nco = cm->cd[nco].sub; cm->cd[pco].sub = nco; } else { assert(nco < cm->max); pco = nco; nco = cm->cd[pco].sub; } } } else { cd->sub = cm->free; cm->free = (color) (cd - cm->cd); } } /* * pseudocolor - allocate a false color, to be managed by other means */ static color pseudocolor(struct colormap *cm) { color co; struct colordesc *cd; co = newcolor(cm); if (CISERR()) return COLORLESS; cd = &cm->cd[co]; cd->nschrs = 0; cd->nuchrs = 1; /* pretend it is in the upper map */ cd->sub = NOSUB; cd->arcs = NULL; cd->firstchr = CHR_MIN; cd->flags = PSEUDO; return co; } /* * subcolor - allocate a new subcolor (if necessary) to this chr * * This works only for chrs that map into the low color map. */ static color subcolor(struct colormap *cm, chr c) { color co; /* current color of c */ color sco; /* new subcolor */ assert(c <= MAX_SIMPLE_CHR); co = cm->locolormap[c - CHR_MIN]; sco = newsub(cm, co); if (CISERR()) return COLORLESS; assert(sco != COLORLESS); if (co == sco) /* already in an open subcolor */ return co; /* rest is redundant */ cm->cd[co].nschrs--; if (cm->cd[sco].nschrs == 0) cm->cd[sco].firstchr = c; cm->cd[sco].nschrs++; cm->locolormap[c - CHR_MIN] = sco; return sco; } /* * subcolorhi - allocate a new subcolor (if necessary) to this colormap entry * * This is the same processing as subcolor(), but for entries in the high * colormap, which do not necessarily correspond to exactly one chr code. */ static color subcolorhi(struct colormap *cm, color *pco) { color co; /* current color of entry */ color sco; /* new subcolor */ co = *pco; sco = newsub(cm, co); if (CISERR()) return COLORLESS; assert(sco != COLORLESS); if (co == sco) /* already in an open subcolor */ return co; /* rest is redundant */ cm->cd[co].nuchrs--; cm->cd[sco].nuchrs++; *pco = sco; return sco; } /* * newsub - allocate a new subcolor (if necessary) for a color */ static color newsub(struct colormap *cm, color co) { color sco; /* new subcolor */ sco = cm->cd[co].sub; if (sco == NOSUB) { /* color has no open subcolor */ /* optimization: singly-referenced color need not be subcolored */ if ((cm->cd[co].nschrs + cm->cd[co].nuchrs) == 1) return co; sco = newcolor(cm); /* must create subcolor */ if (sco == COLORLESS) { assert(CISERR()); return COLORLESS; } cm->cd[co].sub = sco; cm->cd[sco].sub = sco; /* open subcolor points to self */ } assert(sco != NOSUB); return sco; } /* * newhicolorrow - get a new row in the hicolormap, cloning it from oldrow * * Returns array index of new row. Note the array might move. */ static int newhicolorrow(struct colormap *cm, int oldrow) { int newrow = cm->hiarrayrows; color *newrowptr; int i; /* Assign a fresh array row index, enlarging storage if needed */ if (newrow >= cm->maxarrayrows) { color *newarray; if (cm->maxarrayrows >= INT_MAX / (cm->hiarraycols * 2)) { CERR(REG_ESPACE); return 0; } newarray = (color *) REALLOC(cm->hicolormap, cm->maxarrayrows * 2 * cm->hiarraycols * sizeof(color)); if (newarray == NULL) { CERR(REG_ESPACE); return 0; } cm->hicolormap = newarray; cm->maxarrayrows *= 2; } cm->hiarrayrows++; /* Copy old row data */ newrowptr = &cm->hicolormap[newrow * cm->hiarraycols]; memcpy(newrowptr, &cm->hicolormap[oldrow * cm->hiarraycols], cm->hiarraycols * sizeof(color)); /* Increase color reference counts to reflect new colormap entries */ for (i = 0; i < cm->hiarraycols; i++) cm->cd[newrowptr[i]].nuchrs++; return newrow; } /* * newhicolorcols - create a new set of columns in the high colormap * * Essentially, extends the 2-D array to the right with a copy of itself. */ static void newhicolorcols(struct colormap *cm) { color *newarray; int r, c; if (cm->hiarraycols >= INT_MAX / (cm->maxarrayrows * 2)) { CERR(REG_ESPACE); return; } newarray = (color *) REALLOC(cm->hicolormap, cm->maxarrayrows * cm->hiarraycols * 2 * sizeof(color)); if (newarray == NULL) { CERR(REG_ESPACE); return; } cm->hicolormap = newarray; /* Duplicate existing columns to the right, and increase ref counts */ /* Must work backwards in the array because we realloc'd in place */ for (r = cm->hiarrayrows - 1; r >= 0; r--) { color *oldrowptr = &newarray[r * cm->hiarraycols]; color *newrowptr = &newarray[r * cm->hiarraycols * 2]; color *newrowptr2 = newrowptr + cm->hiarraycols; for (c = 0; c < cm->hiarraycols; c++) { color co = oldrowptr[c]; newrowptr[c] = newrowptr2[c] = co; cm->cd[co].nuchrs++; } } cm->hiarraycols *= 2; } /* * subcolorcvec - allocate new subcolors to cvec members, fill in arcs * * For each chr "c" represented by the cvec, do the equivalent of * newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp); * * Note that in typical cases, many of the subcolors are the same. * While newarc() would discard duplicate arc requests, we can save * some cycles by not calling it repetitively to begin with. This is * mechanized with the "lastsubcolor" state variable. */ static void subcolorcvec(struct vars *v, struct cvec *cv, struct state *lp, struct state *rp) { struct colormap *cm = v->cm; color lastsubcolor = COLORLESS; chr ch, from, to; const chr *p; int i; /* ordinary characters */ for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--) { ch = *p; subcoloronechr(v, ch, lp, rp, &lastsubcolor); NOERR(); } /* and the ranges */ for (p = cv->ranges, i = cv->nranges; i > 0; p += 2, i--) { from = *p; to = *(p + 1); if (from <= MAX_SIMPLE_CHR) { /* deal with simple chars one at a time */ chr lim = (to <= MAX_SIMPLE_CHR) ? to : MAX_SIMPLE_CHR; while (from <= lim) { color sco = subcolor(cm, from); NOERR(); if (sco != lastsubcolor) { newarc(v->nfa, PLAIN, sco, lp, rp); NOERR(); lastsubcolor = sco; } from++; } } /* deal with any part of the range that's above MAX_SIMPLE_CHR */ if (from < to) subcoloronerange(v, from, to, lp, rp, &lastsubcolor); else if (from == to) subcoloronechr(v, from, lp, rp, &lastsubcolor); NOERR(); } /* and deal with cclass if any */ if (cv->cclasscode >= 0) { int classbit; color *pco; int r, c; /* Enlarge array if we don't have a column bit assignment for cclass */ if (cm->classbits[cv->cclasscode] == 0) { cm->classbits[cv->cclasscode] = cm->hiarraycols; newhicolorcols(cm); NOERR(); } /* Apply subcolorhi() and make arc for each entry in relevant cols */ classbit = cm->classbits[cv->cclasscode]; pco = cm->hicolormap; for (r = 0; r < cm->hiarrayrows; r++) { for (c = 0; c < cm->hiarraycols; c++) { if (c & classbit) { color sco = subcolorhi(cm, pco); NOERR(); /* add the arc if needed */ if (sco != lastsubcolor) { newarc(v->nfa, PLAIN, sco, lp, rp); NOERR(); lastsubcolor = sco; } } pco++; } } } } /* * subcoloronechr - do subcolorcvec's work for a singleton chr * * We could just let subcoloronerange do this, but it's a bit more efficient * if we exploit the single-chr case. Also, callers find it useful for this * to be able to handle both low and high chr codes. */ static void subcoloronechr(struct vars *v, chr ch, struct state *lp, struct state *rp, color *lastsubcolor) { struct colormap *cm = v->cm; colormaprange *newranges; int numnewranges; colormaprange *oldrange; int oldrangen; int newrow; /* Easy case for low chr codes */ if (ch <= MAX_SIMPLE_CHR) { color sco = subcolor(cm, ch); NOERR(); if (sco != *lastsubcolor) { newarc(v->nfa, PLAIN, sco, lp, rp); *lastsubcolor = sco; } return; } /* * Potentially, we could need two more colormapranges than we have now, if * the given chr is in the middle of some existing range. */ newranges = (colormaprange *) MALLOC((cm->numcmranges + 2) * sizeof(colormaprange)); if (newranges == NULL) { CERR(REG_ESPACE); return; } numnewranges = 0; /* Ranges before target are unchanged */ for (oldrange = cm->cmranges, oldrangen = 0; oldrangen < cm->numcmranges; oldrange++, oldrangen++) { if (oldrange->cmax >= ch) break; newranges[numnewranges++] = *oldrange; } /* Match target chr against current range */ if (oldrangen >= cm->numcmranges || oldrange->cmin > ch) { /* chr does not belong to any existing range, make a new one */ newranges[numnewranges].cmin = ch; newranges[numnewranges].cmax = ch; /* row state should be cloned from the "all others" row */ newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); numnewranges++; } else if (oldrange->cmin == oldrange->cmax) { /* we have an existing singleton range matching the chr */ newranges[numnewranges++] = *oldrange; newrow = oldrange->rownum; /* we've now fully processed this old range */ oldrange++, oldrangen++; } else { /* chr is a subset of this existing range, must split it */ if (ch > oldrange->cmin) { /* emit portion of old range before chr */ newranges[numnewranges].cmin = oldrange->cmin; newranges[numnewranges].cmax = ch - 1; newranges[numnewranges].rownum = oldrange->rownum; numnewranges++; } /* emit chr as singleton range, initially cloning from range */ newranges[numnewranges].cmin = ch; newranges[numnewranges].cmax = ch; newranges[numnewranges].rownum = newrow = newhicolorrow(cm, oldrange->rownum); numnewranges++; if (ch < oldrange->cmax) { /* emit portion of old range after chr */ newranges[numnewranges].cmin = ch + 1; newranges[numnewranges].cmax = oldrange->cmax; /* must clone the row if we are making two new ranges from old */ newranges[numnewranges].rownum = (ch > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : oldrange->rownum; numnewranges++; } /* we've now fully processed this old range */ oldrange++, oldrangen++; } /* Update colors in newrow and create arcs as needed */ subcoloronerow(v, newrow, lp, rp, lastsubcolor); /* Ranges after target are unchanged */ for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) { newranges[numnewranges++] = *oldrange; } /* Assert our original space estimate was adequate */ assert(numnewranges <= (cm->numcmranges + 2)); /* And finally, store back the updated list of ranges */ if (cm->cmranges != NULL) FREE(cm->cmranges); cm->cmranges = newranges; cm->numcmranges = numnewranges; } /* * subcoloronerange - do subcolorcvec's work for a high range */ static void subcoloronerange(struct vars *v, chr from, chr to, struct state *lp, struct state *rp, color *lastsubcolor) { struct colormap *cm = v->cm; colormaprange *newranges; int numnewranges; colormaprange *oldrange; int oldrangen; int newrow; /* Caller should take care of non-high-range cases */ assert(from > MAX_SIMPLE_CHR); assert(from < to); /* * Potentially, if we have N non-adjacent ranges, we could need as many as * 2N+1 result ranges (consider case where new range spans 'em all). */ newranges = (colormaprange *) MALLOC((cm->numcmranges * 2 + 1) * sizeof(colormaprange)); if (newranges == NULL) { CERR(REG_ESPACE); return; } numnewranges = 0; /* Ranges before target are unchanged */ for (oldrange = cm->cmranges, oldrangen = 0; oldrangen < cm->numcmranges; oldrange++, oldrangen++) { if (oldrange->cmax >= from) break; newranges[numnewranges++] = *oldrange; } /* * Deal with ranges that (partially) overlap the target. As we process * each such range, increase "from" to remove the dealt-with characters * from the target range. */ while (oldrangen < cm->numcmranges && oldrange->cmin <= to) { if (from < oldrange->cmin) { /* Handle portion of new range that corresponds to no old range */ newranges[numnewranges].cmin = from; newranges[numnewranges].cmax = oldrange->cmin - 1; /* row state should be cloned from the "all others" row */ newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); numnewranges++; /* Update colors in newrow and create arcs as needed */ subcoloronerow(v, newrow, lp, rp, lastsubcolor); /* We've now fully processed the part of new range before old */ from = oldrange->cmin; } if (from <= oldrange->cmin && to >= oldrange->cmax) { /* old range is fully contained in new, process it in-place */ newranges[numnewranges++] = *oldrange; newrow = oldrange->rownum; from = oldrange->cmax + 1; } else { /* some part of old range does not overlap new range */ if (from > oldrange->cmin) { /* emit portion of old range before new range */ newranges[numnewranges].cmin = oldrange->cmin; newranges[numnewranges].cmax = from - 1; newranges[numnewranges].rownum = oldrange->rownum; numnewranges++; } /* emit common subrange, initially cloning from old range */ newranges[numnewranges].cmin = from; newranges[numnewranges].cmax = (to < oldrange->cmax) ? to : oldrange->cmax; newranges[numnewranges].rownum = newrow = newhicolorrow(cm, oldrange->rownum); numnewranges++; if (to < oldrange->cmax) { /* emit portion of old range after new range */ newranges[numnewranges].cmin = to + 1; newranges[numnewranges].cmax = oldrange->cmax; /* must clone the row if we are making two new ranges from old */ newranges[numnewranges].rownum = (from > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : oldrange->rownum; numnewranges++; } from = oldrange->cmax + 1; } /* Update colors in newrow and create arcs as needed */ subcoloronerow(v, newrow, lp, rp, lastsubcolor); /* we've now fully processed this old range */ oldrange++, oldrangen++; } if (from <= to) { /* Handle portion of new range that corresponds to no old range */ newranges[numnewranges].cmin = from; newranges[numnewranges].cmax = to; /* row state should be cloned from the "all others" row */ newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); numnewranges++; /* Update colors in newrow and create arcs as needed */ subcoloronerow(v, newrow, lp, rp, lastsubcolor); } /* Ranges after target are unchanged */ for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) { newranges[numnewranges++] = *oldrange; } /* Assert our original space estimate was adequate */ assert(numnewranges <= (cm->numcmranges * 2 + 1)); /* And finally, store back the updated list of ranges */ if (cm->cmranges != NULL) FREE(cm->cmranges); cm->cmranges = newranges; cm->numcmranges = numnewranges; } /* * subcoloronerow - do subcolorcvec's work for one new row in the high colormap */ static void subcoloronerow(struct vars *v, int rownum, struct state *lp, struct state *rp, color *lastsubcolor) { struct colormap *cm = v->cm; color *pco; int i; /* Apply subcolorhi() and make arc for each entry in row */ pco = &cm->hicolormap[rownum * cm->hiarraycols]; for (i = 0; i < cm->hiarraycols; pco++, i++) { color sco = subcolorhi(cm, pco); NOERR(); /* make the arc if needed */ if (sco != *lastsubcolor) { newarc(v->nfa, PLAIN, sco, lp, rp); NOERR(); *lastsubcolor = sco; } } } /* * okcolors - promote subcolors to full colors */ static void okcolors(struct nfa *nfa, struct colormap *cm) { struct colordesc *cd; struct colordesc *end = CDEND(cm); struct colordesc *scd; struct arc *a; color co; color sco; for (cd = cm->cd, co = 0; cd < end; cd++, co++) { sco = cd->sub; if (UNUSEDCOLOR(cd) || sco == NOSUB) { /* has no subcolor, no further action */ } else if (sco == co) { /* is subcolor, let parent deal with it */ } else if (cd->nschrs == 0 && cd->nuchrs == 0) { /* parent empty, its arcs change color to subcolor */ cd->sub = NOSUB; scd = &cm->cd[sco]; assert(scd->nschrs > 0 || scd->nuchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; while ((a = cd->arcs) != NULL) { assert(a->co == co); uncolorchain(cm, a); a->co = sco; colorchain(cm, a); } freecolor(cm, co); } else { /* parent's arcs must gain parallel subcolor arcs */ cd->sub = NOSUB; scd = &cm->cd[sco]; assert(scd->nschrs > 0 || scd->nuchrs > 0); assert(scd->sub == sco); scd->sub = NOSUB; for (a = cd->arcs; a != NULL; a = a->colorchain) { assert(a->co == co); newarc(nfa, a->type, sco, a->from, a->to); } } } } /* * colorchain - add this arc to the color chain of its color */ static void colorchain(struct colormap *cm, struct arc *a) { struct colordesc *cd = &cm->cd[a->co]; if (cd->arcs != NULL) cd->arcs->colorchainRev = a; a->colorchain = cd->arcs; a->colorchainRev = NULL; cd->arcs = a; } /* * uncolorchain - delete this arc from the color chain of its color */ static void uncolorchain(struct colormap *cm, struct arc *a) { struct colordesc *cd = &cm->cd[a->co]; struct arc *aa = a->colorchainRev; if (aa == NULL) { assert(cd->arcs == a); cd->arcs = a->colorchain; } else { assert(aa->colorchain == a); aa->colorchain = a->colorchain; } if (a->colorchain != NULL) a->colorchain->colorchainRev = aa; a->colorchain = NULL; /* paranoia */ a->colorchainRev = NULL; } /* * rainbow - add arcs of all full colors (but one) between specified states */ static void rainbow(struct nfa *nfa, struct colormap *cm, int type, color but, /* COLORLESS if no exceptions */ struct state *from, struct state *to) { struct colordesc *cd; struct colordesc *end = CDEND(cm); color co; for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++) if (!UNUSEDCOLOR(cd) && cd->sub != co && co != but && !(cd->flags & PSEUDO)) newarc(nfa, type, co, from, to); } /* * colorcomplement - add arcs of complementary colors * * The calling sequence ought to be reconciled with cloneouts(). */ static void colorcomplement(struct nfa *nfa, struct colormap *cm, int type, struct state *of, /* complements of this guy's PLAIN outarcs */ struct state *from, struct state *to) { struct colordesc *cd; struct colordesc *end = CDEND(cm); color co; assert(of != from); for (cd = cm->cd, co = 0; cd < end && !CISERR(); cd++, co++) if (!UNUSEDCOLOR(cd) && !(cd->flags & PSEUDO)) if (findarc(of, PLAIN, co) == NULL) newarc(nfa, type, co, from, to); } #ifdef REG_DEBUG /* * dumpcolors - debugging output */ static void dumpcolors(struct colormap *cm, FILE *f) { struct colordesc *cd; struct colordesc *end; color co; chr c; fprintf(f, "max %ld\n", (long) cm->max); end = CDEND(cm); for (cd = cm->cd + 1, co = 1; cd < end; cd++, co++) /* skip 0 */ { if (!UNUSEDCOLOR(cd)) { assert(cd->nschrs > 0 || cd->nuchrs > 0); if (cd->flags & PSEUDO) fprintf(f, "#%2ld(ps): ", (long) co); else fprintf(f, "#%2ld(%2d): ", (long) co, cd->nschrs + cd->nuchrs); /* * Unfortunately, it's hard to do this next bit more efficiently. */ for (c = CHR_MIN; c <= MAX_SIMPLE_CHR; c++) if (GETCOLOR(cm, c) == co) dumpchr(c, f); fprintf(f, "\n"); } } /* dump the high colormap if it contains anything interesting */ if (cm->hiarrayrows > 1 || cm->hiarraycols > 1) { int r, c; const color *rowptr; fprintf(f, "other:\t"); for (c = 0; c < cm->hiarraycols; c++) { fprintf(f, "\t%ld", (long) cm->hicolormap[c]); } fprintf(f, "\n"); for (r = 0; r < cm->numcmranges; r++) { dumpchr(cm->cmranges[r].cmin, f); fprintf(f, ".."); dumpchr(cm->cmranges[r].cmax, f); fprintf(f, ":"); rowptr = &cm->hicolormap[cm->cmranges[r].rownum * cm->hiarraycols]; for (c = 0; c < cm->hiarraycols; c++) { fprintf(f, "\t%ld", (long) rowptr[c]); } fprintf(f, "\n"); } } } /* * dumpchr - print a chr * * Kind of char-centric but works well enough for debug use. */ static void dumpchr(chr c, FILE *f) { if (c == '\\') fprintf(f, "\\\\"); else if (c > ' ' && c <= '~') putc((char) c, f); else fprintf(f, "\\u%04lx", (long) c); } #endif /* REG_DEBUG */