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