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