sed(1): Fix implicit definition of getline error
[dragonfly.git] / usr.bin / mklocale / yacc.y
1 %{
2 /*-
3  * Copyright (c) 1993
4  *      The Regents of the University of California.  All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Paul Borman at Krystal Technologies.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#)yacc.y   8.1 (Berkeley) 6/6/93
34  * $FreeBSD: head/usr.bin/mklocale/yacc.y 216370 2010-12-11 08:32:16Z joel $
35  */
36
37 #include <arpa/inet.h>
38 #include <ctype.h>
39 #include <err.h>
40 #include <stddef.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include "ldef.h"
46 #include "extern.h"
47 #include "runefile.h"
48
49 static void *xmalloc(unsigned int sz);
50 static uint32_t *xlalloc(unsigned int sz);
51 void yyerror(const char *s);
52 static uint32_t *xrelalloc(uint32_t *old, unsigned int sz);
53 static void dump_tables(void);
54 static void cleanout(void);
55
56 const char      *locale_file = "<stdout>";
57
58 rune_map        maplower = { { 0 }, NULL };
59 rune_map        mapupper = { { 0 }, NULL };
60 rune_map        types = { { 0 }, NULL };
61
62 _FileRuneLocale new_locale = { "", "", {}, {}, {}, 0, 0, 0, 0 };
63 char            *variable = NULL;
64
65 void set_map(rune_map *, rune_list *, uint32_t);
66 void set_digitmap(rune_map *, rune_list *);
67 void add_map(rune_map *, rune_list *, uint32_t);
68 static void usage(void);
69 %}
70
71 %union  {
72     int32_t     rune;
73     int         i;
74     char        *str;
75
76     rune_list   *list;
77 }
78
79 %token  <rune>  RUNE
80 %token          LBRK
81 %token          RBRK
82 %token          THRU
83 %token          MAPLOWER
84 %token          MAPUPPER
85 %token          DIGITMAP
86 %token  <i>     LIST
87 %token  <str>   VARIABLE
88 %token          ENCODING
89 %token          INVALID
90 %token  <str>   STRING
91
92 %type   <list>  list
93 %type   <list>  map
94
95
96 %%
97
98 locale  :       /* empty */
99         |       table
100                 { dump_tables(); }
101         ;
102
103 table   :       entry
104         |       table entry
105         ;
106
107 entry   :       ENCODING STRING
108                 { if (strcmp($2, "NONE") &&
109                       strcmp($2, "ASCII") &&
110                       strcmp($2, "UTF-8") &&
111                       strcmp($2, "EUC") &&
112                       strcmp($2, "GBK") &&
113                       strcmp($2, "GB18030") &&
114                       strcmp($2, "GB2312") &&
115                       strcmp($2, "BIG5") &&
116                       strcmp($2, "MSKanji"))
117                         warnx("ENCODING %s is not supported by libc", $2);
118                 strncpy(new_locale.encoding, $2,
119                     sizeof(new_locale.encoding)); }
120         |       VARIABLE
121                 { new_locale.variable_len = strlen($1) + 1;
122                   variable = xmalloc(new_locale.variable_len);
123                   strcpy(variable, $1);
124                 }
125         |       INVALID RUNE
126                 { warnx("the INVALID keyword is deprecated"); }
127         |       LIST list
128                 { set_map(&types, $2, $1); }
129         |       MAPLOWER map
130                 { set_map(&maplower, $2, 0); }
131         |       MAPUPPER map
132                 { set_map(&mapupper, $2, 0); }
133         |       DIGITMAP map
134                 { set_digitmap(&types, $2); }
135         ;
136
137 list    :       RUNE
138                 {
139                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
140                     $$->min = $1;
141                     $$->max = $1;
142                     $$->next = 0;
143                 }
144         |       RUNE THRU RUNE
145                 {
146                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
147                     $$->min = $1;
148                     $$->max = $3;
149                     $$->next = 0;
150                 }
151         |       list RUNE
152                 {
153                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
154                     $$->min = $2;
155                     $$->max = $2;
156                     $$->next = $1;
157                 }
158         |       list RUNE THRU RUNE
159                 {
160                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
161                     $$->min = $2;
162                     $$->max = $4;
163                     $$->next = $1;
164                 }
165         ;
166
167 map     :       LBRK RUNE RUNE RBRK
168                 {
169                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
170                     $$->min = $2;
171                     $$->max = $2;
172                     $$->map = $3;
173                     $$->next = 0;
174                 }
175         |       map LBRK RUNE RUNE RBRK
176                 {
177                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
178                     $$->min = $3;
179                     $$->max = $3;
180                     $$->map = $4;
181                     $$->next = $1;
182                 }
183         |       LBRK RUNE THRU RUNE ':' RUNE RBRK
184                 {
185                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
186                     $$->min = $2;
187                     $$->max = $4;
188                     $$->map = $6;
189                     $$->next = 0;
190                 }
191         |       map LBRK RUNE THRU RUNE ':' RUNE RBRK
192                 {
193                     $$ = (rune_list *)xmalloc(sizeof(rune_list));
194                     $$->min = $3;
195                     $$->max = $5;
196                     $$->map = $7;
197                     $$->next = $1;
198                 }
199         ;
200 %%
201
202 int debug;
203 FILE *fp;
204
205 static void
206 cleanout(void)
207 {
208     if (fp != NULL)
209         unlink(locale_file);
210 }
211
212 int
213 main(int ac, char *av[])
214 {
215     int x;
216
217     fp = stdout;
218
219     while ((x = getopt(ac, av, "do:")) != -1) {
220         switch(x) {
221         case 'd':
222             debug = 1;
223             break;
224         case 'o':
225             locale_file = optarg;
226             if ((fp = fopen(locale_file, "w")) == NULL)
227                 err(1, "%s", locale_file);
228             atexit(cleanout);
229             break;
230         default:
231             usage();
232         }
233     }
234
235     switch (ac - optind) {
236     case 0:
237         break;
238     case 1:
239         if (freopen(av[optind], "r", stdin) == 0)
240             err(1, "%s", av[optind]);
241         break;
242     default:
243         usage();
244     }
245     for (x = 0; x < _CACHED_RUNES; ++x) {
246         mapupper.map[x] = x;
247         maplower.map[x] = x;
248     }
249     memcpy(new_locale.magic, _FILE_RUNE_MAGIC_1, sizeof(new_locale.magic));
250
251     yyparse();
252
253     return(0);
254 }
255
256 static void
257 usage(void)
258 {
259     fprintf(stderr, "usage: mklocale [-d] [-o output] [source]\n");
260     exit(1);
261 }
262
263 void
264 yyerror(const char *s)
265 {
266     fprintf(stderr, "%s\n", s);
267 }
268
269 static void *
270 xmalloc(unsigned int sz)
271 {
272     void *r = malloc(sz);
273     if (!r)
274         errx(1, "xmalloc");
275     return(r);
276 }
277
278 static uint32_t *
279 xlalloc(unsigned int sz)
280 {
281     uint32_t *r = (uint32_t *)malloc(sz * sizeof(uint32_t));
282     if (!r)
283         errx(1, "xlalloc");
284     return(r);
285 }
286
287 static uint32_t *
288 xrelalloc(uint32_t *old, unsigned int sz)
289 {
290     uint32_t *r = (uint32_t *)realloc((char *)old,
291                                                 sz * sizeof(uint32_t));
292     if (!r)
293         errx(1, "xrelalloc");
294     return(r);
295 }
296
297 void
298 set_map(rune_map *map, rune_list *list, uint32_t flag)
299 {
300     while (list) {
301         rune_list *nlist = list->next;
302         add_map(map, list, flag);
303         list = nlist;
304     }
305 }
306
307 void
308 set_digitmap(rune_map *map, rune_list *list)
309 {
310     int32_t i;
311
312     while (list) {
313         rune_list *nlist = list->next;
314         for (i = list->min; i <= list->max; ++i) {
315             if (list->map + (i - list->min)) {
316                 rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
317                 tmp->min = i;
318                 tmp->max = i;
319                 add_map(map, tmp, list->map + (i - list->min));
320             }
321         }
322         free(list);
323         list = nlist;
324     }
325 }
326
327 void
328 add_map(rune_map *map, rune_list *list, uint32_t flag)
329 {
330     int32_t i;
331     rune_list *lr = 0;
332     rune_list *r;
333     int32_t run;
334
335     while (list->min < _CACHED_RUNES && list->min <= list->max) {
336         if (flag)
337             map->map[list->min++] |= flag;
338         else
339             map->map[list->min++] = list->map++;
340     }
341
342     if (list->min > list->max) {
343         free(list);
344         return;
345     }
346
347     run = list->max - list->min + 1;
348
349     if (!(r = map->root) || (list->max < r->min - 1)
350                          || (!flag && list->max == r->min - 1)) {
351         if (flag) {
352             list->types = xlalloc(run);
353             for (i = 0; i < run; ++i)
354                 list->types[i] = flag;
355         }
356         list->next = map->root;
357         map->root = list;
358         return;
359     }
360
361     for (r = map->root; r && r->max + 1 < list->min; r = r->next)
362         lr = r;
363
364     if (!r) {
365         /*
366          * We are off the end.
367          */
368         if (flag) {
369             list->types = xlalloc(run);
370             for (i = 0; i < run; ++i)
371                 list->types[i] = flag;
372         }
373         list->next = 0;
374         lr->next = list;
375         return;
376     }
377
378     if (list->max < r->min - 1) {
379         /*
380          * We come before this range and we do not intersect it.
381          * We are not before the root node, it was checked before the loop
382          */
383         if (flag) {
384             list->types = xlalloc(run);
385             for (i = 0; i < run; ++i)
386                 list->types[i] = flag;
387         }
388         list->next = lr->next;
389         lr->next = list;
390         return;
391     }
392
393     /*
394      * At this point we have found that we at least intersect with
395      * the range pointed to by `r', we might intersect with one or
396      * more ranges beyond `r' as well.
397      */
398
399     if (!flag && list->map - list->min != r->map - r->min) {
400         /*
401          * There are only two cases when we are doing case maps and
402          * our maps needn't have the same offset.  When we are adjoining
403          * but not intersecting.
404          */
405         if (list->max + 1 == r->min) {
406             lr->next = list;
407             list->next = r;
408             return;
409         }
410         if (list->min - 1 == r->max) {
411             list->next = r->next;
412             r->next = list;
413             return;
414         }
415         errx(1, "error: conflicting map entries");
416     }
417
418     if (list->min >= r->min && list->max <= r->max) {
419         /*
420          * Subset case.
421          */
422
423         if (flag) {
424             for (i = list->min; i <= list->max; ++i)
425                 r->types[i - r->min] |= flag;
426         }
427         free(list);
428         return;
429     }
430     if (list->min <= r->min && list->max >= r->max) {
431         /*
432          * Superset case.  Make him big enough to hold us.
433          * We might need to merge with the guy after him.
434          */
435         if (flag) {
436             list->types = xlalloc(list->max - list->min + 1);
437
438             for (i = list->min; i <= list->max; ++i)
439                 list->types[i - list->min] = flag;
440
441             for (i = r->min; i <= r->max; ++i)
442                 list->types[i - list->min] |= r->types[i - r->min];
443
444             free(r->types);
445             r->types = list->types;
446         } else {
447             r->map = list->map;
448         }
449         r->min = list->min;
450         r->max = list->max;
451         free(list);
452     } else if (list->min < r->min) {
453         /*
454          * Our tail intersects his head.
455          */
456         if (flag) {
457             list->types = xlalloc(r->max - list->min + 1);
458
459             for (i = r->min; i <= r->max; ++i)
460                 list->types[i - list->min] = r->types[i - r->min];
461
462             for (i = list->min; i < r->min; ++i)
463                 list->types[i - list->min] = flag;
464
465             for (i = r->min; i <= list->max; ++i)
466                 list->types[i - list->min] |= flag;
467
468             free(r->types);
469             r->types = list->types;
470         } else {
471             r->map = list->map;
472         }
473         r->min = list->min;
474         free(list);
475         return;
476     } else {
477         /*
478          * Our head intersects his tail.
479          * We might need to merge with the guy after him.
480          */
481         if (flag) {
482             r->types = xrelalloc(r->types, list->max - r->min + 1);
483
484             for (i = list->min; i <= r->max; ++i)
485                 r->types[i - r->min] |= flag;
486
487             for (i = r->max+1; i <= list->max; ++i)
488                 r->types[i - r->min] = flag;
489         }
490         r->max = list->max;
491         free(list);
492     }
493
494     /*
495      * Okay, check to see if we grew into the next guy(s)
496      */
497     while ((lr = r->next) && r->max >= lr->min) {
498         if (flag) {
499             if (r->max >= lr->max) {
500                 /*
501                  * Good, we consumed all of him.
502                  */
503                 for (i = lr->min; i <= lr->max; ++i)
504                     r->types[i - r->min] |= lr->types[i - lr->min];
505             } else {
506                 /*
507                  * "append" him on to the end of us.
508                  */
509                 r->types = xrelalloc(r->types, lr->max - r->min + 1);
510
511                 for (i = lr->min; i <= r->max; ++i)
512                     r->types[i - r->min] |= lr->types[i - lr->min];
513
514                 for (i = r->max+1; i <= lr->max; ++i)
515                     r->types[i - r->min] = lr->types[i - lr->min];
516
517                 r->max = lr->max;
518             }
519         } else {
520             if (lr->max > r->max)
521                 r->max = lr->max;
522         }
523
524         r->next = lr->next;
525
526         if (flag)
527             free(lr->types);
528         free(lr);
529     }
530 }
531
532 static void
533 dump_tables(void)
534 {
535     int x, first_d, curr_d;
536     rune_list *list;
537
538     /*
539      * See if we can compress some of the istype arrays
540      */
541     for(list = types.root; list; list = list->next) {
542         list->map = list->types[0];
543         for (x = 1; x < list->max - list->min + 1; ++x) {
544             if ((int32_t)list->types[x] != list->map) {
545                 list->map = 0;
546                 break;
547             }
548         }
549     }
550
551     first_d = curr_d = -1;
552     for (x = 0; x < _CACHED_RUNES; ++x) {
553         uint32_t r = types.map[x];
554
555         if (r & _CTYPE_D) {
556                 if (first_d < 0)
557                         first_d = curr_d = x;
558                 else if (x != curr_d + 1)
559                         errx(1, "error: DIGIT range is not contiguous");
560                 else if (x - first_d > 9)
561                         errx(1, "error: DIGIT range is too big");
562                 else
563                         curr_d++;
564                 if (!(r & _CTYPE_X))
565                         errx(1,
566                         "error: DIGIT range is not a subset of XDIGIT range");
567         }
568     }
569     if (first_d < 0)
570         errx(1, "error: no DIGIT range defined in the single byte area");
571     else if (curr_d - first_d < 9)
572         errx(1, "error: DIGIT range is too small in the single byte area");
573
574     /*
575      * Fill in our tables.  Do this in network order so that
576      * diverse machines have a chance of sharing data.
577      * (Machines like Crays cannot share with little machines due to
578      *  word size.  Sigh.  We tried.)
579      */
580     for (x = 0; x < _CACHED_RUNES; ++x) {
581         new_locale.runetype[x] = htonl(types.map[x]);
582         new_locale.maplower[x] = htonl(maplower.map[x]);
583         new_locale.mapupper[x] = htonl(mapupper.map[x]);
584     }
585
586     /*
587      * Count up how many ranges we will need for each of the extents.
588      */
589     list = types.root;
590
591     while (list) {
592         new_locale.runetype_ext_nranges++;
593         list = list->next;
594     }
595     new_locale.runetype_ext_nranges =
596          htonl(new_locale.runetype_ext_nranges);
597
598     list = maplower.root;
599
600     while (list) {
601         new_locale.maplower_ext_nranges++;
602         list = list->next;
603     }
604     new_locale.maplower_ext_nranges =
605         htonl(new_locale.maplower_ext_nranges);
606
607     list = mapupper.root;
608
609     while (list) {
610         new_locale.mapupper_ext_nranges++;
611         list = list->next;
612     }
613     new_locale.mapupper_ext_nranges =
614         htonl(new_locale.mapupper_ext_nranges);
615
616     new_locale.variable_len = htonl(new_locale.variable_len);
617
618     /*
619      * Okay, we are now ready to write the new locale file.
620      */
621
622     /*
623      * PART 1: The _FileRuneLocale structure
624      */
625     if (fwrite((char *)&new_locale, sizeof(new_locale), 1, fp) != 1) {
626         perror(locale_file);
627         exit(1);
628     }
629     /*
630      * PART 2: The runetype_ext structures (not the actual tables)
631      */
632     list = types.root;
633
634     while (list) {
635         _FileRuneEntry re;
636
637         re.min = htonl(list->min);
638         re.max = htonl(list->max);
639         re.map = htonl(list->map);
640
641         if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
642             perror(locale_file);
643             exit(1);
644         }
645
646         list = list->next;
647     }
648     /*
649      * PART 3: The maplower_ext structures
650      */
651     list = maplower.root;
652
653     while (list) {
654         _FileRuneEntry re;
655
656         re.min = htonl(list->min);
657         re.max = htonl(list->max);
658         re.map = htonl(list->map);
659
660         if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
661             perror(locale_file);
662             exit(1);
663         }
664
665         list = list->next;
666     }
667     /*
668      * PART 4: The mapupper_ext structures
669      */
670     list = mapupper.root;
671
672     while (list) {
673         _FileRuneEntry re;
674
675         re.min = htonl(list->min);
676         re.max = htonl(list->max);
677         re.map = htonl(list->map);
678
679         if (fwrite((char *)&re, sizeof(re), 1, fp) != 1) {
680             perror(locale_file);
681             exit(1);
682         }
683
684         list = list->next;
685     }
686     /*
687      * PART 5: The runetype_ext tables
688      */
689     list = types.root;
690
691     while (list) {
692         for (x = 0; x < list->max - list->min + 1; ++x)
693             list->types[x] = htonl(list->types[x]);
694
695         if (!list->map) {
696             if (fwrite((char *)list->types,
697                        (list->max - list->min + 1) * sizeof(uint32_t),
698                        1, fp) != 1) {
699                 perror(locale_file);
700                 exit(1);
701             }
702         }
703         list = list->next;
704     }
705     /*
706      * PART 6: And finally the variable data
707      */
708     if (new_locale.variable_len != 0 &&
709         fwrite(variable, ntohl(new_locale.variable_len), 1, fp) != 1) {
710         perror(locale_file);
711         exit(1);
712     }
713     if (fclose(fp) != 0) {
714         perror(locale_file);
715         exit(1);
716     }
717     fp = NULL;
718
719     if (!debug)
720         return;
721
722     if (new_locale.encoding[0])
723         fprintf(stderr, "ENCODING       %s\n", new_locale.encoding);
724     if (variable)
725         fprintf(stderr, "VARIABLE       %s\n", variable);
726
727     fprintf(stderr, "\nMAPLOWER:\n\n");
728
729     for (x = 0; x < _CACHED_RUNES; ++x) {
730         if (isprint(maplower.map[x]))
731             fprintf(stderr, " '%c'", (int)maplower.map[x]);
732         else if (maplower.map[x])
733             fprintf(stderr, "%04x", maplower.map[x]);
734         else
735             fprintf(stderr, "%4x", 0);
736         if ((x & 0xf) == 0xf)
737             fprintf(stderr, "\n");
738         else
739             fprintf(stderr, " ");
740     }
741     fprintf(stderr, "\n");
742
743     for (list = maplower.root; list; list = list->next)
744         fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
745
746     fprintf(stderr, "\nMAPUPPER:\n\n");
747
748     for (x = 0; x < _CACHED_RUNES; ++x) {
749         if (isprint(mapupper.map[x]))
750             fprintf(stderr, " '%c'", (int)mapupper.map[x]);
751         else if (mapupper.map[x])
752             fprintf(stderr, "%04x", mapupper.map[x]);
753         else
754             fprintf(stderr, "%4x", 0);
755         if ((x & 0xf) == 0xf)
756             fprintf(stderr, "\n");
757         else
758             fprintf(stderr, " ");
759     }
760     fprintf(stderr, "\n");
761
762     for (list = mapupper.root; list; list = list->next)
763         fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
764
765
766     fprintf(stderr, "\nTYPES:\n\n");
767
768     for (x = 0; x < _CACHED_RUNES; ++x) {
769         uint32_t r = types.map[x];
770
771         if (r) {
772             if (isprint(x))
773                 fprintf(stderr, " '%c': %2d", x, (int)(r & 0xff));
774             else
775                 fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
776
777             fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
778             fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
779             fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
780             fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
781             fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
782             fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
783             fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
784             fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
785             fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
786             fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
787             fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
788             fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
789             fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
790             fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
791             fprintf(stderr, "\n");
792         }
793     }
794
795     for (list = types.root; list; list = list->next) {
796         if (list->map && list->min + 3 < list->max) {
797             uint32_t r = list->map;
798
799             fprintf(stderr, "%04x: %2d",
800                 (uint32_t)list->min, (int)(r & 0xff));
801
802             fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
803             fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
804             fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
805             fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
806             fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
807             fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
808             fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
809             fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
810             fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
811             fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
812             fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
813             fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
814             fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
815             fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
816             fprintf(stderr, "\n...\n");
817
818             fprintf(stderr, "%04x: %2d",
819                 (uint32_t)list->max, (int)(r & 0xff));
820
821             fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
822             fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
823             fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
824             fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
825             fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
826             fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
827             fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
828             fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
829             fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
830             fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
831             fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
832             fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
833             fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
834             fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
835             fprintf(stderr, "\n");
836         } else 
837         for (x = list->min; x <= list->max; ++x) {
838             uint32_t r = ntohl(list->types[x - list->min]);
839
840             if (r) {
841                 fprintf(stderr, "%04x: %2d", x, (int)(r & 0xff));
842
843                 fprintf(stderr, " %4s", (r & _CTYPE_A) ? "alph" : "");
844                 fprintf(stderr, " %4s", (r & _CTYPE_C) ? "ctrl" : "");
845                 fprintf(stderr, " %4s", (r & _CTYPE_D) ? "dig" : "");
846                 fprintf(stderr, " %4s", (r & _CTYPE_G) ? "graf" : "");
847                 fprintf(stderr, " %4s", (r & _CTYPE_L) ? "low" : "");
848                 fprintf(stderr, " %4s", (r & _CTYPE_P) ? "punc" : "");
849                 fprintf(stderr, " %4s", (r & _CTYPE_S) ? "spac" : "");
850                 fprintf(stderr, " %4s", (r & _CTYPE_U) ? "upp" : "");
851                 fprintf(stderr, " %4s", (r & _CTYPE_X) ? "xdig" : "");
852                 fprintf(stderr, " %4s", (r & _CTYPE_B) ? "blnk" : "");
853                 fprintf(stderr, " %4s", (r & _CTYPE_R) ? "prnt" : "");
854                 fprintf(stderr, " %4s", (r & _CTYPE_I) ? "ideo" : "");
855                 fprintf(stderr, " %4s", (r & _CTYPE_T) ? "spec" : "");
856                 fprintf(stderr, " %4s", (r & _CTYPE_Q) ? "phon" : "");
857                 fprintf(stderr, "\n");
858             }
859         }
860     }
861 }