2 * colorings of characters
3 * This file is #included by regcomp.c.
5 * Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
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
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.
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.
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.
34 * Note that there are some incestuous relationships between this code and
35 * NFA arc maintenance, which perhaps ought to be cleaned up sometime.
40 #define CISERR() VISERR(cm->v)
41 #define CERR(e) VERR(cm->v, (e))
46 * initcm - set up new colormap
49 initcm(struct vars
* v
,
61 cm
->ncds
= NINLINECDS
;
66 cd
= cm
->cd
; /* cm->cd[WHITE] */
70 cd
->nchrs
= CHR_MAX
- CHR_MIN
+ 1;
72 /* upper levels of tree */
73 for (t
= &cm
->tree
[0], j
= NBYTS
- 1; j
> 0; t
= nextt
, j
--)
76 for (i
= BYTTAB
- 1; i
>= 0; i
--)
79 /* bottom level is solid white */
80 t
= &cm
->tree
[NBYTS
- 1];
81 for (i
= BYTTAB
- 1; i
>= 0; i
--)
87 * freecm - free dynamically-allocated things in a colormap
90 freecm(struct colormap
* cm
)
97 cmtreefree(cm
, cm
->tree
, 0);
98 for (i
= 1; i
<= cm
->max
; i
++) /* skip WHITE */
99 if (!UNUSEDCOLOR(&cm
->cd
[i
]))
101 cb
= cm
->cd
[i
].block
;
105 if (cm
->cd
!= cm
->cdspace
)
110 * cmtreefree - free a non-terminal part of a colormap tree
113 cmtreefree(struct colormap
* cm
,
115 int level
) /* level number (top == 0) of this block */
119 union tree
*fillt
= &cm
->tree
[level
+ 1];
122 assert(level
< NBYTS
- 1); /* this level has pointers */
123 for (i
= BYTTAB
- 1; i
>= 0; i
--)
129 if (level
< NBYTS
- 2)
130 { /* more pointer blocks below */
131 cmtreefree(cm
, t
, level
+ 1);
135 { /* color block below */
136 cb
= cm
->cd
[t
->tcolor
[0]].block
;
137 if (t
!= cb
) /* not a solid block */
145 * setcolor - set the color of a character in a colormap
147 static color
/* previous color */
148 setcolor(struct colormap
* cm
,
164 assert(cm
->magic
== CMMAGIC
);
165 if (CISERR() || co
== COLORLESS
)
169 for (level
= 0, shift
= BYTBITS
* (NBYTS
- 1); shift
> 0;
170 level
++, shift
-= BYTBITS
)
172 b
= (uc
>> shift
) & BYTMASK
;
176 fillt
= &cm
->tree
[level
+ 1];
177 bottom
= (shift
<= BYTBITS
) ? 1 : 0;
178 cb
= (bottom
) ? cm
->cd
[t
->tcolor
[0]].block
: fillt
;
179 if (t
== fillt
|| t
== cb
)
180 { /* must allocate a new block */
181 newt
= (union tree
*) MALLOC((bottom
) ?
182 sizeof(struct colors
) : sizeof(struct ptrs
));
189 memcpy(VS(newt
->tcolor
), VS(t
->tcolor
),
190 BYTTAB
* sizeof(color
));
192 memcpy(VS(newt
->tptr
), VS(t
->tptr
),
193 BYTTAB
* sizeof(union tree
*));
201 t
->tcolor
[b
] = (color
) co
;
206 * maxcolor - report largest color number in use
209 maxcolor(struct colormap
* cm
)
214 return (color
) cm
->max
;
218 * newcolor - find a new color (must be subject of setcolor at once)
219 * Beware: may relocate the colordescs.
221 static color
/* COLORLESS for error */
222 newcolor(struct colormap
* cm
)
224 struct colordesc
*cd
;
232 assert(cm
->free
> 0);
233 assert((size_t) cm
->free
< cm
->ncds
);
234 cd
= &cm
->cd
[cm
->free
];
235 assert(UNUSEDCOLOR(cd
));
236 assert(cd
->arcs
== NULL
);
239 else if (cm
->max
< cm
->ncds
- 1)
242 cd
= &cm
->cd
[cm
->max
];
246 /* oops, must allocate more */
247 struct colordesc
*newCd
;
250 if (cm
->cd
== cm
->cdspace
)
252 newCd
= (struct colordesc
*) MALLOC(n
* sizeof(struct colordesc
));
254 memcpy(VS(newCd
), VS(cm
->cdspace
), cm
->ncds
*
255 sizeof(struct colordesc
));
258 newCd
= (struct colordesc
*)
259 REALLOC(cm
->cd
, n
* sizeof(struct colordesc
));
267 assert(cm
->max
< cm
->ncds
- 1);
269 cd
= &cm
->cd
[cm
->max
];
278 return (color
) (cd
- cm
->cd
);
282 * freecolor - free a color (must have no arcs or subcolor)
285 freecolor(struct colormap
* cm
,
288 struct colordesc
*cd
= &cm
->cd
[co
];
290 nco
; /* for freelist scan */
296 assert(cd
->arcs
== NULL
);
297 assert(cd
->sub
== NOSUB
);
298 assert(cd
->nchrs
== 0);
300 if (cd
->block
!= NULL
)
303 cd
->block
= NULL
; /* just paranoia */
306 if ((size_t) co
== cm
->max
)
308 while (cm
->max
> WHITE
&& UNUSEDCOLOR(&cm
->cd
[cm
->max
]))
310 assert(cm
->free
>= 0);
311 while ((size_t) cm
->free
> cm
->max
)
312 cm
->free
= cm
->cd
[cm
->free
].sub
;
315 assert(cm
->free
< cm
->max
);
317 nco
= cm
->cd
[pco
].sub
;
319 if ((size_t) nco
> cm
->max
)
321 /* take this one out of freelist */
322 nco
= cm
->cd
[nco
].sub
;
323 cm
->cd
[pco
].sub
= nco
;
327 assert(nco
< cm
->max
);
329 nco
= cm
->cd
[pco
].sub
;
336 cm
->free
= (color
) (cd
- cm
->cd
);
341 * pseudocolor - allocate a false color, to be managed by other means
344 pseudocolor(struct colormap
* cm
)
351 cm
->cd
[co
].nchrs
= 1;
352 cm
->cd
[co
].flags
= PSEUDO
;
357 * subcolor - allocate a new subcolor (if necessary) to this chr
360 subcolor(struct colormap
* cm
, chr c
)
362 color co
; /* current color of c */
363 color sco
; /* new subcolor */
365 co
= GETCOLOR(cm
, c
);
366 sco
= newsub(cm
, co
);
369 assert(sco
!= COLORLESS
);
371 if (co
== sco
) /* already in an open subcolor */
372 return co
; /* rest is redundant */
375 setcolor(cm
, c
, sco
);
380 * newsub - allocate a new subcolor (if necessary) for a color
383 newsub(struct colormap
* cm
,
386 color sco
; /* new subcolor */
388 sco
= cm
->cd
[co
].sub
;
390 { /* color has no open subcolor */
391 if (cm
->cd
[co
].nchrs
== 1) /* optimization */
393 sco
= newcolor(cm
); /* must create subcolor */
394 if (sco
== COLORLESS
)
399 cm
->cd
[co
].sub
= sco
;
400 cm
->cd
[sco
].sub
= sco
; /* open subcolor points to self */
402 assert(sco
!= NOSUB
);
408 * subrange - allocate new subcolors to this range of chrs, fill in arcs
411 subrange(struct vars
* v
,
422 /* first, align "from" on a tree-block boundary */
424 i
= (int) (((uf
+ BYTTAB
- 1) & (uchr
) ~BYTMASK
) - uf
);
425 for (; from
<= to
&& i
> 0; i
--, from
++)
426 newarc(v
->nfa
, PLAIN
, subcolor(v
->cm
, from
), lp
, rp
);
427 if (from
> to
) /* didn't reach a boundary */
430 /* deal with whole blocks */
431 for (; to
- from
>= BYTTAB
; from
+= BYTTAB
)
432 subblock(v
, from
, lp
, rp
);
434 /* clean up any remaining partial table */
435 for (; from
<= to
; from
++)
436 newarc(v
->nfa
, PLAIN
, subcolor(v
->cm
, from
), lp
, rp
);
440 * subblock - allocate new subcolors for one tree block of chrs, fill in arcs
443 subblock(struct vars
* v
,
444 chr start
, /* first of BYTTAB chrs */
449 struct colormap
*cm
= v
->cm
;
463 assert((uc
% BYTTAB
) == 0);
465 /* find its color block, making new pointer blocks as needed */
468 for (level
= 0, shift
= BYTBITS
* (NBYTS
- 1); shift
> 0;
469 level
++, shift
-= BYTBITS
)
471 b
= (uc
>> shift
) & BYTMASK
;
475 fillt
= &cm
->tree
[level
+ 1];
476 if (t
== fillt
&& shift
> BYTBITS
)
477 { /* need new ptr block */
478 t
= (union tree
*) MALLOC(sizeof(struct ptrs
));
484 memcpy(VS(t
->tptr
), VS(fillt
->tptr
),
485 BYTTAB
* sizeof(union tree
*));
490 /* special cases: fill block or solid block */
492 cb
= cm
->cd
[co
].block
;
493 if (t
== fillt
|| t
== cb
)
495 /* either way, we want a subcolor solid block */
496 sco
= newsub(cm
, co
);
497 t
= cm
->cd
[sco
].block
;
499 { /* must set it up */
500 t
= (union tree
*) MALLOC(sizeof(struct colors
));
506 for (i
= 0; i
< BYTTAB
; i
++)
508 cm
->cd
[sco
].block
= t
;
510 /* find loop must have run at least once */
512 newarc(v
->nfa
, PLAIN
, sco
, lp
, rp
);
513 cm
->cd
[co
].nchrs
-= BYTTAB
;
514 cm
->cd
[sco
].nchrs
+= BYTTAB
;
518 /* general case, a mixed block to be altered */
523 sco
= newsub(cm
, co
);
524 newarc(v
->nfa
, PLAIN
, sco
, lp
, rp
);
528 t
->tcolor
[i
++] = sco
;
529 } while (i
< BYTTAB
&& t
->tcolor
[i
] == co
);
531 cm
->cd
[co
].nchrs
-= ndone
;
532 cm
->cd
[sco
].nchrs
+= ndone
;
537 * okcolors - promote subcolors to full colors
540 okcolors(struct nfa
* nfa
,
541 struct colormap
* cm
)
543 struct colordesc
*cd
;
544 struct colordesc
*end
= CDEND(cm
);
545 struct colordesc
*scd
;
550 for (cd
= cm
->cd
, co
= 0; cd
< end
; cd
++, co
++)
553 if (UNUSEDCOLOR(cd
) || sco
== NOSUB
)
555 /* has no subcolor, no further action */
559 /* is subcolor, let parent deal with it */
561 else if (cd
->nchrs
== 0)
563 /* parent empty, its arcs change color to subcolor */
566 assert(scd
->nchrs
> 0);
567 assert(scd
->sub
== sco
);
569 while ((a
= cd
->arcs
) != NULL
)
580 /* parent's arcs must gain parallel subcolor arcs */
583 assert(scd
->nchrs
> 0);
584 assert(scd
->sub
== sco
);
586 for (a
= cd
->arcs
; a
!= NULL
; a
= a
->colorchain
)
589 newarc(nfa
, a
->type
, sco
, a
->from
, a
->to
);
596 * colorchain - add this arc to the color chain of its color
599 colorchain(struct colormap
* cm
,
602 struct colordesc
*cd
= &cm
->cd
[a
->co
];
604 if (cd
->arcs
!= NULL
)
605 cd
->arcs
->colorchainRev
= a
;
606 a
->colorchain
= cd
->arcs
;
607 a
->colorchainRev
= NULL
;
612 * uncolorchain - delete this arc from the color chain of its color
615 uncolorchain(struct colormap
* cm
,
618 struct colordesc
*cd
= &cm
->cd
[a
->co
];
619 struct arc
*aa
= a
->colorchainRev
;
623 assert(cd
->arcs
== a
);
624 cd
->arcs
= a
->colorchain
;
628 assert(aa
->colorchain
== a
);
629 aa
->colorchain
= a
->colorchain
;
631 if (a
->colorchain
!= NULL
)
632 a
->colorchain
->colorchainRev
= aa
;
633 a
->colorchain
= NULL
; /* paranoia */
634 a
->colorchainRev
= NULL
;
638 * rainbow - add arcs of all full colors (but one) between specified states
641 rainbow(struct nfa
* nfa
,
642 struct colormap
* cm
,
644 pcolor but
, /* COLORLESS if no exceptions */
648 struct colordesc
*cd
;
649 struct colordesc
*end
= CDEND(cm
);
652 for (cd
= cm
->cd
, co
= 0; cd
< end
&& !CISERR(); cd
++, co
++)
653 if (!UNUSEDCOLOR(cd
) && cd
->sub
!= co
&& co
!= but
&&
654 !(cd
->flags
& PSEUDO
))
655 newarc(nfa
, type
, co
, from
, to
);
659 * colorcomplement - add arcs of complementary colors
661 * The calling sequence ought to be reconciled with cloneouts().
664 colorcomplement(struct nfa
* nfa
,
665 struct colormap
* cm
,
667 struct state
* of
, /* complements of this guy's PLAIN
672 struct colordesc
*cd
;
673 struct colordesc
*end
= CDEND(cm
);
677 for (cd
= cm
->cd
, co
= 0; cd
< end
&& !CISERR(); cd
++, co
++)
678 if (!UNUSEDCOLOR(cd
) && !(cd
->flags
& PSEUDO
))
679 if (findarc(of
, PLAIN
, co
) == NULL
)
680 newarc(nfa
, type
, co
, from
, to
);
687 * dumpcolors - debugging output
690 dumpcolors(struct colormap
* cm
,
693 struct colordesc
*cd
;
694 struct colordesc
*end
;
699 fprintf(f
, "max %ld\n", (long) cm
->max
);
701 fillcheck(cm
, cm
->tree
, 0, f
);
703 for (cd
= cm
->cd
+ 1, co
= 1; cd
< end
; cd
++, co
++) /* skip 0 */
704 if (!UNUSEDCOLOR(cd
))
706 assert(cd
->nchrs
> 0);
707 has
= (cd
->block
!= NULL
) ? "#" : "";
708 if (cd
->flags
& PSEUDO
)
709 fprintf(f
, "#%2ld%s(ps): ", (long) co
, has
);
711 fprintf(f
, "#%2ld%s(%2d): ", (long) co
,
715 * Unfortunately, it's hard to do this next bit more efficiently.
717 * Spencer's original coding has the loop iterating from CHR_MIN
718 * to CHR_MAX, but that's utterly unusable for 32-bit chr. For
719 * debugging purposes it seems fine to print only chr codes up to
722 for (c
= CHR_MIN
; c
< 1000; c
++)
723 if (GETCOLOR(cm
, c
) == co
)
730 * fillcheck - check proper filling of a tree
733 fillcheck(struct colormap
* cm
,
735 int level
, /* level number (top == 0) of this block */
740 union tree
*fillt
= &cm
->tree
[level
+ 1];
742 assert(level
< NBYTS
- 1); /* this level has pointers */
743 for (i
= BYTTAB
- 1; i
>= 0; i
--)
747 fprintf(f
, "NULL found in filled tree!\n");
751 else if (level
< NBYTS
- 2) /* more pointer blocks below */
752 fillcheck(cm
, t
, level
+ 1, f
);
757 * dumpchr - print a chr
759 * Kind of char-centric but works well enough for debug use.
767 else if (c
> ' ' && c
<= '~')
770 fprintf(f
, "\\u%04lx", (long) c
);
773 #endif /* REG_DEBUG */