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