/Users/deen/code/yugabyte-db/src/postgres/src/backend/regex/regc_color.c
Line | Count | Source (jump to first uncovered line) |
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 |
18 | | * of 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 | | * src/backend/regex/regc_color.c |
32 | | * |
33 | | * |
34 | | * Note that there are some incestuous relationships between this code and |
35 | | * NFA arc maintenance, which perhaps ought to be cleaned up sometime. |
36 | | */ |
37 | | |
38 | | |
39 | | |
40 | 49.8k | #define CISERR() VISERR(cm->v) |
41 | 0 | #define CERR(e) VERR(cm->v, (e)) |
42 | | |
43 | | |
44 | | |
45 | | /* |
46 | | * initcm - set up new colormap |
47 | | */ |
48 | | static void |
49 | | initcm(struct vars *v, |
50 | | struct colormap *cm) |
51 | 325 | { |
52 | 325 | struct colordesc *cd; |
53 | | |
54 | 325 | cm->magic = CMMAGIC; |
55 | 325 | cm->v = v; |
56 | | |
57 | 325 | cm->ncds = NINLINECDS; |
58 | 325 | cm->cd = cm->cdspace; |
59 | 325 | cm->max = 0; |
60 | 325 | cm->free = 0; |
61 | | |
62 | 325 | cd = cm->cd; /* cm->cd[WHITE] */ |
63 | 325 | cd->nschrs = MAX_SIMPLE_CHR - CHR_MIN + 1; |
64 | 325 | cd->nuchrs = 1; |
65 | 325 | cd->sub = NOSUB; |
66 | 325 | cd->arcs = NULL; |
67 | 325 | cd->firstchr = CHR_MIN; |
68 | 325 | cd->flags = 0; |
69 | | |
70 | 325 | cm->locolormap = (color *) |
71 | 325 | MALLOC((MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); |
72 | 325 | if (cm->locolormap == NULL) |
73 | 0 | { |
74 | 0 | CERR(REG_ESPACE); |
75 | 0 | cm->cmranges = NULL; /* prevent failure during freecm */ |
76 | 0 | cm->hicolormap = NULL; |
77 | 0 | return; |
78 | 0 | } |
79 | | /* this memset relies on WHITE being zero: */ |
80 | 325 | memset(cm->locolormap, WHITE, |
81 | 325 | (MAX_SIMPLE_CHR - CHR_MIN + 1) * sizeof(color)); |
82 | | |
83 | 325 | memset(cm->classbits, 0, sizeof(cm->classbits)); |
84 | 325 | cm->numcmranges = 0; |
85 | 325 | cm->cmranges = NULL; |
86 | 325 | cm->maxarrayrows = 4; /* arbitrary initial allocation */ |
87 | 325 | cm->hiarrayrows = 1; /* but we have only one row/col initially */ |
88 | 325 | cm->hiarraycols = 1; |
89 | 325 | cm->hicolormap = (color *) MALLOC(cm->maxarrayrows * sizeof(color)); |
90 | 325 | if (cm->hicolormap == NULL) |
91 | 0 | { |
92 | 0 | CERR(REG_ESPACE); |
93 | 0 | return; |
94 | 0 | } |
95 | | /* initialize the "all other characters" row to WHITE */ |
96 | 325 | cm->hicolormap[0] = WHITE; |
97 | 325 | } |
98 | | |
99 | | /* |
100 | | * freecm - free dynamically-allocated things in a colormap |
101 | | */ |
102 | | static void |
103 | | freecm(struct colormap *cm) |
104 | 43 | { |
105 | 43 | cm->magic = 0; |
106 | 43 | if (cm->cd != cm->cdspace) |
107 | 7 | FREE(cm->cd); |
108 | 43 | if (cm->locolormap != NULL) |
109 | 43 | FREE(cm->locolormap); |
110 | 43 | if (cm->cmranges != NULL) |
111 | 0 | FREE(cm->cmranges); |
112 | 43 | if (cm->hicolormap != NULL) |
113 | 43 | FREE(cm->hicolormap); |
114 | 43 | } |
115 | | |
116 | | /* |
117 | | * pg_reg_getcolor - slow case of GETCOLOR() |
118 | | */ |
119 | | color |
120 | | pg_reg_getcolor(struct colormap *cm, chr c) |
121 | 17 | { |
122 | 17 | int rownum, |
123 | 17 | colnum, |
124 | 17 | low, |
125 | 17 | high; |
126 | | |
127 | | /* Should not be used for chrs in the locolormap */ |
128 | 17 | assert(c > MAX_SIMPLE_CHR); |
129 | | |
130 | | /* |
131 | | * Find which row it's in. The colormapranges are in order, so we can use |
132 | | * binary search. |
133 | | */ |
134 | 17 | rownum = 0; /* if no match, use array row zero */ |
135 | 17 | low = 0; |
136 | 17 | high = cm->numcmranges; |
137 | 17 | while (low < high) |
138 | 0 | { |
139 | 0 | int middle = low + (high - low) / 2; |
140 | 0 | const colormaprange *cmr = &cm->cmranges[middle]; |
141 | |
|
142 | 0 | if (c < cmr->cmin) |
143 | 0 | high = middle; |
144 | 0 | else if (c > cmr->cmax) |
145 | 0 | low = middle + 1; |
146 | 0 | else |
147 | 0 | { |
148 | 0 | rownum = cmr->rownum; /* found a match */ |
149 | 0 | break; |
150 | 0 | } |
151 | 0 | } |
152 | | |
153 | | /* |
154 | | * Find which column it's in --- this is all locale-dependent. |
155 | | */ |
156 | 17 | if (cm->hiarraycols > 1) |
157 | 0 | { |
158 | 0 | colnum = cclass_column_index(cm, c); |
159 | 0 | return cm->hicolormap[rownum * cm->hiarraycols + colnum]; |
160 | 0 | } |
161 | 17 | else |
162 | 17 | { |
163 | | /* fast path if no relevant cclasses */ |
164 | 17 | return cm->hicolormap[rownum]; |
165 | 17 | } |
166 | 17 | } |
167 | | |
168 | | /* |
169 | | * maxcolor - report largest color number in use |
170 | | */ |
171 | | static color |
172 | | maxcolor(struct colormap *cm) |
173 | 1.41k | { |
174 | 1.41k | if (CISERR()) |
175 | 0 | return COLORLESS; |
176 | | |
177 | 1.41k | return (color) cm->max; |
178 | 1.41k | } |
179 | | |
180 | | /* |
181 | | * newcolor - find a new color (must be assigned at once) |
182 | | * Beware: may relocate the colordescs. |
183 | | */ |
184 | | static color /* COLORLESS for error */ |
185 | | newcolor(struct colormap *cm) |
186 | 3.41k | { |
187 | 3.41k | struct colordesc *cd; |
188 | 3.41k | size_t n; |
189 | | |
190 | 3.41k | if (CISERR()) |
191 | 0 | return COLORLESS; |
192 | | |
193 | 3.41k | if (cm->free != 0) |
194 | 39 | { |
195 | 39 | assert(cm->free > 0); |
196 | 39 | assert((size_t) cm->free < cm->ncds); |
197 | 39 | cd = &cm->cd[cm->free]; |
198 | 39 | assert(UNUSEDCOLOR(cd)); |
199 | 39 | assert(cd->arcs == NULL); |
200 | 39 | cm->free = cd->sub; |
201 | 39 | } |
202 | 3.37k | else if (cm->max < cm->ncds - 1) |
203 | 3.17k | { |
204 | 3.17k | cm->max++; |
205 | 3.17k | cd = &cm->cd[cm->max]; |
206 | 3.17k | } |
207 | 200 | else |
208 | 200 | { |
209 | | /* oops, must allocate more */ |
210 | 200 | struct colordesc *newCd; |
211 | | |
212 | 200 | if (cm->max == MAX_COLOR) |
213 | 0 | { |
214 | 0 | CERR(REG_ECOLORS); |
215 | 0 | return COLORLESS; /* too many colors */ |
216 | 0 | } |
217 | | |
218 | 200 | n = cm->ncds * 2; |
219 | 200 | if (n > MAX_COLOR + 1) |
220 | 0 | n = MAX_COLOR + 1; |
221 | 200 | if (cm->cd == cm->cdspace) |
222 | 197 | { |
223 | 197 | newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc)); |
224 | 197 | if (newCd != NULL) |
225 | 197 | memcpy(VS(newCd), VS(cm->cdspace), cm->ncds * |
226 | 197 | sizeof(struct colordesc)); |
227 | 197 | } |
228 | 3 | else |
229 | 3 | newCd = (struct colordesc *) |
230 | 3 | REALLOC(cm->cd, n * sizeof(struct colordesc)); |
231 | 200 | if (newCd == NULL) |
232 | 0 | { |
233 | 0 | CERR(REG_ESPACE); |
234 | 0 | return COLORLESS; |
235 | 0 | } |
236 | 200 | cm->cd = newCd; |
237 | 200 | cm->ncds = n; |
238 | 200 | assert(cm->max < cm->ncds - 1); |
239 | 200 | cm->max++; |
240 | 200 | cd = &cm->cd[cm->max]; |
241 | 200 | } |
242 | | |
243 | 3.41k | cd->nschrs = 0; |
244 | 3.41k | cd->nuchrs = 0; |
245 | 3.41k | cd->sub = NOSUB; |
246 | 3.41k | cd->arcs = NULL; |
247 | 3.41k | cd->firstchr = CHR_MIN; /* in case never set otherwise */ |
248 | 3.41k | cd->flags = 0; |
249 | | |
250 | 3.41k | return (color) (cd - cm->cd); |
251 | 3.41k | } |
252 | | |
253 | | /* |
254 | | * freecolor - free a color (must have no arcs or subcolor) |
255 | | */ |
256 | | static void |
257 | | freecolor(struct colormap *cm, |
258 | | color co) |
259 | 41 | { |
260 | 41 | struct colordesc *cd = &cm->cd[co]; |
261 | 41 | color pco, |
262 | 41 | nco; /* for freelist scan */ |
263 | | |
264 | 41 | assert(co >= 0); |
265 | 41 | if (co == WHITE) |
266 | 0 | return; |
267 | | |
268 | 41 | assert(cd->arcs == NULL); |
269 | 41 | assert(cd->sub == NOSUB); |
270 | 41 | assert(cd->nschrs == 0); |
271 | 41 | assert(cd->nuchrs == 0); |
272 | 41 | cd->flags = FREECOL; |
273 | | |
274 | 41 | if ((size_t) co == cm->max) |
275 | 1 | { |
276 | 3 | while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max])) |
277 | 2 | cm->max--; |
278 | 1 | assert(cm->free >= 0); |
279 | 2 | while (1 (size_t) cm->free > cm->max) |
280 | 1 | cm->free = cm->cd[cm->free].sub; |
281 | 1 | if (cm->free > 0) |
282 | 0 | { |
283 | 0 | assert(cm->free < cm->max); |
284 | 0 | pco = cm->free; |
285 | 0 | nco = cm->cd[pco].sub; |
286 | 0 | while (nco > 0) |
287 | 0 | if ((size_t) nco > cm->max) |
288 | 0 | { |
289 | | /* take this one out of freelist */ |
290 | 0 | nco = cm->cd[nco].sub; |
291 | 0 | cm->cd[pco].sub = nco; |
292 | 0 | } |
293 | 0 | else |
294 | 0 | { |
295 | 0 | assert(nco < cm->max); |
296 | 0 | pco = nco; |
297 | 0 | nco = cm->cd[pco].sub; |
298 | 0 | } |
299 | 0 | } |
300 | 1 | } |
301 | 40 | else |
302 | 40 | { |
303 | 40 | cd->sub = cm->free; |
304 | 40 | cm->free = (color) (cd - cm->cd); |
305 | 40 | } |
306 | 41 | } |
307 | | |
308 | | /* |
309 | | * pseudocolor - allocate a false color, to be managed by other means |
310 | | */ |
311 | | static color |
312 | | pseudocolor(struct colormap *cm) |
313 | 1.29k | { |
314 | 1.29k | color co; |
315 | 1.29k | struct colordesc *cd; |
316 | | |
317 | 1.29k | co = newcolor(cm); |
318 | 1.29k | if (CISERR()) |
319 | 0 | return COLORLESS; |
320 | 1.29k | cd = &cm->cd[co]; |
321 | 1.29k | cd->nschrs = 0; |
322 | 1.29k | cd->nuchrs = 1; /* pretend it is in the upper map */ |
323 | 1.29k | cd->sub = NOSUB; |
324 | 1.29k | cd->arcs = NULL; |
325 | 1.29k | cd->firstchr = CHR_MIN; |
326 | 1.29k | cd->flags = PSEUDO; |
327 | 1.29k | return co; |
328 | 1.29k | } |
329 | | |
330 | | /* |
331 | | * subcolor - allocate a new subcolor (if necessary) to this chr |
332 | | * |
333 | | * This works only for chrs that map into the low color map. |
334 | | */ |
335 | | static color |
336 | | subcolor(struct colormap *cm, chr c) |
337 | 11.7k | { |
338 | 11.7k | color co; /* current color of c */ |
339 | 11.7k | color sco; /* new subcolor */ |
340 | | |
341 | 11.7k | assert(c <= MAX_SIMPLE_CHR); |
342 | | |
343 | 11.7k | co = cm->locolormap[c - CHR_MIN]; |
344 | 11.7k | sco = newsub(cm, co); |
345 | 11.7k | if (CISERR()) |
346 | 0 | return COLORLESS; |
347 | 11.7k | assert(sco != COLORLESS); |
348 | | |
349 | 11.7k | if (co == sco) /* already in an open subcolor */ |
350 | 630 | return co; /* rest is redundant */ |
351 | 11.0k | cm->cd[co].nschrs--; |
352 | 11.0k | if (cm->cd[sco].nschrs == 0) |
353 | 2.11k | cm->cd[sco].firstchr = c; |
354 | 11.0k | cm->cd[sco].nschrs++; |
355 | 11.0k | cm->locolormap[c - CHR_MIN] = sco; |
356 | 11.0k | return sco; |
357 | 11.7k | } |
358 | | |
359 | | /* |
360 | | * subcolorhi - allocate a new subcolor (if necessary) to this colormap entry |
361 | | * |
362 | | * This is the same processing as subcolor(), but for entries in the high |
363 | | * colormap, which do not necessarily correspond to exactly one chr code. |
364 | | */ |
365 | | static color |
366 | | subcolorhi(struct colormap *cm, color *pco) |
367 | 38 | { |
368 | 38 | color co; /* current color of entry */ |
369 | 38 | color sco; /* new subcolor */ |
370 | | |
371 | 38 | co = *pco; |
372 | 38 | sco = newsub(cm, co); |
373 | 38 | if (CISERR()) |
374 | 0 | return COLORLESS; |
375 | 38 | assert(sco != COLORLESS); |
376 | | |
377 | 38 | if (co == sco) /* already in an open subcolor */ |
378 | 0 | return co; /* rest is redundant */ |
379 | 38 | cm->cd[co].nuchrs--; |
380 | 38 | cm->cd[sco].nuchrs++; |
381 | 38 | *pco = sco; |
382 | 38 | return sco; |
383 | 38 | } |
384 | | |
385 | | /* |
386 | | * newsub - allocate a new subcolor (if necessary) for a color |
387 | | */ |
388 | | static color |
389 | | newsub(struct colormap *cm, |
390 | | color co) |
391 | 11.7k | { |
392 | 11.7k | color sco; /* new subcolor */ |
393 | | |
394 | 11.7k | sco = cm->cd[co].sub; |
395 | 11.7k | if (sco == NOSUB) |
396 | 2.74k | { /* color has no open subcolor */ |
397 | | /* optimization: singly-referenced color need not be subcolored */ |
398 | 2.74k | if ((cm->cd[co].nschrs + cm->cd[co].nuchrs) == 1) |
399 | 630 | return co; |
400 | 2.11k | sco = newcolor(cm); /* must create subcolor */ |
401 | 2.11k | if (sco == COLORLESS) |
402 | 0 | { |
403 | 0 | assert(CISERR()); |
404 | 0 | return COLORLESS; |
405 | 0 | } |
406 | 2.11k | cm->cd[co].sub = sco; |
407 | 2.11k | cm->cd[sco].sub = sco; /* open subcolor points to self */ |
408 | 2.11k | } |
409 | 11.1k | assert(sco != NOSUB); |
410 | | |
411 | 11.1k | return sco; |
412 | 11.1k | } |
413 | | |
414 | | /* |
415 | | * newhicolorrow - get a new row in the hicolormap, cloning it from oldrow |
416 | | * |
417 | | * Returns array index of new row. Note the array might move. |
418 | | */ |
419 | | static int |
420 | | newhicolorrow(struct colormap *cm, |
421 | | int oldrow) |
422 | 0 | { |
423 | 0 | int newrow = cm->hiarrayrows; |
424 | 0 | color *newrowptr; |
425 | 0 | int i; |
426 | | |
427 | | /* Assign a fresh array row index, enlarging storage if needed */ |
428 | 0 | if (newrow >= cm->maxarrayrows) |
429 | 0 | { |
430 | 0 | color *newarray; |
431 | |
|
432 | 0 | if (cm->maxarrayrows >= INT_MAX / (cm->hiarraycols * 2)) |
433 | 0 | { |
434 | 0 | CERR(REG_ESPACE); |
435 | 0 | return 0; |
436 | 0 | } |
437 | 0 | newarray = (color *) REALLOC(cm->hicolormap, |
438 | 0 | cm->maxarrayrows * 2 * |
439 | 0 | cm->hiarraycols * sizeof(color)); |
440 | 0 | if (newarray == NULL) |
441 | 0 | { |
442 | 0 | CERR(REG_ESPACE); |
443 | 0 | return 0; |
444 | 0 | } |
445 | 0 | cm->hicolormap = newarray; |
446 | 0 | cm->maxarrayrows *= 2; |
447 | 0 | } |
448 | 0 | cm->hiarrayrows++; |
449 | | |
450 | | /* Copy old row data */ |
451 | 0 | newrowptr = &cm->hicolormap[newrow * cm->hiarraycols]; |
452 | 0 | memcpy(newrowptr, |
453 | 0 | &cm->hicolormap[oldrow * cm->hiarraycols], |
454 | 0 | cm->hiarraycols * sizeof(color)); |
455 | | |
456 | | /* Increase color reference counts to reflect new colormap entries */ |
457 | 0 | for (i = 0; i < cm->hiarraycols; i++) |
458 | 0 | cm->cd[newrowptr[i]].nuchrs++; |
459 | |
|
460 | 0 | return newrow; |
461 | 0 | } |
462 | | |
463 | | /* |
464 | | * newhicolorcols - create a new set of columns in the high colormap |
465 | | * |
466 | | * Essentially, extends the 2-D array to the right with a copy of itself. |
467 | | */ |
468 | | static void |
469 | | newhicolorcols(struct colormap *cm) |
470 | 27 | { |
471 | 27 | color *newarray; |
472 | 27 | int r, |
473 | 27 | c; |
474 | | |
475 | 27 | if (cm->hiarraycols >= INT_MAX / (cm->maxarrayrows * 2)) |
476 | 0 | { |
477 | 0 | CERR(REG_ESPACE); |
478 | 0 | return; |
479 | 0 | } |
480 | 27 | newarray = (color *) REALLOC(cm->hicolormap, |
481 | 27 | cm->maxarrayrows * |
482 | 27 | cm->hiarraycols * 2 * sizeof(color)); |
483 | 27 | if (newarray == NULL) |
484 | 0 | { |
485 | 0 | CERR(REG_ESPACE); |
486 | 0 | return; |
487 | 0 | } |
488 | 27 | cm->hicolormap = newarray; |
489 | | |
490 | | /* Duplicate existing columns to the right, and increase ref counts */ |
491 | | /* Must work backwards in the array because we realloc'd in place */ |
492 | 54 | for (r = cm->hiarrayrows - 1; r >= 0; r--27 ) |
493 | 27 | { |
494 | 27 | color *oldrowptr = &newarray[r * cm->hiarraycols]; |
495 | 27 | color *newrowptr = &newarray[r * cm->hiarraycols * 2]; |
496 | 27 | color *newrowptr2 = newrowptr + cm->hiarraycols; |
497 | | |
498 | 54 | for (c = 0; c < cm->hiarraycols; c++27 ) |
499 | 27 | { |
500 | 27 | color co = oldrowptr[c]; |
501 | | |
502 | 27 | newrowptr[c] = newrowptr2[c] = co; |
503 | 27 | cm->cd[co].nuchrs++; |
504 | 27 | } |
505 | 27 | } |
506 | | |
507 | 27 | cm->hiarraycols *= 2; |
508 | 27 | } |
509 | | |
510 | | /* |
511 | | * subcolorcvec - allocate new subcolors to cvec members, fill in arcs |
512 | | * |
513 | | * For each chr "c" represented by the cvec, do the equivalent of |
514 | | * newarc(v->nfa, PLAIN, subcolor(v->cm, c), lp, rp); |
515 | | * |
516 | | * Note that in typical cases, many of the subcolors are the same. |
517 | | * While newarc() would discard duplicate arc requests, we can save |
518 | | * some cycles by not calling it repetitively to begin with. This is |
519 | | * mechanized with the "lastsubcolor" state variable. |
520 | | */ |
521 | | static void |
522 | | subcolorcvec(struct vars *v, |
523 | | struct cvec *cv, |
524 | | struct state *lp, |
525 | | struct state *rp) |
526 | 344 | { |
527 | 344 | struct colormap *cm = v->cm; |
528 | 344 | color lastsubcolor = COLORLESS; |
529 | 344 | chr ch, |
530 | 344 | from, |
531 | 344 | to; |
532 | 344 | const chr *p; |
533 | 344 | int i; |
534 | | |
535 | | /* ordinary characters */ |
536 | 1.51k | for (p = cv->chrs, i = cv->nchrs; i > 0; p++, i--1.17k ) |
537 | 1.17k | { |
538 | 1.17k | ch = *p; |
539 | 1.17k | subcoloronechr(v, ch, lp, rp, &lastsubcolor); |
540 | 1.17k | NOERR(); |
541 | 1.17k | } |
542 | | |
543 | | /* and the ranges */ |
544 | 583 | for (p = cv->ranges, i = cv->nranges; 344 i > 0; p += 2, i--239 ) |
545 | 239 | { |
546 | 239 | from = *p; |
547 | 239 | to = *(p + 1); |
548 | 239 | if (from <= MAX_SIMPLE_CHR) |
549 | 239 | { |
550 | | /* deal with simple chars one at a time */ |
551 | 239 | chr lim = (to <= MAX_SIMPLE_CHR) ? to : MAX_SIMPLE_CHR0 ; |
552 | | |
553 | 8.40k | while (from <= lim) |
554 | 8.16k | { |
555 | 8.16k | color sco = subcolor(cm, from); |
556 | | |
557 | 8.16k | NOERR(); |
558 | 8.16k | if (sco != lastsubcolor) |
559 | 218 | { |
560 | 218 | newarc(v->nfa, PLAIN, sco, lp, rp); |
561 | 218 | NOERR(); |
562 | 218 | lastsubcolor = sco; |
563 | 218 | } |
564 | 8.16k | from++; |
565 | 8.16k | } |
566 | 239 | } |
567 | | /* deal with any part of the range that's above MAX_SIMPLE_CHR */ |
568 | 239 | if (from < to) |
569 | 0 | subcoloronerange(v, from, to, lp, rp, &lastsubcolor); |
570 | 239 | else if (from == to) |
571 | 0 | subcoloronechr(v, from, lp, rp, &lastsubcolor); |
572 | 239 | NOERR(); |
573 | 239 | } |
574 | | |
575 | | /* and deal with cclass if any */ |
576 | 344 | if (cv->cclasscode >= 0) |
577 | 38 | { |
578 | 38 | int classbit; |
579 | 38 | color *pco; |
580 | 38 | int r, |
581 | 38 | c; |
582 | | |
583 | | /* Enlarge array if we don't have a column bit assignment for cclass */ |
584 | 38 | if (cm->classbits[cv->cclasscode] == 0) |
585 | 27 | { |
586 | 27 | cm->classbits[cv->cclasscode] = cm->hiarraycols; |
587 | 27 | newhicolorcols(cm); |
588 | 27 | NOERR(); |
589 | 27 | } |
590 | | /* Apply subcolorhi() and make arc for each entry in relevant cols */ |
591 | 38 | classbit = cm->classbits[cv->cclasscode]; |
592 | 38 | pco = cm->hicolormap; |
593 | 76 | for (r = 0; r < cm->hiarrayrows; r++38 ) |
594 | 38 | { |
595 | 114 | for (c = 0; c < cm->hiarraycols; c++76 ) |
596 | 76 | { |
597 | 76 | if (c & classbit) |
598 | 38 | { |
599 | 38 | color sco = subcolorhi(cm, pco); |
600 | | |
601 | 38 | NOERR(); |
602 | | /* add the arc if needed */ |
603 | 38 | if (sco != lastsubcolor) |
604 | 0 | { |
605 | 0 | newarc(v->nfa, PLAIN, sco, lp, rp); |
606 | 0 | NOERR(); |
607 | 0 | lastsubcolor = sco; |
608 | 0 | } |
609 | 38 | } |
610 | 76 | pco++; |
611 | 76 | } |
612 | 38 | } |
613 | 38 | } |
614 | 344 | } |
615 | | |
616 | | /* |
617 | | * subcoloronechr - do subcolorcvec's work for a singleton chr |
618 | | * |
619 | | * We could just let subcoloronerange do this, but it's a bit more efficient |
620 | | * if we exploit the single-chr case. Also, callers find it useful for this |
621 | | * to be able to handle both low and high chr codes. |
622 | | */ |
623 | | static void |
624 | | subcoloronechr(struct vars *v, |
625 | | chr ch, |
626 | | struct state *lp, |
627 | | struct state *rp, |
628 | | color *lastsubcolor) |
629 | 3.49k | { |
630 | 3.49k | struct colormap *cm = v->cm; |
631 | 3.49k | colormaprange *newranges; |
632 | 3.49k | int numnewranges; |
633 | 3.49k | colormaprange *oldrange; |
634 | 3.49k | int oldrangen; |
635 | 3.49k | int newrow; |
636 | | |
637 | | /* Easy case for low chr codes */ |
638 | 3.49k | if (ch <= MAX_SIMPLE_CHR) |
639 | 3.49k | { |
640 | 3.49k | color sco = subcolor(cm, ch); |
641 | | |
642 | 3.49k | NOERR(); |
643 | 3.49k | if (sco != *lastsubcolor) |
644 | 2.61k | { |
645 | 2.61k | newarc(v->nfa, PLAIN, sco, lp, rp); |
646 | 2.61k | *lastsubcolor = sco; |
647 | 2.61k | } |
648 | 3.49k | return; |
649 | 3.49k | } |
650 | | |
651 | | /* |
652 | | * Potentially, we could need two more colormapranges than we have now, if |
653 | | * the given chr is in the middle of some existing range. |
654 | | */ |
655 | 0 | newranges = (colormaprange *) |
656 | 0 | MALLOC((cm->numcmranges + 2) * sizeof(colormaprange)); |
657 | 0 | if (newranges == NULL) |
658 | 0 | { |
659 | 0 | CERR(REG_ESPACE); |
660 | 0 | return; |
661 | 0 | } |
662 | 0 | numnewranges = 0; |
663 | | |
664 | | /* Ranges before target are unchanged */ |
665 | 0 | for (oldrange = cm->cmranges, oldrangen = 0; |
666 | 0 | oldrangen < cm->numcmranges; |
667 | 0 | oldrange++, oldrangen++) |
668 | 0 | { |
669 | 0 | if (oldrange->cmax >= ch) |
670 | 0 | break; |
671 | 0 | newranges[numnewranges++] = *oldrange; |
672 | 0 | } |
673 | | |
674 | | /* Match target chr against current range */ |
675 | 0 | if (oldrangen >= cm->numcmranges || oldrange->cmin > ch) |
676 | 0 | { |
677 | | /* chr does not belong to any existing range, make a new one */ |
678 | 0 | newranges[numnewranges].cmin = ch; |
679 | 0 | newranges[numnewranges].cmax = ch; |
680 | | /* row state should be cloned from the "all others" row */ |
681 | 0 | newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); |
682 | 0 | numnewranges++; |
683 | 0 | } |
684 | 0 | else if (oldrange->cmin == oldrange->cmax) |
685 | 0 | { |
686 | | /* we have an existing singleton range matching the chr */ |
687 | 0 | newranges[numnewranges++] = *oldrange; |
688 | 0 | newrow = oldrange->rownum; |
689 | | /* we've now fully processed this old range */ |
690 | 0 | oldrange++, oldrangen++; |
691 | 0 | } |
692 | 0 | else |
693 | 0 | { |
694 | | /* chr is a subset of this existing range, must split it */ |
695 | 0 | if (ch > oldrange->cmin) |
696 | 0 | { |
697 | | /* emit portion of old range before chr */ |
698 | 0 | newranges[numnewranges].cmin = oldrange->cmin; |
699 | 0 | newranges[numnewranges].cmax = ch - 1; |
700 | 0 | newranges[numnewranges].rownum = oldrange->rownum; |
701 | 0 | numnewranges++; |
702 | 0 | } |
703 | | /* emit chr as singleton range, initially cloning from range */ |
704 | 0 | newranges[numnewranges].cmin = ch; |
705 | 0 | newranges[numnewranges].cmax = ch; |
706 | 0 | newranges[numnewranges].rownum = newrow = |
707 | 0 | newhicolorrow(cm, oldrange->rownum); |
708 | 0 | numnewranges++; |
709 | 0 | if (ch < oldrange->cmax) |
710 | 0 | { |
711 | | /* emit portion of old range after chr */ |
712 | 0 | newranges[numnewranges].cmin = ch + 1; |
713 | 0 | newranges[numnewranges].cmax = oldrange->cmax; |
714 | | /* must clone the row if we are making two new ranges from old */ |
715 | 0 | newranges[numnewranges].rownum = |
716 | 0 | (ch > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : |
717 | 0 | oldrange->rownum; |
718 | 0 | numnewranges++; |
719 | 0 | } |
720 | | /* we've now fully processed this old range */ |
721 | 0 | oldrange++, oldrangen++; |
722 | 0 | } |
723 | | |
724 | | /* Update colors in newrow and create arcs as needed */ |
725 | 0 | subcoloronerow(v, newrow, lp, rp, lastsubcolor); |
726 | | |
727 | | /* Ranges after target are unchanged */ |
728 | 0 | for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) |
729 | 0 | { |
730 | 0 | newranges[numnewranges++] = *oldrange; |
731 | 0 | } |
732 | | |
733 | | /* Assert our original space estimate was adequate */ |
734 | 0 | assert(numnewranges <= (cm->numcmranges + 2)); |
735 | | |
736 | | /* And finally, store back the updated list of ranges */ |
737 | 0 | if (cm->cmranges != NULL) |
738 | 0 | FREE(cm->cmranges); |
739 | 0 | cm->cmranges = newranges; |
740 | 0 | cm->numcmranges = numnewranges; |
741 | 0 | } |
742 | | |
743 | | /* |
744 | | * subcoloronerange - do subcolorcvec's work for a high range |
745 | | */ |
746 | | static void |
747 | | subcoloronerange(struct vars *v, |
748 | | chr from, |
749 | | chr to, |
750 | | struct state *lp, |
751 | | struct state *rp, |
752 | | color *lastsubcolor) |
753 | 0 | { |
754 | 0 | struct colormap *cm = v->cm; |
755 | 0 | colormaprange *newranges; |
756 | 0 | int numnewranges; |
757 | 0 | colormaprange *oldrange; |
758 | 0 | int oldrangen; |
759 | 0 | int newrow; |
760 | | |
761 | | /* Caller should take care of non-high-range cases */ |
762 | 0 | assert(from > MAX_SIMPLE_CHR); |
763 | 0 | assert(from < to); |
764 | | |
765 | | /* |
766 | | * Potentially, if we have N non-adjacent ranges, we could need as many as |
767 | | * 2N+1 result ranges (consider case where new range spans 'em all). |
768 | | */ |
769 | 0 | newranges = (colormaprange *) |
770 | 0 | MALLOC((cm->numcmranges * 2 + 1) * sizeof(colormaprange)); |
771 | 0 | if (newranges == NULL) |
772 | 0 | { |
773 | 0 | CERR(REG_ESPACE); |
774 | 0 | return; |
775 | 0 | } |
776 | 0 | numnewranges = 0; |
777 | | |
778 | | /* Ranges before target are unchanged */ |
779 | 0 | for (oldrange = cm->cmranges, oldrangen = 0; |
780 | 0 | oldrangen < cm->numcmranges; |
781 | 0 | oldrange++, oldrangen++) |
782 | 0 | { |
783 | 0 | if (oldrange->cmax >= from) |
784 | 0 | break; |
785 | 0 | newranges[numnewranges++] = *oldrange; |
786 | 0 | } |
787 | | |
788 | | /* |
789 | | * Deal with ranges that (partially) overlap the target. As we process |
790 | | * each such range, increase "from" to remove the dealt-with characters |
791 | | * from the target range. |
792 | | */ |
793 | 0 | while (oldrangen < cm->numcmranges && oldrange->cmin <= to) |
794 | 0 | { |
795 | 0 | if (from < oldrange->cmin) |
796 | 0 | { |
797 | | /* Handle portion of new range that corresponds to no old range */ |
798 | 0 | newranges[numnewranges].cmin = from; |
799 | 0 | newranges[numnewranges].cmax = oldrange->cmin - 1; |
800 | | /* row state should be cloned from the "all others" row */ |
801 | 0 | newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); |
802 | 0 | numnewranges++; |
803 | | /* Update colors in newrow and create arcs as needed */ |
804 | 0 | subcoloronerow(v, newrow, lp, rp, lastsubcolor); |
805 | | /* We've now fully processed the part of new range before old */ |
806 | 0 | from = oldrange->cmin; |
807 | 0 | } |
808 | |
|
809 | 0 | if (from <= oldrange->cmin && to >= oldrange->cmax) |
810 | 0 | { |
811 | | /* old range is fully contained in new, process it in-place */ |
812 | 0 | newranges[numnewranges++] = *oldrange; |
813 | 0 | newrow = oldrange->rownum; |
814 | 0 | from = oldrange->cmax + 1; |
815 | 0 | } |
816 | 0 | else |
817 | 0 | { |
818 | | /* some part of old range does not overlap new range */ |
819 | 0 | if (from > oldrange->cmin) |
820 | 0 | { |
821 | | /* emit portion of old range before new range */ |
822 | 0 | newranges[numnewranges].cmin = oldrange->cmin; |
823 | 0 | newranges[numnewranges].cmax = from - 1; |
824 | 0 | newranges[numnewranges].rownum = oldrange->rownum; |
825 | 0 | numnewranges++; |
826 | 0 | } |
827 | | /* emit common subrange, initially cloning from old range */ |
828 | 0 | newranges[numnewranges].cmin = from; |
829 | 0 | newranges[numnewranges].cmax = |
830 | 0 | (to < oldrange->cmax) ? to : oldrange->cmax; |
831 | 0 | newranges[numnewranges].rownum = newrow = |
832 | 0 | newhicolorrow(cm, oldrange->rownum); |
833 | 0 | numnewranges++; |
834 | 0 | if (to < oldrange->cmax) |
835 | 0 | { |
836 | | /* emit portion of old range after new range */ |
837 | 0 | newranges[numnewranges].cmin = to + 1; |
838 | 0 | newranges[numnewranges].cmax = oldrange->cmax; |
839 | | /* must clone the row if we are making two new ranges from old */ |
840 | 0 | newranges[numnewranges].rownum = |
841 | 0 | (from > oldrange->cmin) ? newhicolorrow(cm, oldrange->rownum) : |
842 | 0 | oldrange->rownum; |
843 | 0 | numnewranges++; |
844 | 0 | } |
845 | 0 | from = oldrange->cmax + 1; |
846 | 0 | } |
847 | | /* Update colors in newrow and create arcs as needed */ |
848 | 0 | subcoloronerow(v, newrow, lp, rp, lastsubcolor); |
849 | | /* we've now fully processed this old range */ |
850 | 0 | oldrange++, oldrangen++; |
851 | 0 | } |
852 | |
|
853 | 0 | if (from <= to) |
854 | 0 | { |
855 | | /* Handle portion of new range that corresponds to no old range */ |
856 | 0 | newranges[numnewranges].cmin = from; |
857 | 0 | newranges[numnewranges].cmax = to; |
858 | | /* row state should be cloned from the "all others" row */ |
859 | 0 | newranges[numnewranges].rownum = newrow = newhicolorrow(cm, 0); |
860 | 0 | numnewranges++; |
861 | | /* Update colors in newrow and create arcs as needed */ |
862 | 0 | subcoloronerow(v, newrow, lp, rp, lastsubcolor); |
863 | 0 | } |
864 | | |
865 | | /* Ranges after target are unchanged */ |
866 | 0 | for (; oldrangen < cm->numcmranges; oldrange++, oldrangen++) |
867 | 0 | { |
868 | 0 | newranges[numnewranges++] = *oldrange; |
869 | 0 | } |
870 | | |
871 | | /* Assert our original space estimate was adequate */ |
872 | 0 | assert(numnewranges <= (cm->numcmranges * 2 + 1)); |
873 | | |
874 | | /* And finally, store back the updated list of ranges */ |
875 | 0 | if (cm->cmranges != NULL) |
876 | 0 | FREE(cm->cmranges); |
877 | 0 | cm->cmranges = newranges; |
878 | 0 | cm->numcmranges = numnewranges; |
879 | 0 | } |
880 | | |
881 | | /* |
882 | | * subcoloronerow - do subcolorcvec's work for one new row in the high colormap |
883 | | */ |
884 | | static void |
885 | | subcoloronerow(struct vars *v, |
886 | | int rownum, |
887 | | struct state *lp, |
888 | | struct state *rp, |
889 | | color *lastsubcolor) |
890 | 0 | { |
891 | 0 | struct colormap *cm = v->cm; |
892 | 0 | color *pco; |
893 | 0 | int i; |
894 | | |
895 | | /* Apply subcolorhi() and make arc for each entry in row */ |
896 | 0 | pco = &cm->hicolormap[rownum * cm->hiarraycols]; |
897 | 0 | for (i = 0; i < cm->hiarraycols; pco++, i++) |
898 | 0 | { |
899 | 0 | color sco = subcolorhi(cm, pco); |
900 | |
|
901 | 0 | NOERR(); |
902 | | /* make the arc if needed */ |
903 | 0 | if (sco != *lastsubcolor) |
904 | 0 | { |
905 | 0 | newarc(v->nfa, PLAIN, sco, lp, rp); |
906 | 0 | NOERR(); |
907 | 0 | *lastsubcolor = sco; |
908 | 0 | } |
909 | 0 | } |
910 | 0 | } |
911 | | |
912 | | /* |
913 | | * okcolors - promote subcolors to full colors |
914 | | */ |
915 | | static void |
916 | | okcolors(struct nfa *nfa, |
917 | | struct colormap *cm) |
918 | 2.64k | { |
919 | 2.64k | struct colordesc *cd; |
920 | 2.64k | struct colordesc *end = CDEND(cm); |
921 | 2.64k | struct colordesc *scd; |
922 | 2.64k | struct arc *a; |
923 | 2.64k | color co; |
924 | 2.64k | color sco; |
925 | | |
926 | 20.0k | for (cd = cm->cd, co = 0; cd < end; cd++, co++17.4k ) |
927 | 17.4k | { |
928 | 17.4k | sco = cd->sub; |
929 | 17.4k | if (UNUSEDCOLOR(cd) || sco == 17.4k NOSUB17.4k ) |
930 | 15.3k | { |
931 | | /* has no subcolor, no further action */ |
932 | 15.3k | } |
933 | 2.12k | else if (sco == co) |
934 | 2 | { |
935 | | /* is subcolor, let parent deal with it */ |
936 | 2 | } |
937 | 2.11k | else if (cd->nschrs == 0 && cd->nuchrs == 042 ) |
938 | 41 | { |
939 | | /* parent empty, its arcs change color to subcolor */ |
940 | 41 | cd->sub = NOSUB; |
941 | 41 | scd = &cm->cd[sco]; |
942 | 41 | assert(scd->nschrs > 0 || scd->nuchrs > 0); |
943 | 41 | assert(scd->sub == sco); |
944 | 41 | scd->sub = NOSUB; |
945 | 173 | while ((a = cd->arcs) != NULL) |
946 | 132 | { |
947 | 132 | assert(a->co == co); |
948 | 132 | uncolorchain(cm, a); |
949 | 132 | a->co = sco; |
950 | 132 | colorchain(cm, a); |
951 | 132 | } |
952 | 41 | freecolor(cm, co); |
953 | 41 | } |
954 | 2.07k | else |
955 | 2.07k | { |
956 | | /* parent's arcs must gain parallel subcolor arcs */ |
957 | 2.07k | cd->sub = NOSUB; |
958 | 2.07k | scd = &cm->cd[sco]; |
959 | 2.07k | assert(scd->nschrs > 0 || scd->nuchrs > 0); |
960 | 2.07k | assert(scd->sub == sco); |
961 | 2.07k | scd->sub = NOSUB; |
962 | 6.84k | for (a = cd->arcs; a != NULL; a = a->colorchain4.76k ) |
963 | 4.76k | { |
964 | 4.76k | assert(a->co == co); |
965 | 4.76k | newarc(nfa, a->type, sco, a->from, a->to); |
966 | 4.76k | } |
967 | 2.07k | } |
968 | 17.4k | } |
969 | 2.64k | } |
970 | | |
971 | | /* |
972 | | * colorchain - add this arc to the color chain of its color |
973 | | */ |
974 | | static void |
975 | | colorchain(struct colormap *cm, |
976 | | struct arc *a) |
977 | 20.7k | { |
978 | 20.7k | struct colordesc *cd = &cm->cd[a->co]; |
979 | | |
980 | 20.7k | if (cd->arcs != NULL) |
981 | 17.3k | cd->arcs->colorchainRev = a; |
982 | 20.7k | a->colorchain = cd->arcs; |
983 | 20.7k | a->colorchainRev = NULL; |
984 | 20.7k | cd->arcs = a; |
985 | 20.7k | } |
986 | | |
987 | | /* |
988 | | * uncolorchain - delete this arc from the color chain of its color |
989 | | */ |
990 | | static void |
991 | | uncolorchain(struct colormap *cm, |
992 | | struct arc *a) |
993 | 11.9k | { |
994 | 11.9k | struct colordesc *cd = &cm->cd[a->co]; |
995 | 11.9k | struct arc *aa = a->colorchainRev; |
996 | | |
997 | 11.9k | if (aa == NULL) |
998 | 2.46k | { |
999 | 2.46k | assert(cd->arcs == a); |
1000 | 2.46k | cd->arcs = a->colorchain; |
1001 | 2.46k | } |
1002 | 9.53k | else |
1003 | 9.53k | { |
1004 | 9.53k | assert(aa->colorchain == a); |
1005 | 9.53k | aa->colorchain = a->colorchain; |
1006 | 9.53k | } |
1007 | 11.9k | if (a->colorchain != NULL) |
1008 | 7.75k | a->colorchain->colorchainRev = aa; |
1009 | 11.9k | a->colorchain = NULL; /* paranoia */ |
1010 | 11.9k | a->colorchainRev = NULL; |
1011 | 11.9k | } |
1012 | | |
1013 | | /* |
1014 | | * rainbow - add arcs of all full colors (but one) between specified states |
1015 | | */ |
1016 | | static void |
1017 | | rainbow(struct nfa *nfa, |
1018 | | struct colormap *cm, |
1019 | | int type, |
1020 | | color but, /* COLORLESS if no exceptions */ |
1021 | | struct state *from, |
1022 | | struct state *to) |
1023 | 3.05k | { |
1024 | 3.05k | struct colordesc *cd; |
1025 | 3.05k | struct colordesc *end = CDEND(cm); |
1026 | 3.05k | color co; |
1027 | | |
1028 | 35.0k | for (cd = cm->cd, co = 0; cd < end && !31.9k CISERR31.9k (); cd++, co++31.9k ) |
1029 | 31.9k | if (!UNUSEDCOLOR(cd) && cd->sub != co && co != but && |
1030 | 31.9k | !(cd->flags & 31.9k PSEUDO31.9k )) |
1031 | 22.5k | newarc(nfa, type, co, from, to); |
1032 | 3.05k | } |
1033 | | |
1034 | | /* |
1035 | | * colorcomplement - add arcs of complementary colors |
1036 | | * |
1037 | | * The calling sequence ought to be reconciled with cloneouts(). |
1038 | | */ |
1039 | | static void |
1040 | | colorcomplement(struct nfa *nfa, |
1041 | | struct colormap *cm, |
1042 | | int type, |
1043 | | struct state *of, /* complements of this guy's PLAIN outarcs */ |
1044 | | struct state *from, |
1045 | | struct state *to) |
1046 | 6 | { |
1047 | 6 | struct colordesc *cd; |
1048 | 6 | struct colordesc *end = CDEND(cm); |
1049 | 6 | color co; |
1050 | | |
1051 | 6 | assert(of != from); |
1052 | 23 | for (cd = cm->cd, co = 0; 6 cd < end && !17 CISERR17 (); cd++, co++17 ) |
1053 | 17 | if (!UNUSEDCOLOR(cd) && !(cd->flags & PSEUDO)) |
1054 | 17 | if (findarc(of, PLAIN, co) == NULL) |
1055 | 11 | newarc(nfa, type, co, from, to); |
1056 | 6 | } |
1057 | | |
1058 | | |
1059 | | #ifdef REG_DEBUG |
1060 | | |
1061 | | /* |
1062 | | * dumpcolors - debugging output |
1063 | | */ |
1064 | | static void |
1065 | | dumpcolors(struct colormap *cm, |
1066 | | FILE *f) |
1067 | | { |
1068 | | struct colordesc *cd; |
1069 | | struct colordesc *end; |
1070 | | color co; |
1071 | | chr c; |
1072 | | |
1073 | | fprintf(f, "max %ld\n", (long) cm->max); |
1074 | | end = CDEND(cm); |
1075 | | for (cd = cm->cd + 1, co = 1; cd < end; cd++, co++) /* skip 0 */ |
1076 | | { |
1077 | | if (!UNUSEDCOLOR(cd)) |
1078 | | { |
1079 | | assert(cd->nschrs > 0 || cd->nuchrs > 0); |
1080 | | if (cd->flags & PSEUDO) |
1081 | | fprintf(f, "#%2ld(ps): ", (long) co); |
1082 | | else |
1083 | | fprintf(f, "#%2ld(%2d): ", (long) co, cd->nschrs + cd->nuchrs); |
1084 | | |
1085 | | /* |
1086 | | * Unfortunately, it's hard to do this next bit more efficiently. |
1087 | | */ |
1088 | | for (c = CHR_MIN; c <= MAX_SIMPLE_CHR; c++) |
1089 | | if (GETCOLOR(cm, c) == co) |
1090 | | dumpchr(c, f); |
1091 | | fprintf(f, "\n"); |
1092 | | } |
1093 | | } |
1094 | | /* dump the high colormap if it contains anything interesting */ |
1095 | | if (cm->hiarrayrows > 1 || cm->hiarraycols > 1) |
1096 | | { |
1097 | | int r, |
1098 | | c; |
1099 | | const color *rowptr; |
1100 | | |
1101 | | fprintf(f, "other:\t"); |
1102 | | for (c = 0; c < cm->hiarraycols; c++) |
1103 | | { |
1104 | | fprintf(f, "\t%ld", (long) cm->hicolormap[c]); |
1105 | | } |
1106 | | fprintf(f, "\n"); |
1107 | | for (r = 0; r < cm->numcmranges; r++) |
1108 | | { |
1109 | | dumpchr(cm->cmranges[r].cmin, f); |
1110 | | fprintf(f, ".."); |
1111 | | dumpchr(cm->cmranges[r].cmax, f); |
1112 | | fprintf(f, ":"); |
1113 | | rowptr = &cm->hicolormap[cm->cmranges[r].rownum * cm->hiarraycols]; |
1114 | | for (c = 0; c < cm->hiarraycols; c++) |
1115 | | { |
1116 | | fprintf(f, "\t%ld", (long) rowptr[c]); |
1117 | | } |
1118 | | fprintf(f, "\n"); |
1119 | | } |
1120 | | } |
1121 | | } |
1122 | | |
1123 | | /* |
1124 | | * dumpchr - print a chr |
1125 | | * |
1126 | | * Kind of char-centric but works well enough for debug use. |
1127 | | */ |
1128 | | static void |
1129 | | dumpchr(chr c, |
1130 | | FILE *f) |
1131 | | { |
1132 | | if (c == '\\') |
1133 | | fprintf(f, "\\\\"); |
1134 | | else if (c > ' ' && c <= '~') |
1135 | | putc((char) c, f); |
1136 | | else |
1137 | | fprintf(f, "\\u%04lx", (long) c); |
1138 | | } |
1139 | | |
1140 | | #endif /* REG_DEBUG */ |