mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-31 13:47:22 +02:00
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4d
wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
1141 lines
26 KiB
C
1141 lines
26 KiB
C
/*
|
|
* 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 */
|