yacc.y revision 122145
145088Smarkm%{
256585Sobrien/*-
350472Speter * Copyright (c) 1993
445088Smarkm *	The Regents of the University of California.  All rights reserved.
558750Scwt *
658750Scwt * This code is derived from software contributed to Berkeley by
756585Sobrien * Paul Borman at Krystal Technologies.
856585Sobrien *
945088Smarkm * Redistribution and use in source and binary forms, with or without
10130151Sschweikh * modification, are permitted provided that the following conditions
1153685Sobrien * are met:
1253685Sobrien * 1. Redistributions of source code must retain the above copyright
1353685Sobrien *    notice, this list of conditions and the following disclaimer.
1453685Sobrien * 2. Redistributions in binary form must reproduce the above copyright
15130151Sschweikh *    notice, this list of conditions and the following disclaimer in the
1653685Sobrien *    documentation and/or other materials provided with the distribution.
1753685Sobrien * 3. All advertising materials mentioning features or use of this software
1845088Smarkm *    must display the following acknowledgement:
1953685Sobrien *	This product includes software developed by the University of
2045088Smarkm *	California, Berkeley and its contributors.
2145088Smarkm * 4. Neither the name of the University nor the names of its contributors
2245488Smarkm *    may be used to endorse or promote products derived from this software
2345088Smarkm *    without specific prior written permission.
2445088Smarkm *
2545088Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2645088Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27130151Sschweikh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2845088Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2981890Sdwmalone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3081890Sdwmalone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3181890Sdwmalone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3281890Sdwmalone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3381890Sdwmalone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3481890Sdwmalone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3545088Smarkm * SUCH DAMAGE.
3645088Smarkm */
3760031Ssheldonh
3874537Salfred#ifndef lint
39155756Sume#if 0
40155756Sumestatic char sccsid[] = "@(#)yacc.y	8.1 (Berkeley) 6/6/93";
41155756Sume#endif /* 0 */
4260031Ssheldonh#endif /* not lint */
4345088Smarkm
4463515Sume#include <sys/cdefs.h>
4563515Sume__FBSDID("$FreeBSD: head/usr.bin/mklocale/yacc.y 122145 2003-11-05 22:52:51Z davidxu $");
4663515Sume
47133065Sume#include <arpa/inet.h>
48133065Sume
4963515Sume#include <ctype.h>
5045088Smarkm#include <err.h>
5145088Smarkm#include <rune.h>
5245488Smarkm#include <stddef.h>
5345488Smarkm#include <stdio.h>
5445088Smarkm#include <stdlib.h>
5545088Smarkm#include <string.h>
5649394Ssheldonh#include <unistd.h>
5749394Ssheldonh
5849394Ssheldonh#include "ldef.h"
5949394Ssheldonh#include "extern.h"
6049394Ssheldonh
6149394Ssheldonhstatic void *xmalloc(unsigned int sz);
6276030Salexstatic unsigned long *xlalloc(unsigned int sz);
6353685Sobrienvoid yyerror(const char *s);
6474537Salfredstatic unsigned long *xrelalloc(unsigned long *old, unsigned int sz);
6574537Salfredstatic void dump_tables(void);
6674537Salfredstatic void cleanout(void);
6745488Smarkm
6890319Smarkmconst char	*locale_file = "<stdout>";
6990319Smarkm
7090319Smarkmrune_map	maplower = { { 0 }, NULL };
7190319Smarkmrune_map	mapupper = { { 0 }, NULL };
7290319Smarkmrune_map	types = { { 0 }, NULL };
7390319Smarkm
7445088Smarkm_RuneLocale	new_locale = { "", "", NULL, NULL, 0, {}, {}, {},
7545488Smarkm	{0, NULL}, {0, NULL}, {0, NULL}, NULL, 0 };
7645488Smarkm
7745488Smarkmvoid set_map(rune_map *, rune_list *, unsigned long);
7845088Smarkmvoid set_digitmap(rune_map *, rune_list *);
7945088Smarkmvoid add_map(rune_map *, rune_list *, unsigned long);
8045088Smarkmstatic void usage(void);
8145088Smarkm%}
8245088Smarkm
8345088Smarkm%union	{
8445088Smarkm    rune_t	rune;
8545088Smarkm    int		i;
8645088Smarkm    char	*str;
8757284Sjkh
8845088Smarkm    rune_list	*list;
8957284Sjkh}
9045088Smarkm
91%token	<rune>	RUNE
92%token		LBRK
93%token		RBRK
94%token		THRU
95%token		MAPLOWER
96%token		MAPUPPER
97%token		DIGITMAP
98%token	<i>	LIST
99%token	<str>	VARIABLE
100%token		ENCODING
101%token		INVALID
102%token	<str>	STRING
103
104%type	<list>	list
105%type	<list>	map
106
107
108%%
109
110locale	:	/* empty */
111	|	table
112	    	{ dump_tables(); }
113	;
114
115table	:	entry
116	|	table entry
117	;
118
119entry	:	ENCODING STRING
120		{ if (strcmp($2, "NONE") &&
121		      strcmp($2, "UTF2") &&
122		      strcmp($2, "UTF-8") &&
123		      strcmp($2, "EUC") &&
124		      strcmp($2, "GBK") &&
125		      strcmp($2, "GB18030") &&
126		      strcmp($2, "GB2312") &&
127		      strcmp($2, "BIG5") &&
128		      strcmp($2, "MSKanji"))
129			warnx("ENCODING %s is not supported by libc", $2);
130		strncpy(new_locale.encoding, $2, sizeof(new_locale.encoding)); }
131	|	VARIABLE
132		{ new_locale.variable_len = strlen($1) + 1;
133		  new_locale.variable = xmalloc(new_locale.variable_len);
134		  strcpy((char *)new_locale.variable, $1);
135		}
136	|	INVALID RUNE
137		{ warnx("the INVALID keyword is deprecated");
138		  new_locale.invalid_rune = $2;
139		}
140	|	LIST list
141		{ set_map(&types, $2, $1); }
142	|	MAPLOWER map
143		{ set_map(&maplower, $2, 0); }
144	|	MAPUPPER map
145		{ set_map(&mapupper, $2, 0); }
146	|	DIGITMAP map
147		{ set_digitmap(&types, $2); }
148	;
149
150list	:	RUNE
151		{
152		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
153		    $$->min = $1;
154		    $$->max = $1;
155		    $$->next = 0;
156		}
157	|	RUNE THRU RUNE
158		{
159		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
160		    $$->min = $1;
161		    $$->max = $3;
162		    $$->next = 0;
163		}
164	|	list RUNE
165		{
166		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
167		    $$->min = $2;
168		    $$->max = $2;
169		    $$->next = $1;
170		}
171	|	list RUNE THRU RUNE
172		{
173		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
174		    $$->min = $2;
175		    $$->max = $4;
176		    $$->next = $1;
177		}
178	;
179
180map	:	LBRK RUNE RUNE RBRK
181		{
182		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
183		    $$->min = $2;
184		    $$->max = $2;
185		    $$->map = $3;
186		    $$->next = 0;
187		}
188	|	map LBRK RUNE RUNE RBRK
189		{
190		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
191		    $$->min = $3;
192		    $$->max = $3;
193		    $$->map = $4;
194		    $$->next = $1;
195		}
196	|	LBRK RUNE THRU RUNE ':' RUNE RBRK
197		{
198		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
199		    $$->min = $2;
200		    $$->max = $4;
201		    $$->map = $6;
202		    $$->next = 0;
203		}
204	|	map LBRK RUNE THRU RUNE ':' RUNE RBRK
205		{
206		    $$ = (rune_list *)xmalloc(sizeof(rune_list));
207		    $$->min = $3;
208		    $$->max = $5;
209		    $$->map = $7;
210		    $$->next = $1;
211		}
212	;
213%%
214
215int debug;
216FILE *fp;
217
218static void
219cleanout(void)
220{
221    if (fp != NULL)
222	unlink(locale_file);
223}
224
225int
226main(int ac, char *av[])
227{
228    int x;
229
230    fp = stdout;
231
232    while ((x = getopt(ac, av, "do:")) != EOF) {
233	switch(x) {
234	case 'd':
235	    debug = 1;
236	    break;
237	case 'o':
238	    locale_file = optarg;
239	    if ((fp = fopen(locale_file, "w")) == 0)
240		err(1, "%s", locale_file);
241	    atexit(cleanout);
242	    break;
243	default:
244	    usage();
245	}
246    }
247
248    switch (ac - optind) {
249    case 0:
250	break;
251    case 1:
252	if (freopen(av[optind], "r", stdin) == 0)
253	    err(1, "%s", av[optind]);
254	break;
255    default:
256	usage();
257    }
258    for (x = 0; x < _CACHED_RUNES; ++x) {
259	mapupper.map[x] = x;
260	maplower.map[x] = x;
261    }
262    new_locale.invalid_rune = _INVALID_RUNE;
263    memcpy(new_locale.magic, _RUNE_MAGIC_1, sizeof(new_locale.magic));
264
265    yyparse();
266
267    return(0);
268}
269
270static void
271usage()
272{
273    fprintf(stderr, "usage: mklocale [-d] [-o output] [source]\n");
274    exit(1);
275}
276
277void
278yyerror(s)
279	const char *s;
280{
281    fprintf(stderr, "%s\n", s);
282}
283
284static void *
285xmalloc(sz)
286	unsigned int sz;
287{
288    void *r = malloc(sz);
289    if (!r)
290	errx(1, "xmalloc");
291    return(r);
292}
293
294static unsigned long *
295xlalloc(sz)
296	unsigned int sz;
297{
298    unsigned long *r = (unsigned long *)malloc(sz * sizeof(unsigned long));
299    if (!r)
300	errx(1, "xlalloc");
301    return(r);
302}
303
304static unsigned long *
305xrelalloc(old, sz)
306	unsigned long *old;
307	unsigned int sz;
308{
309    unsigned long *r = (unsigned long *)realloc((char *)old,
310						sz * sizeof(unsigned long));
311    if (!r)
312	errx(1, "xrelalloc");
313    return(r);
314}
315
316void
317set_map(map, list, flag)
318	rune_map *map;
319	rune_list *list;
320	unsigned long flag;
321{
322    while (list) {
323	rune_list *nlist = list->next;
324	add_map(map, list, flag);
325	list = nlist;
326    }
327}
328
329void
330set_digitmap(map, list)
331	rune_map *map;
332	rune_list *list;
333{
334    rune_t i;
335
336    while (list) {
337	rune_list *nlist = list->next;
338	for (i = list->min; i <= list->max; ++i) {
339	    if (list->map + (i - list->min)) {
340		rune_list *tmp = (rune_list *)xmalloc(sizeof(rune_list));
341		tmp->min = i;
342		tmp->max = i;
343		add_map(map, tmp, list->map + (i - list->min));
344	    }
345	}
346	free(list);
347	list = nlist;
348    }
349}
350
351void
352add_map(map, list, flag)
353	rune_map *map;
354	rune_list *list;
355	unsigned long flag;
356{
357    rune_t i;
358    rune_list *lr = 0;
359    rune_list *r;
360    rune_t run;
361
362    while (list->min < _CACHED_RUNES && list->min <= list->max) {
363	if (flag)
364	    map->map[list->min++] |= flag;
365	else
366	    map->map[list->min++] = list->map++;
367    }
368
369    if (list->min > list->max) {
370	free(list);
371	return;
372    }
373
374    run = list->max - list->min + 1;
375
376    if (!(r = map->root) || (list->max < r->min - 1)
377			 || (!flag && list->max == r->min - 1)) {
378	if (flag) {
379	    list->types = xlalloc(run);
380	    for (i = 0; i < run; ++i)
381		list->types[i] = flag;
382	}
383	list->next = map->root;
384	map->root = list;
385	return;
386    }
387
388    for (r = map->root; r && r->max + 1 < list->min; r = r->next)
389	lr = r;
390
391    if (!r) {
392	/*
393	 * We are off the end.
394	 */
395	if (flag) {
396	    list->types = xlalloc(run);
397	    for (i = 0; i < run; ++i)
398		list->types[i] = flag;
399	}
400	list->next = 0;
401	lr->next = list;
402	return;
403    }
404
405    if (list->max < r->min - 1) {
406	/*
407	 * We come before this range and we do not intersect it.
408	 * We are not before the root node, it was checked before the loop
409	 */
410	if (flag) {
411	    list->types = xlalloc(run);
412	    for (i = 0; i < run; ++i)
413		list->types[i] = flag;
414	}
415	list->next = lr->next;
416	lr->next = list;
417	return;
418    }
419
420    /*
421     * At this point we have found that we at least intersect with
422     * the range pointed to by `r', we might intersect with one or
423     * more ranges beyond `r' as well.
424     */
425
426    if (!flag && list->map - list->min != r->map - r->min) {
427	/*
428	 * There are only two cases when we are doing case maps and
429	 * our maps needn't have the same offset.  When we are adjoining
430	 * but not intersecting.
431	 */
432	if (list->max + 1 == r->min) {
433	    lr->next = list;
434	    list->next = r;
435	    return;
436	}
437	if (list->min - 1 == r->max) {
438	    list->next = r->next;
439	    r->next = list;
440	    return;
441	}
442	errx(1, "error: conflicting map entries");
443    }
444
445    if (list->min >= r->min && list->max <= r->max) {
446	/*
447	 * Subset case.
448	 */
449
450	if (flag) {
451	    for (i = list->min; i <= list->max; ++i)
452		r->types[i - r->min] |= flag;
453	}
454	free(list);
455	return;
456    }
457    if (list->min <= r->min && list->max >= r->max) {
458	/*
459	 * Superset case.  Make him big enough to hold us.
460	 * We might need to merge with the guy after him.
461	 */
462	if (flag) {
463	    list->types = xlalloc(list->max - list->min + 1);
464
465	    for (i = list->min; i <= list->max; ++i)
466		list->types[i - list->min] = flag;
467
468	    for (i = r->min; i <= r->max; ++i)
469		list->types[i - list->min] |= r->types[i - r->min];
470
471	    free(r->types);
472	    r->types = list->types;
473	} else {
474	    r->map = list->map;
475	}
476	r->min = list->min;
477	r->max = list->max;
478	free(list);
479    } else if (list->min < r->min) {
480	/*
481	 * Our tail intersects his head.
482	 */
483	if (flag) {
484	    list->types = xlalloc(r->max - list->min + 1);
485
486	    for (i = r->min; i <= r->max; ++i)
487		list->types[i - list->min] = r->types[i - r->min];
488
489	    for (i = list->min; i < r->min; ++i)
490		list->types[i - list->min] = flag;
491
492	    for (i = r->min; i <= list->max; ++i)
493		list->types[i - list->min] |= flag;
494
495	    free(r->types);
496	    r->types = list->types;
497	} else {
498	    r->map = list->map;
499	}
500	r->min = list->min;
501	free(list);
502	return;
503    } else {
504	/*
505	 * Our head intersects his tail.
506	 * We might need to merge with the guy after him.
507	 */
508	if (flag) {
509	    r->types = xrelalloc(r->types, list->max - r->min + 1);
510
511	    for (i = list->min; i <= r->max; ++i)
512		r->types[i - r->min] |= flag;
513
514	    for (i = r->max+1; i <= list->max; ++i)
515		r->types[i - r->min] = flag;
516	}
517	r->max = list->max;
518	free(list);
519    }
520
521    /*
522     * Okay, check to see if we grew into the next guy(s)
523     */
524    while ((lr = r->next) && r->max >= lr->min) {
525	if (flag) {
526	    if (r->max >= lr->max) {
527		/*
528		 * Good, we consumed all of him.
529		 */
530		for (i = lr->min; i <= lr->max; ++i)
531		    r->types[i - r->min] |= lr->types[i - lr->min];
532	    } else {
533		/*
534		 * "append" him on to the end of us.
535		 */
536		r->types = xrelalloc(r->types, lr->max - r->min + 1);
537
538		for (i = lr->min; i <= r->max; ++i)
539		    r->types[i - r->min] |= lr->types[i - lr->min];
540
541		for (i = r->max+1; i <= lr->max; ++i)
542		    r->types[i - r->min] = lr->types[i - lr->min];
543
544		r->max = lr->max;
545	    }
546	} else {
547	    if (lr->max > r->max)
548		r->max = lr->max;
549	}
550
551	r->next = lr->next;
552
553	if (flag)
554	    free(lr->types);
555	free(lr);
556    }
557}
558
559static void
560dump_tables()
561{
562    int x, first_d, curr_d;
563    rune_list *list;
564
565    /*
566     * See if we can compress some of the istype arrays
567     */
568    for(list = types.root; list; list = list->next) {
569	list->map = list->types[0];
570	for (x = 1; x < list->max - list->min + 1; ++x) {
571	    if ((rune_t)list->types[x] != list->map) {
572		list->map = 0;
573		break;
574	    }
575	}
576    }
577
578    first_d = curr_d = -1;
579    for (x = 0; x < _CACHED_RUNES; ++x) {
580	unsigned long r = types.map[x];
581
582	if (r & _CTYPE_D) {
583		if (first_d < 0)
584			first_d = curr_d = x;
585		else if (x != curr_d + 1)
586			errx(1, "error: DIGIT range is not contiguous");
587		else if (x - first_d > 9)
588			errx(1, "error: DIGIT range is too big");
589		else
590			curr_d++;
591		if (!(r & _CTYPE_X))
592			errx(1,
593			"error: DIGIT range is not a subset of XDIGIT range");
594	}
595    }
596    if (first_d < 0)
597	errx(1, "error: no DIGIT range defined in the single byte area");
598    else if (curr_d - first_d < 9)
599	errx(1, "error: DIGIT range is too small in the single byte area");
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