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