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 of
18 * 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 * Note that there are some incestuous relationships between this code and NFA
32 * arc maintenance, which perhaps ought to be cleaned up sometime.
33 */
34
35 #define CISERR() VISERR(cm->v)
36 #define CERR(e) VERR(cm->v, (e))
37
38 /*
39 - initcm - set up new colormap
40 ^ static void initcm(struct vars *, struct colormap *);
41 */
42 static void
initcm(struct vars * v,struct colormap * cm)43 initcm(
44 struct vars *v,
45 struct colormap *cm)
46 {
47 int i;
48 int j;
49 union tree *t;
50 union tree *nextt;
51 struct colordesc *cd;
52
53 cm->magic = CMMAGIC;
54 cm->v = v;
55
56 cm->ncds = NINLINECDS;
57 cm->cd = cm->cdspace;
58 cm->max = 0;
59 cm->free = 0;
60
61 cd = cm->cd; /* cm->cd[WHITE] */
62 cd->sub = NOSUB;
63 cd->arcs = NULL;
64 cd->flags = 0;
65 cd->nchrs = CHR_MAX - CHR_MIN + 1;
66
67 /*
68 * Upper levels of tree.
69 */
70
71 for (t=&cm->tree[0], j=NBYTS-1 ; j>0 ; t=nextt, j--) {
72 nextt = t + 1;
73 for (i=BYTTAB-1 ; i>=0 ; i--) {
74 t->tptr[i] = nextt;
75 }
76 }
77
78 /*
79 * Bottom level is solid white.
80 */
81
82 t = &cm->tree[NBYTS-1];
83 for (i=BYTTAB-1 ; i>=0 ; i--) {
84 t->tcolor[i] = WHITE;
85 }
86 cd->block = t;
87 }
88
89 /*
90 - freecm - free dynamically-allocated things in a colormap
91 ^ static void freecm(struct colormap *);
92 */
93 static void
freecm(struct colormap * cm)94 freecm(
95 struct colormap *cm)
96 {
97 size_t i;
98 union tree *cb;
99
100 cm->magic = 0;
101 if (NBYTS > 1) {
102 cmtreefree(cm, cm->tree, 0);
103 }
104 for (i=1 ; i<=cm->max ; i++) { /* skip WHITE */
105 if (!UNUSEDCOLOR(&cm->cd[i])) {
106 cb = cm->cd[i].block;
107 if (cb != NULL) {
108 FREE(cb);
109 }
110 }
111 }
112 if (cm->cd != cm->cdspace) {
113 FREE(cm->cd);
114 }
115 }
116
117 /*
118 - cmtreefree - free a non-terminal part of a colormap tree
119 ^ static void cmtreefree(struct colormap *, union tree *, int);
120 */
121 static void
cmtreefree(struct colormap * cm,union tree * tree,int level)122 cmtreefree(
123 struct colormap *cm,
124 union tree *tree,
125 int level) /* level number (top == 0) of this block */
126 {
127 int i;
128 union tree *t;
129 union tree *fillt = &cm->tree[level+1];
130 union tree *cb;
131
132 assert(level < NBYTS-1); /* this level has pointers */
133 for (i=BYTTAB-1 ; i>=0 ; i--) {
134 t = tree->tptr[i];
135 assert(t != NULL);
136 if (t != fillt) {
137 if (level < NBYTS-2) { /* more pointer blocks below */
138 cmtreefree(cm, t, level+1);
139 FREE(t);
140 } else { /* color block below */
141 cb = cm->cd[t->tcolor[0]].block;
142 if (t != cb) { /* not a solid block */
143 FREE(t);
144 }
145 }
146 }
147 }
148 }
149
150 /*
151 - setcolor - set the color of a character in a colormap
152 ^ static color setcolor(struct colormap *, pchr, pcolor);
153 */
154 static color /* previous color */
setcolor(struct colormap * cm,pchr c,pcolor co)155 setcolor(
156 struct colormap *cm,
157 pchr c,
158 pcolor co)
159 {
160 uchr uc = c;
161 int shift;
162 int level;
163 int b;
164 int bottom;
165 union tree *t;
166 union tree *newt;
167 union tree *fillt;
168 union tree *lastt;
169 union tree *cb;
170 color prev;
171
172 assert(cm->magic == CMMAGIC);
173 if (CISERR() || co == COLORLESS) {
174 return COLORLESS;
175 }
176
177 t = cm->tree;
178 for (level=0, shift=BYTBITS*(NBYTS-1) ; shift>0; level++, shift-=BYTBITS){
179 b = (uc >> shift) & BYTMASK;
180 lastt = t;
181 t = lastt->tptr[b];
182 assert(t != NULL);
183 fillt = &cm->tree[level+1];
184 bottom = (shift <= BYTBITS) ? 1 : 0;
185 cb = (bottom) ? cm->cd[t->tcolor[0]].block : fillt;
186 if (t == fillt || t == cb) { /* must allocate a new block */
187 newt = (union tree *) MALLOC((bottom) ?
188 sizeof(struct colors) : sizeof(struct ptrs));
189 if (newt == NULL) {
190 CERR(REG_ESPACE);
191 return COLORLESS;
192 }
193 if (bottom) {
194 memcpy(newt->tcolor, t->tcolor, BYTTAB*sizeof(color));
195 } else {
196 memcpy(newt->tptr, t->tptr, BYTTAB*sizeof(union tree *));
197 }
198 t = newt;
199 lastt->tptr[b] = t;
200 }
201 }
202
203 b = uc & BYTMASK;
204 prev = t->tcolor[b];
205 t->tcolor[b] = (color) co;
206 return prev;
207 }
208
209 /*
210 - maxcolor - report largest color number in use
211 ^ static color maxcolor(struct colormap *);
212 */
213 static color
maxcolor(struct colormap * cm)214 maxcolor(
215 struct colormap *cm)
216 {
217 if (CISERR()) {
218 return COLORLESS;
219 }
220
221 return (color) cm->max;
222 }
223
224 /*
225 - newcolor - find a new color (must be subject of setcolor at once)
226 * Beware: may relocate the colordescs.
227 ^ static color newcolor(struct colormap *);
228 */
229 static color /* COLORLESS for error */
newcolor(struct colormap * cm)230 newcolor(
231 struct colormap *cm)
232 {
233 struct colordesc *cd;
234 size_t n;
235
236 if (CISERR()) {
237 return COLORLESS;
238 }
239
240 if (cm->free != 0) {
241 assert(cm->free > 0);
242 assert((size_t) cm->free < cm->ncds);
243 cd = &cm->cd[cm->free];
244 assert(UNUSEDCOLOR(cd));
245 assert(cd->arcs == NULL);
246 cm->free = cd->sub;
247 } else if (cm->max < cm->ncds - 1) {
248 cm->max++;
249 cd = &cm->cd[cm->max];
250 } else {
251 struct colordesc *newCd;
252
253 /*
254 * Oops, must allocate more.
255 */
256
257 if (cm->max == MAX_COLOR) {
258 CERR(REG_ECOLORS);
259 return COLORLESS; /* too many colors */
260 }
261 n = cm->ncds * 2;
262 if (n > MAX_COLOR + 1) {
263 n = MAX_COLOR + 1;
264 }
265 if (cm->cd == cm->cdspace) {
266 newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc));
267 if (newCd != NULL) {
268 memcpy(newCd, cm->cdspace,
269 cm->ncds * sizeof(struct colordesc));
270 }
271 } else {
272 newCd = (struct colordesc *)
273 REALLOC(cm->cd, n * sizeof(struct colordesc));
274 }
275 if (newCd == NULL) {
276 CERR(REG_ESPACE);
277 return COLORLESS;
278 }
279 cm->cd = newCd;
280 cm->ncds = n;
281 assert(cm->max < cm->ncds - 1);
282 cm->max++;
283 cd = &cm->cd[cm->max];
284 }
285
286 cd->nchrs = 0;
287 cd->sub = NOSUB;
288 cd->arcs = NULL;
289 cd->flags = 0;
290 cd->block = NULL;
291
292 return (color) (cd - cm->cd);
293 }
294
295 /*
296 - freecolor - free a color (must have no arcs or subcolor)
297 ^ static void freecolor(struct colormap *, pcolor);
298 */
299 static void
freecolor(struct colormap * cm,pcolor co)300 freecolor(
301 struct colormap *cm,
302 pcolor co)
303 {
304 struct colordesc *cd = &cm->cd[co];
305 color pco, nco; /* for freelist scan */
306
307 assert(co >= 0);
308 if (co == WHITE) {
309 return;
310 }
311
312 assert(cd->arcs == NULL);
313 assert(cd->sub == NOSUB);
314 assert(cd->nchrs == 0);
315 cd->flags = FREECOL;
316 if (cd->block != NULL) {
317 FREE(cd->block);
318 cd->block = NULL; /* just paranoia */
319 }
320
321 if ((size_t) co == cm->max) {
322 while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max])) {
323 cm->max--;
324 }
325 assert(cm->free >= 0);
326 while ((size_t) cm->free > cm->max) {
327 cm->free = cm->cd[cm->free].sub;
328 }
329 if (cm->free > 0) {
330 assert((size_t)cm->free < cm->max);
331 pco = cm->free;
332 nco = cm->cd[pco].sub;
333 while (nco > 0) {
334 if ((size_t) nco > cm->max) {
335 /*
336 * Take this one out of freelist.
337 */
338
339 nco = cm->cd[nco].sub;
340 cm->cd[pco].sub = nco;
341 } else {
342 assert((size_t)nco < cm->max);
343 pco = nco;
344 nco = cm->cd[pco].sub;
345 }
346 }
347 }
348 } else {
349 cd->sub = cm->free;
350 cm->free = (color) (cd - cm->cd);
351 }
352 }
353
354 /*
355 - pseudocolor - allocate a false color, to be managed by other means
356 ^ static color pseudocolor(struct colormap *);
357 */
358 static color
pseudocolor(struct colormap * cm)359 pseudocolor(
360 struct colormap *cm)
361 {
362 color co;
363
364 co = newcolor(cm);
365 if (CISERR()) {
366 return COLORLESS;
367 }
368 cm->cd[co].nchrs = 1;
369 cm->cd[co].flags = PSEUDO;
370 return co;
371 }
372
373 /*
374 - subcolor - allocate a new subcolor (if necessary) to this chr
375 ^ static color subcolor(struct colormap *, pchr c);
376 */
377 static color
subcolor(struct colormap * cm,pchr c)378 subcolor(
379 struct colormap *cm,
380 pchr c)
381 {
382 color co; /* current color of c */
383 color sco; /* new subcolor */
384
385 co = GETCOLOR(cm, c);
386 sco = newsub(cm, co);
387 if (CISERR()) {
388 return COLORLESS;
389 }
390 assert(sco != COLORLESS);
391
392 if (co == sco) { /* already in an open subcolor */
393 return co; /* rest is redundant */
394 }
395 cm->cd[co].nchrs--;
396 cm->cd[sco].nchrs++;
397 setcolor(cm, c, sco);
398 return sco;
399 }
400
401 /*
402 - newsub - allocate a new subcolor (if necessary) for a color
403 ^ static color newsub(struct colormap *, pcolor);
404 */
405 static color
newsub(struct colormap * cm,pcolor co)406 newsub(
407 struct colormap *cm,
408 pcolor co)
409 {
410 color sco; /* new subcolor */
411
412 sco = cm->cd[co].sub;
413 if (sco == NOSUB) { /* color has no open subcolor */
414 if (cm->cd[co].nchrs == 1) { /* optimization */
415 return co;
416 }
417 sco = newcolor(cm); /* must create subcolor */
418 if (sco == COLORLESS) {
419 assert(CISERR());
420 return COLORLESS;
421 }
422 cm->cd[co].sub = sco;
423 cm->cd[sco].sub = sco; /* open subcolor points to self */
424 }
425 assert(sco != NOSUB);
426
427 return sco;
428 }
429
430 /*
431 - subrange - allocate new subcolors to this range of chrs, fill in arcs
432 ^ static void subrange(struct vars *, pchr, pchr, struct state *,
433 ^ struct state *);
434 */
435 static void
subrange(struct vars * v,pchr from,pchr to,struct state * lp,struct state * rp)436 subrange(
437 struct vars *v,
438 pchr from,
439 pchr to,
440 struct state *lp,
441 struct state *rp)
442 {
443 uchr uf;
444 int i;
445
446 assert(from <= to);
447
448 /*
449 * First, align "from" on a tree-block boundary
450 */
451
452 uf = (uchr) from;
453 i = (int) (((uf + BYTTAB - 1) & (uchr) ~BYTMASK) - uf);
454 for (; from<=to && i>0; i--, from++) {
455 newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp);
456 }
457 if (from > to) { /* didn't reach a boundary */
458 return;
459 }
460
461 /*
462 * Deal with whole blocks.
463 */
464
465 for (; to-from>=BYTTAB ; from+=BYTTAB) {
466 subblock(v, from, lp, rp);
467 }
468
469 /*
470 * Clean up any remaining partial table.
471 */
472
473 for (; from<=to ; from++) {
474 newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp);
475 }
476 }
477
478 /*
479 - subblock - allocate new subcolors for one tree block of chrs, fill in arcs
480 ^ static void subblock(struct vars *, pchr, struct state *, struct state *);
481 */
482 static void
subblock(struct vars * v,pchr start,struct state * lp,struct state * rp)483 subblock(
484 struct vars *v,
485 pchr start, /* first of BYTTAB chrs */
486 struct state *lp,
487 struct state *rp)
488 {
489 uchr uc = start;
490 struct colormap *cm = v->cm;
491 int shift;
492 int level;
493 int i;
494 int b;
495 union tree *t;
496 union tree *cb;
497 union tree *fillt;
498 union tree *lastt;
499 int previ;
500 int ndone;
501 color co;
502 color sco;
503
504 assert((uc % BYTTAB) == 0);
505
506 /*
507 * Find its color block, making new pointer blocks as needed.
508 */
509
510 t = cm->tree;
511 fillt = NULL;
512 for (level=0, shift=BYTBITS*(NBYTS-1); shift>0; level++, shift-=BYTBITS) {
513 b = (uc >> shift) & BYTMASK;
514 lastt = t;
515 t = lastt->tptr[b];
516 assert(t != NULL);
517 fillt = &cm->tree[level+1];
518 if (t == fillt && shift > BYTBITS) { /* need new ptr block */
519 t = (union tree *) MALLOC(sizeof(struct ptrs));
520 if (t == NULL) {
521 CERR(REG_ESPACE);
522 return;
523 }
524 memcpy(t->tptr, fillt->tptr, BYTTAB*sizeof(union tree *));
525 lastt->tptr[b] = t;
526 }
527 }
528
529 /*
530 * Special cases: fill block or solid block.
531 */
532 co = t->tcolor[0];
533 cb = cm->cd[co].block;
534 if (t == fillt || t == cb) {
535 /*
536 * Either way, we want a subcolor solid block.
537 */
538
539 sco = newsub(cm, co);
540 t = cm->cd[sco].block;
541 if (t == NULL) { /* must set it up */
542 t = (union tree *) MALLOC(sizeof(struct colors));
543 if (t == NULL) {
544 CERR(REG_ESPACE);
545 return;
546 }
547 for (i=0 ; i<BYTTAB ; i++) {
548 t->tcolor[i] = sco;
549 }
550 cm->cd[sco].block = t;
551 }
552
553 /*
554 * Find loop must have run at least once.
555 */
556
557 lastt->tptr[b] = t;
558 newarc(v->nfa, PLAIN, sco, lp, rp);
559 cm->cd[co].nchrs -= BYTTAB;
560 cm->cd[sco].nchrs += BYTTAB;
561 return;
562 }
563
564 /*
565 * General case, a mixed block to be altered.
566 */
567
568 i = 0;
569 while (i < BYTTAB) {
570 co = t->tcolor[i];
571 sco = newsub(cm, co);
572 newarc(v->nfa, PLAIN, sco, lp, rp);
573 previ = i;
574 do {
575 t->tcolor[i++] = sco;
576 } while (i < BYTTAB && t->tcolor[i] == co);
577 ndone = i - previ;
578 cm->cd[co].nchrs -= ndone;
579 cm->cd[sco].nchrs += ndone;
580 }
581 }
582
583 /*
584 - okcolors - promote subcolors to full colors
585 ^ static void okcolors(struct nfa *, struct colormap *);
586 */
587 static void
okcolors(struct nfa * nfa,struct colormap * cm)588 okcolors(
589 struct nfa *nfa,
590 struct colormap *cm)
591 {
592 struct colordesc *cd;
593 struct colordesc *end = CDEND(cm);
594 struct colordesc *scd;
595 struct arc *a;
596 color co;
597 color sco;
598
599 for (cd=cm->cd, co=0 ; cd<end ; cd++, co++) {
600 sco = cd->sub;
601 if (UNUSEDCOLOR(cd) || sco == NOSUB) {
602 /*
603 * Has no subcolor, no further action.
604 */
605 } else if (sco == co) {
606 /*
607 * Is subcolor, let parent deal with it.
608 */
609 } else if (cd->nchrs == 0) {
610 /*
611 * Parent empty, its arcs change color to subcolor.
612 */
613
614 cd->sub = NOSUB;
615 scd = &cm->cd[sco];
616 assert(scd->nchrs > 0);
617 assert(scd->sub == sco);
618 scd->sub = NOSUB;
619 while ((a = cd->arcs) != NULL) {
620 assert(a->co == co);
621 uncolorchain(cm, a);
622 a->co = sco;
623 colorchain(cm, a);
624 }
625 freecolor(cm, co);
626 } else {
627 /*
628 * Parent's arcs must gain parallel subcolor arcs.
629 */
630
631 cd->sub = NOSUB;
632 scd = &cm->cd[sco];
633 assert(scd->nchrs > 0);
634 assert(scd->sub == sco);
635 scd->sub = NOSUB;
636 for (a=cd->arcs ; a!=NULL ; a=a->colorchain) {
637 assert(a->co == co);
638 newarc(nfa, a->type, sco, a->from, a->to);
639 }
640 }
641 }
642 }
643
644 /*
645 - colorchain - add this arc to the color chain of its color
646 ^ static void colorchain(struct colormap *, struct arc *);
647 */
648 static void
colorchain(struct colormap * cm,struct arc * a)649 colorchain(
650 struct colormap *cm,
651 struct arc *a)
652 {
653 struct colordesc *cd = &cm->cd[a->co];
654
655 if (cd->arcs != NULL) {
656 cd->arcs->colorchainRev = a;
657 }
658 a->colorchain = cd->arcs;
659 a->colorchainRev = NULL;
660 cd->arcs = a;
661 }
662
663 /*
664 - uncolorchain - delete this arc from the color chain of its color
665 ^ static void uncolorchain(struct colormap *, struct arc *);
666 */
667 static void
uncolorchain(struct colormap * cm,struct arc * a)668 uncolorchain(
669 struct colormap *cm,
670 struct arc *a)
671 {
672 struct colordesc *cd = &cm->cd[a->co];
673 struct arc *aa = a->colorchainRev;
674
675 if (aa == NULL) {
676 assert(cd->arcs == a);
677 cd->arcs = a->colorchain;
678 } else {
679 assert(aa->colorchain == a);
680 aa->colorchain = a->colorchain;
681 }
682 if (a->colorchain != NULL) {
683 a->colorchain->colorchainRev = aa;
684 }
685 a->colorchain = NULL; /* paranoia */
686 a->colorchainRev = NULL;
687 }
688
689 /*
690 - rainbow - add arcs of all full colors (but one) between specified states
691 ^ static void rainbow(struct nfa *, struct colormap *, int, pcolor,
692 ^ struct state *, struct state *);
693 */
694 static void
rainbow(struct nfa * nfa,struct colormap * cm,int type,pcolor but,struct state * from,struct state * to)695 rainbow(
696 struct nfa *nfa,
697 struct colormap *cm,
698 int type,
699 pcolor but, /* COLORLESS if no exceptions */
700 struct state *from,
701 struct state *to)
702 {
703 struct colordesc *cd;
704 struct colordesc *end = CDEND(cm);
705 color co;
706
707 for (cd=cm->cd, co=0 ; cd<end && !CISERR(); cd++, co++) {
708 if (!UNUSEDCOLOR(cd) && (cd->sub != co) && (co != but)
709 && !(cd->flags&PSEUDO)) {
710 newarc(nfa, type, co, from, to);
711 }
712 }
713 }
714
715 /*
716 - colorcomplement - add arcs of complementary colors
717 * The calling sequence ought to be reconciled with cloneouts().
718 ^ static void colorcomplement(struct nfa *, struct colormap *, int,
719 ^ struct state *, struct state *, struct state *);
720 */
721 static void
colorcomplement(struct nfa * nfa,struct colormap * cm,int type,struct state * of,struct state * from,struct state * to)722 colorcomplement(
723 struct nfa *nfa,
724 struct colormap *cm,
725 int type,
726 struct state *of, /* complements of this guy's PLAIN outarcs */
727 struct state *from,
728 struct state *to)
729 {
730 struct colordesc *cd;
731 struct colordesc *end = CDEND(cm);
732 color co;
733
734 assert(of != from);
735 for (cd=cm->cd, co=0 ; cd<end && !CISERR() ; cd++, co++) {
736 if (!UNUSEDCOLOR(cd) && !(cd->flags&PSEUDO)) {
737 if (findarc(of, PLAIN, co) == NULL) {
738 newarc(nfa, type, co, from, to);
739 }
740 }
741 }
742 }
743
744 #ifdef REG_DEBUG
745 /*
746 ^ #ifdef REG_DEBUG
747 */
748
749 /*
750 - dumpcolors - debugging output
751 ^ static void dumpcolors(struct colormap *, FILE *);
752 */
753 static void
dumpcolors(struct colormap * cm,FILE * f)754 dumpcolors(
755 struct colormap *cm,
756 FILE *f)
757 {
758 struct colordesc *cd;
759 struct colordesc *end;
760 color co;
761 chr c;
762 char *has;
763
764 fprintf(f, "max %ld\n", (long) cm->max);
765 if (NBYTS > 1) {
766 fillcheck(cm, cm->tree, 0, f);
767 }
768 end = CDEND(cm);
769 for (cd=cm->cd+1, co=1 ; cd<end ; cd++, co++) { /* skip 0 */
770 if (!UNUSEDCOLOR(cd)) {
771 assert(cd->nchrs > 0);
772 has = (cd->block != NULL) ? "#" : "";
773 if (cd->flags&PSEUDO) {
774 fprintf(f, "#%2ld%s(ps): ", (long) co, has);
775 } else {
776 fprintf(f, "#%2ld%s(%2d): ", (long) co, has, cd->nchrs);
777 }
778
779 /*
780 * Unfortunately, it's hard to do this next bit more efficiently.
781 *
782 * Spencer's original coding has the loop iterating from CHR_MIN
783 * to CHR_MAX, but that's utterly unusable for 32-bit chr, or
784 * even 16-bit. For debugging purposes it seems fine to print
785 * only chr codes up to 1000 or so.
786 */
787
788 for (c=CHR_MIN ; c<1000 ; c++) {
789 if (GETCOLOR(cm, c) == co) {
790 dumpchr(c, f);
791 }
792 }
793 fprintf(f, "\n");
794 }
795 }
796 }
797
798 /*
799 - fillcheck - check proper filling of a tree
800 ^ static void fillcheck(struct colormap *, union tree *, int, FILE *);
801 */
802 static void
fillcheck(struct colormap * cm,union tree * tree,int level,FILE * f)803 fillcheck(
804 struct colormap *cm,
805 union tree *tree,
806 int level, /* level number (top == 0) of this block */
807 FILE *f)
808 {
809 int i;
810 union tree *t;
811 union tree *fillt = &cm->tree[level+1];
812
813 assert(level < NBYTS-1); /* this level has pointers */
814 for (i=BYTTAB-1 ; i>=0 ; i--) {
815 t = tree->tptr[i];
816 if (t == NULL) {
817 fprintf(f, "NULL found in filled tree!\n");
818 } else if (t == fillt) {
819 /* empty body */
820 } else if (level < NBYTS-2) { /* more pointer blocks below */
821 fillcheck(cm, t, level+1, f);
822 }
823 }
824 }
825
826 /*
827 - dumpchr - print a chr
828 * Kind of char-centric but works well enough for debug use.
829 ^ static void dumpchr(pchr, FILE *);
830 */
831 static void
dumpchr(pchr c,FILE * f)832 dumpchr(
833 pchr c,
834 FILE *f)
835 {
836 if (c == '\\') {
837 fprintf(f, "\\\\");
838 } else if (c > ' ' && c <= '~') {
839 putc((char) c, f);
840 } else {
841 fprintf(f, "\\u%04lx", (long) c);
842 }
843 }
844
845 /*
846 ^ #endif
847 */
848 #endif /* ifdef REG_DEBUG */
849
850 /*
851 * Local Variables:
852 * mode: c
853 * c-basic-offset: 4
854 * fill-column: 78
855 * End:
856 */
857