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