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