xref: /openbsd/usr.bin/mklocale/yacc.y (revision 4efe9bde)
1 /*	$OpenBSD: yacc.y,v 1.10 2016/05/08 15:25:44 schwarze Exp $	*/
2 /*	$NetBSD: yacc.y,v 1.24 2004/01/05 23:23:36 jmmv Exp $	*/
3 
4 %{
5 /*-
6  * Copyright (c) 1993
7  *	The Regents of the University of California.  All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Paul Borman at Krystal Technologies.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #include <sys/types.h>
38 #include <netinet/in.h>	/* Needed by <arpa/inet.h> on NetBSD 1.5. */
39 #include <arpa/inet.h>	/* Needed for htonl on POSIX systems. */
40 
41 #include <err.h>
42 #include "locale/runetype.h"
43 #include <stddef.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <ctype.h>
49 
50 #include "ldef.h"
51 
52 const char	*locale_file = "<stdout>";
53 
54 rune_map	maplower = { { 0, }, };
55 rune_map	mapupper = { { 0, }, };
56 rune_map	types = { { 0, }, };
57 
58 _RuneLocale	new_locale = { { 0, }, };
59 
60 rune_t	charsetbits = (rune_t)0x00000000;
61 #if 0
62 rune_t	charsetmask = (rune_t)0x0000007f;
63 #endif
64 rune_t	charsetmask = (rune_t)0xffffffff;
65 
66 void set_map(rune_map *, rune_list *, u_int32_t);
67 void add_map(rune_map *, rune_list *, u_int32_t);
68 
69 int		main(int, char *[]);
70 int		yyerror(const char *s);
71 void		*xmalloc(size_t sz);
72 u_int32_t	*xlalloc(size_t sz);
73 u_int32_t	*xrelalloc(u_int32_t *old, size_t sz);
74 void		dump_tables(void);
75 int		yyparse(void);
76 extern int	yylex(void);
77 %}
78 
79 %union	{
80     rune_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		CHARSET
97 %token		ENCODING
98 %token		INVALID
99 %token	<str>	STRING
100 
101 %type	<list>	list
102 %type	<list>	map
103 
104 
105 %%
106 
107 locale	:	/* empty */
108 	|	table
109 	    	{ dump_tables(); }
110 	;
111 
112 table	:	entry
113 	|	table entry
114 	;
115 
116 entry	:	ENCODING STRING
117 		{ strncpy(new_locale.rl_encoding, $2, sizeof(new_locale.rl_encoding)); }
118 	|	VARIABLE
119 		{ new_locale.rl_variable_len = strlen($1) + 1;
120 		  new_locale.rl_variable = strdup($1);
121 		}
122 	|	CHARSET RUNE
123 		{ charsetbits = $2; charsetmask = 0x0000007f; }
124 	|	CHARSET RUNE RUNE
125 		{ charsetbits = $2; charsetmask = $3; }
126 	|	CHARSET STRING
127 		{ int final = $2[strlen($2) - 1] & 0x7f;
128 		  charsetbits = final << 24;
129 		  if ($2[0] == '$') {
130 			charsetmask = 0x00007f7f;
131 			if (strchr(",-./", $2[1]))
132 				charsetbits |= 0x80;
133 			if (0xd0 <= final && final <= 0xdf)
134 				charsetmask |= 0x007f0000;
135 		  } else {
136 			charsetmask = 0x0000007f;
137 			if (strchr(",-./", $2[0]))
138 				charsetbits |= 0x80;
139 			if (strlen($2) == 2 && $2[0] == '!')
140 				charsetbits |= ((0x80 | $2[0]) << 16);
141 		  }
142 
143 		  /*
144 		   * special rules
145 		   */
146 		  if (charsetbits == ('B' << 24)
147 		   && charsetmask == 0x0000007f) {
148 			/*ASCII: 94B*/
149 			charsetbits = 0;
150 			charsetmask = 0x0000007f;
151 		  } else if (charsetbits == (('A' << 24) | 0x80)
152 		  	  && charsetmask == 0x0000007f) {
153 		  	/*Latin1: 96A*/
154 			charsetbits = 0x80;
155 			charsetmask = 0x0000007f;
156 		  }
157 		}
158 	|	INVALID RUNE
159 		{ new_locale.rl_invalid_rune = $2; }
160 	|	LIST list
161 		{ set_map(&types, $2, $1); }
162 	|	MAPLOWER map
163 		{ set_map(&maplower, $2, 0); }
164 	|	MAPUPPER map
165 		{ set_map(&mapupper, $2, 0); }
166 	|	DIGITMAP mapignore
167 		{ }
168 	;
169 
170 list	:	RUNE
171 		{
172 		    $$ = xmalloc(sizeof(rune_list));
173 		    $$->min = ($1 & charsetmask) | charsetbits;
174 		    $$->max = ($1 & charsetmask) | charsetbits;
175 		    $$->map = 0;
176 		    $$->next = 0;
177 		}
178 	|	RUNE THRU RUNE
179 		{
180 		    $$ = xmalloc(sizeof(rune_list));
181 		    $$->min = ($1 & charsetmask) | charsetbits;
182 		    $$->max = ($3 & charsetmask) | charsetbits;
183 		    $$->map = 0;
184 		    $$->next = 0;
185 		}
186 	|	list RUNE
187 		{
188 		    $$ = xmalloc(sizeof(rune_list));
189 		    $$->min = ($2 & charsetmask) | charsetbits;
190 		    $$->max = ($2 & charsetmask) | charsetbits;
191 		    $$->map = 0;
192 		    $$->next = $1;
193 		}
194 	|	list RUNE THRU RUNE
195 		{
196 		    $$ = xmalloc(sizeof(rune_list));
197 		    $$->min = ($2 & charsetmask) | charsetbits;
198 		    $$->max = ($4 & charsetmask) | charsetbits;
199 		    $$->map = 0;
200 		    $$->next = $1;
201 		}
202 	;
203 
204 map	:	LBRK RUNE RUNE RBRK
205 		{
206 		    $$ = xmalloc(sizeof(rune_list));
207 		    $$->min = ($2 & charsetmask) | charsetbits;
208 		    $$->max = ($2 & charsetmask) | charsetbits;
209 		    $$->map = $3;
210 		    $$->next = 0;
211 		}
212 	|	map LBRK RUNE RUNE RBRK
213 		{
214 		    $$ = xmalloc(sizeof(rune_list));
215 		    $$->min = ($3 & charsetmask) | charsetbits;
216 		    $$->max = ($3 & charsetmask) | charsetbits;
217 		    $$->map = $4;
218 		    $$->next = $1;
219 		}
220 	|	LBRK RUNE THRU RUNE ':' RUNE RBRK
221 		{
222 		    $$ = xmalloc(sizeof(rune_list));
223 		    $$->min = ($2 & charsetmask) | charsetbits;
224 		    $$->max = ($4 & charsetmask) | charsetbits;
225 		    $$->map = $6;
226 		    $$->next = 0;
227 		}
228 	|	map LBRK RUNE THRU RUNE ':' RUNE RBRK
229 		{
230 		    $$ = xmalloc(sizeof(rune_list));
231 		    $$->min = ($3 & charsetmask) | charsetbits;
232 		    $$->max = ($5 & charsetmask) | charsetbits;
233 		    $$->map = $7;
234 		    $$->next = $1;
235 		}
236 	;
237 
238 mapignore :	LBRK RUNE RUNE RBRK { }
239 	|	map LBRK RUNE RUNE RBRK { }
240 	|	LBRK RUNE THRU RUNE ':' RUNE RBRK { }
241 	|	map LBRK RUNE THRU RUNE ':' RUNE RBRK { }
242 	;
243 %%
244 
245 int debug = 0;
246 FILE *ofile;
247 
248 int
main(int ac,char * av[])249 main(int ac, char *av[])
250 {
251     int x;
252 
253     extern char *optarg;
254     extern int optind;
255 
256     if (pledge("stdio rpath wpath cpath", NULL) == -1) {
257 	perror("pledge");
258 	exit(1);
259     }
260 
261     while ((x = getopt(ac, av, "do:")) != -1) {
262 	switch(x) {
263 	case 'd':
264 	    debug = 1;
265 	    break;
266 	case 'o':
267 	    locale_file = optarg;
268 	    if ((ofile = fopen(locale_file, "w")) == 0)
269 		err(1, "unable to open output file %s", locale_file);
270 	    break;
271 	default:
272 	usage:
273 	    fprintf(stderr,
274 		"usage: mklocale [-d] [src-file] language/LC_CTYPE\n"
275 		"       mklocale [-d] -o language/LC_CTYPE src-file\n");
276 	    exit(1);
277 	}
278     }
279 
280     switch (ac - optind) {
281     case 0:
282 	break;
283     case 1:
284 	if (freopen(av[optind], "r", stdin) == 0)
285 	    err(1, "unable to open input file %s", av[optind]);
286 	break;
287     default:
288 	goto usage;
289     }
290     for (x = 0; x < _CACHED_RUNES; ++x) {
291 	mapupper.map[x] = x;
292 	maplower.map[x] = x;
293     }
294     new_locale.rl_invalid_rune = _DEFAULT_INVALID_RUNE;
295     memcpy(new_locale.rl_magic, _RUNE_MAGIC_1, sizeof(new_locale.rl_magic));
296 
297     yyparse();
298 
299     return 0;
300 }
301 
302 int
yyerror(const char * s)303 yyerror(const char *s)
304 {
305     fprintf(stderr, "%s\n", s);
306 
307     return 0;
308 }
309 
310 void *
xmalloc(size_t sz)311 xmalloc(size_t sz)
312 {
313     void *r = malloc(sz);
314     if (!r) {
315 	perror("xmalloc");
316 	abort();
317     }
318     return(r);
319 }
320 
321 u_int32_t *
xlalloc(size_t sz)322 xlalloc(size_t sz)
323 {
324     u_int32_t *r = reallocarray(NULL, sz, sizeof(u_int32_t));
325     if (!r) {
326 	perror("xlalloc");
327 	abort();
328     }
329     return(r);
330 }
331 
332 u_int32_t *
xrelalloc(u_int32_t * old,size_t sz)333 xrelalloc(u_int32_t *old, size_t sz)
334 {
335     u_int32_t *r = reallocarray(old, sz, sizeof(u_int32_t));
336     if (!r) {
337 	perror("xrelalloc");
338 	abort();
339     }
340     return(r);
341 }
342 
343 void
set_map(rune_map * map,rune_list * list,u_int32_t flag)344 set_map(rune_map *map, rune_list *list, u_int32_t flag)
345 {
346     list->map &= charsetmask;
347     list->map |= charsetbits;
348     while (list) {
349 	rune_list *nlist = list->next;
350 	add_map(map, list, flag);
351 	list = nlist;
352     }
353 }
354 
355 void
add_map(rune_map * map,rune_list * list,u_int32_t flag)356 add_map(rune_map *map, rune_list *list, u_int32_t flag)
357 {
358     rune_t i;
359     rune_list *lr = 0;
360     rune_list *r;
361     rune_t run;
362 
363     while (list->min < _CACHED_RUNES && list->min <= list->max) {
364 	if (flag)
365 	    map->map[list->min++] |= flag;
366 	else
367 	    map->map[list->min++] = list->map++;
368     }
369 
370     if (list->min > list->max) {
371 	free(list);
372 	return;
373     }
374 
375     run = list->max - list->min + 1;
376 
377     if (!(r = map->root) || (list->max < r->min - 1)
378 			 || (!flag && list->max == r->min - 1)) {
379 	if (flag) {
380 	    list->types = xlalloc(run);
381 	    for (i = 0; i < run; ++i)
382 		list->types[i] = flag;
383 	}
384 	list->next = map->root;
385 	map->root = list;
386 	return;
387     }
388 
389     for (r = map->root; r && r->max + 1 < list->min; r = r->next)
390 	lr = r;
391 
392     if (!r) {
393 	/*
394 	 * We are off the end.
395 	 */
396 	if (flag) {
397 	    list->types = xlalloc(run);
398 	    for (i = 0; i < run; ++i)
399 		list->types[i] = flag;
400 	}
401 	list->next = 0;
402 	lr->next = list;
403 	return;
404     }
405 
406     if (list->max < r->min - 1) {
407 	/*
408 	 * We come before this range and we do not intersect it.
409 	 * We are not before the root node, it was checked before the loop
410 	 */
411 	if (flag) {
412 	    list->types = xlalloc(run);
413 	    for (i = 0; i < run; ++i)
414 		list->types[i] = flag;
415 	}
416 	list->next = lr->next;
417 	lr->next = list;
418 	return;
419     }
420 
421     /*
422      * At this point we have found that we at least intersect with
423      * the range pointed to by `r', we might intersect with one or
424      * more ranges beyond `r' as well.
425      */
426 
427     if (!flag && list->map - list->min != r->map - r->min) {
428 	/*
429 	 * There are only two cases when we are doing case maps and
430 	 * our maps needn't have the same offset.  When we are adjoining
431 	 * but not intersecting.
432 	 */
433 	if (list->max + 1 == r->min) {
434 	    lr->next = list;
435 	    list->next = r;
436 	    return;
437 	}
438 	if (list->min - 1 == r->max) {
439 	    list->next = r->next;
440 	    r->next = list;
441 	    return;
442 	}
443 	fprintf(stderr, "Error: conflicting map entries\n");
444 	exit(1);
445     }
446 
447     if (list->min >= r->min && list->max <= r->max) {
448 	/*
449 	 * Subset case.
450 	 */
451 
452 	if (flag) {
453 	    for (i = list->min; i <= list->max; ++i)
454 		r->types[i - r->min] |= flag;
455 	}
456 	free(list);
457 	return;
458     }
459     if (list->min <= r->min && list->max >= r->max) {
460 	/*
461 	 * Superset case.  Make him big enough to hold us.
462 	 * We might need to merge with the guy after him.
463 	 */
464 	if (flag) {
465 	    list->types = xlalloc(list->max - list->min + 1);
466 
467 	    for (i = list->min; i <= list->max; ++i)
468 		list->types[i - list->min] = flag;
469 
470 	    for (i = r->min; i <= r->max; ++i)
471 		list->types[i - list->min] |= r->types[i - r->min];
472 
473 	    free(r->types);
474 	    r->types = list->types;
475 	} else {
476 	    r->map = list->map;
477 	}
478 	r->min = list->min;
479 	r->max = list->max;
480 	free(list);
481     } else if (list->min < r->min) {
482 	/*
483 	 * Our tail intersects his head.
484 	 */
485 	if (flag) {
486 	    list->types = xlalloc(r->max - list->min + 1);
487 
488 	    for (i = r->min; i <= r->max; ++i)
489 		list->types[i - list->min] = r->types[i - r->min];
490 
491 	    for (i = list->min; i < r->min; ++i)
492 		list->types[i - list->min] = flag;
493 
494 	    for (i = r->min; i <= list->max; ++i)
495 		list->types[i - list->min] |= flag;
496 
497 	    free(r->types);
498 	    r->types = list->types;
499 	} else {
500 	    r->map = list->map;
501 	}
502 	r->min = list->min;
503 	free(list);
504 	return;
505     } else {
506 	/*
507 	 * Our head intersects his tail.
508 	 * We might need to merge with the guy after him.
509 	 */
510 	if (flag) {
511 	    r->types = xrelalloc(r->types, list->max - r->min + 1);
512 
513 	    for (i = list->min; i <= r->max; ++i)
514 		r->types[i - r->min] |= flag;
515 
516 	    for (i = r->max+1; i <= list->max; ++i)
517 		r->types[i - r->min] = flag;
518 	}
519 	r->max = list->max;
520 	free(list);
521     }
522 
523     /*
524      * Okay, check to see if we grew into the next guy(s)
525      */
526     while ((lr = r->next) && r->max >= lr->min) {
527 	if (flag) {
528 	    if (r->max >= lr->max) {
529 		/*
530 		 * Good, we consumed all of him.
531 		 */
532 		for (i = lr->min; i <= lr->max; ++i)
533 		    r->types[i - r->min] |= lr->types[i - lr->min];
534 	    } else {
535 		/*
536 		 * "append" him on to the end of us.
537 		 */
538 		r->types = xrelalloc(r->types, lr->max - r->min + 1);
539 
540 		for (i = lr->min; i <= r->max; ++i)
541 		    r->types[i - r->min] |= lr->types[i - lr->min];
542 
543 		for (i = r->max+1; i <= lr->max; ++i)
544 		    r->types[i - r->min] = lr->types[i - lr->min];
545 
546 		r->max = lr->max;
547 	    }
548 	} else {
549 	    if (lr->max > r->max)
550 		r->max = lr->max;
551 	}
552 
553 	r->next = lr->next;
554 
555 	if (flag)
556 	    free(lr->types);
557 	free(lr);
558     }
559 }
560 
561 void
dump_tables()562 dump_tables()
563 {
564     int x, n;
565     rune_list *list;
566     _FileRuneLocale file_new_locale;
567     FILE *fp = (ofile ? ofile : stdout);
568 
569     memset(&file_new_locale, 0, sizeof(file_new_locale));
570 
571     /*
572      * See if we can compress some of the istype arrays
573      */
574     for(list = types.root; list; list = list->next) {
575 	list->map = list->types[0];
576 	for (x = 1; x < list->max - list->min + 1; ++x) {
577 	    if (list->types[x] != list->map) {
578 		list->map = 0;
579 		break;
580 	    }
581 	}
582     }
583 
584     memcpy(&file_new_locale.frl_magic, new_locale.rl_magic,
585 	sizeof(file_new_locale.frl_magic));
586     memcpy(&file_new_locale.frl_encoding, new_locale.rl_encoding,
587 	sizeof(file_new_locale.frl_encoding));
588 
589     file_new_locale.frl_invalid_rune = htonl(new_locale.rl_invalid_rune);
590 
591     /*
592      * Fill in our tables.  Do this in network order so that
593      * diverse machines have a chance of sharing data.
594      * (Machines like Crays cannot share with little machines due to
595      *  word size.  Sigh.  We tried.)
596      */
597     for (x = 0; x < _CACHED_RUNES; ++x) {
598 	file_new_locale.frl_runetype[x] = htonl(types.map[x]);
599 	file_new_locale.frl_maplower[x] = htonl(maplower.map[x]);
600 	file_new_locale.frl_mapupper[x] = htonl(mapupper.map[x]);
601     }
602 
603     /*
604      * Count up how many ranges we will need for each of the extents.
605      */
606     list = types.root;
607 
608     while (list) {
609 	new_locale.rl_runetype_ext.rr_nranges++;
610 	list = list->next;
611     }
612     file_new_locale.frl_runetype_ext.frr_nranges =
613 	htonl(new_locale.rl_runetype_ext.rr_nranges);
614 
615     list = maplower.root;
616 
617     while (list) {
618 	new_locale.rl_maplower_ext.rr_nranges++;
619 	list = list->next;
620     }
621     file_new_locale.frl_maplower_ext.frr_nranges =
622 	htonl(new_locale.rl_maplower_ext.rr_nranges);
623 
624     list = mapupper.root;
625 
626     while (list) {
627 	new_locale.rl_mapupper_ext.rr_nranges++;
628 	list = list->next;
629     }
630     file_new_locale.frl_mapupper_ext.frr_nranges =
631 	htonl(new_locale.rl_mapupper_ext.rr_nranges);
632 
633     file_new_locale.frl_variable_len = htonl(new_locale.rl_variable_len);
634 
635     /*
636      * Okay, we are now ready to write the new locale file.
637      */
638 
639     /*
640      * PART 1: The _RuneLocale structure
641      */
642     if (fwrite((char *)&file_new_locale, sizeof(file_new_locale), 1, fp) != 1)
643 	err(1, "writing _RuneLocale to %s", locale_file);
644     /*
645      * PART 2: The runetype_ext structures (not the actual tables)
646      */
647     for (list = types.root, n = 0; list != NULL; list = list->next, n++) {
648 	_FileRuneEntry re;
649 
650 	memset(&re, 0, sizeof(re));
651 	re.fre_min = htonl(list->min);
652 	re.fre_max = htonl(list->max);
653 	re.fre_map = htonl(list->map);
654 
655 	if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
656 	    err(1, "writing runetype_ext #%d to %s", n, locale_file);
657     }
658     /*
659      * PART 3: The maplower_ext structures
660      */
661     for (list = maplower.root, n = 0; list != NULL; list = list->next, n++) {
662 	_FileRuneEntry re;
663 
664 	memset(&re, 0, sizeof(re));
665 	re.fre_min = htonl(list->min);
666 	re.fre_max = htonl(list->max);
667 	re.fre_map = htonl(list->map);
668 
669 	if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
670 	    err(1, "writing maplower_ext #%d to %s", n, locale_file);
671     }
672     /*
673      * PART 4: The mapupper_ext structures
674      */
675     for (list = mapupper.root, n = 0; list != NULL; list = list->next, n++) {
676 	_FileRuneEntry re;
677 
678 	memset(&re, 0, sizeof(re));
679 	re.fre_min = htonl(list->min);
680 	re.fre_max = htonl(list->max);
681 	re.fre_map = htonl(list->map);
682 
683 	if (fwrite((char *)&re, sizeof(re), 1, fp) != 1)
684 	    err(1, "writing mapupper_ext #%d to %s", n, locale_file);
685     }
686     /*
687      * PART 5: The runetype_ext tables
688      */
689     for (list = types.root, n = 0; list != NULL; list = list->next, n++) {
690 	for (x = 0; x < list->max - list->min + 1; ++x)
691 	    list->types[x] = htonl(list->types[x]);
692 
693 	if (!list->map) {
694 	    if (fwrite((char *)list->types,
695 		       (list->max - list->min + 1) * sizeof(u_int32_t),
696 		       1, fp) != 1)
697 		err(1, "writing runetype_ext table #%d to %s", n, locale_file);
698 	}
699     }
700     /*
701      * PART 5: And finally the variable data
702      */
703     if (new_locale.rl_variable_len != 0 &&
704 	fwrite((char *)new_locale.rl_variable,
705 	       new_locale.rl_variable_len, 1, fp) != 1)
706 	err(1, "writing variable data to %s", locale_file);
707     fclose(fp);
708 
709     if (!debug)
710 	return;
711 
712     if (new_locale.rl_encoding[0])
713 	fprintf(stderr, "ENCODING	%s\n", new_locale.rl_encoding);
714     if (new_locale.rl_variable)
715 	fprintf(stderr, "VARIABLE	%s\n",
716 		(char *)new_locale.rl_variable);
717 
718     fprintf(stderr, "\nMAPLOWER:\n\n");
719 
720     for (x = 0; x < _CACHED_RUNES; ++x) {
721 	if (isprint(maplower.map[x]))
722 	    fprintf(stderr, " '%c'", (int)maplower.map[x]);
723 	else if (maplower.map[x])
724 	    fprintf(stderr, "%04x", maplower.map[x]);
725 	else
726 	    fprintf(stderr, "%4x", 0);
727 	if ((x & 0xf) == 0xf)
728 	    fprintf(stderr, "\n");
729 	else
730 	    fprintf(stderr, " ");
731     }
732     fprintf(stderr, "\n");
733 
734     for (list = maplower.root; list; list = list->next)
735 	fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
736 
737     fprintf(stderr, "\nMAPUPPER:\n\n");
738 
739     for (x = 0; x < _CACHED_RUNES; ++x) {
740 	if (isprint(mapupper.map[x]))
741 	    fprintf(stderr, " '%c'", (int)mapupper.map[x]);
742 	else if (mapupper.map[x])
743 	    fprintf(stderr, "%04x", mapupper.map[x]);
744 	else
745 	    fprintf(stderr, "%4x", 0);
746 	if ((x & 0xf) == 0xf)
747 	    fprintf(stderr, "\n");
748 	else
749 	    fprintf(stderr, " ");
750     }
751     fprintf(stderr, "\n");
752 
753     for (list = mapupper.root; list; list = list->next)
754 	fprintf(stderr, "\t%04x - %04x : %04x\n", list->min, list->max, list->map);
755 
756 
757     fprintf(stderr, "\nTYPES:\n\n");
758 
759     for (x = 0; x < _CACHED_RUNES; ++x) {
760 	u_int32_t r = types.map[x];
761 
762 	if (r) {
763 	    if (isprint(x))
764 		fprintf(stderr, " '%c':%2d", x, (int)(r & 0xff));
765 	    else
766 		fprintf(stderr, "%04x:%2d", x, (int)(r & 0xff));
767 
768 	    fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
769 	    fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
770 	    fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
771 	    fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
772 	    fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
773 	    fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
774 	    fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
775 	    fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
776 	    fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
777 	    fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
778 	    fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
779 	    fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
780 	    fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
781 	    fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
782 	    fprintf(stderr, "\n");
783 	}
784     }
785 
786     for (list = types.root; list; list = list->next) {
787 	if (list->map && list->min + 3 < list->max) {
788 	    u_int32_t r = list->map;
789 
790 	    fprintf(stderr, "%04x:%2d", list->min, r & 0xff);
791 
792 	    fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
793 	    fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
794 	    fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
795 	    fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
796 	    fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
797 	    fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
798 	    fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
799 	    fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
800 	    fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
801 	    fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
802 	    fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
803 	    fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
804 	    fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
805 	    fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
806 	    fprintf(stderr, "\n...\n");
807 
808 	    fprintf(stderr, "%04x:%2d", list->max, r & 0xff);
809 
810 	    fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
811 	    fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
812 	    fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
813 	    fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
814 	    fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
815 	    fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
816 	    fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
817 	    fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
818 	    fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
819 	    fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
820 	    fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
821 	    fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
822 	    fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
823 	    fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
824             fprintf(stderr, " %1u", (unsigned)((r & _RUNETYPE_SWM)>>_RUNETYPE_SWS));
825 	    fprintf(stderr, "\n");
826 	} else
827 	for (x = list->min; x <= list->max; ++x) {
828 	    u_int32_t r = ntohl(list->types[x - list->min]);
829 
830 	    if (r) {
831 		fprintf(stderr, "%04x:%2d", x, (int)(r & 0xff));
832 
833 		fprintf(stderr, " %4s", (r & _RUNETYPE_A) ? "alph" : "");
834 		fprintf(stderr, " %4s", (r & _RUNETYPE_C) ? "ctrl" : "");
835 		fprintf(stderr, " %4s", (r & _RUNETYPE_D) ? "dig" : "");
836 		fprintf(stderr, " %4s", (r & _RUNETYPE_G) ? "graf" : "");
837 		fprintf(stderr, " %4s", (r & _RUNETYPE_L) ? "low" : "");
838 		fprintf(stderr, " %4s", (r & _RUNETYPE_P) ? "punc" : "");
839 		fprintf(stderr, " %4s", (r & _RUNETYPE_S) ? "spac" : "");
840 		fprintf(stderr, " %4s", (r & _RUNETYPE_U) ? "upp" : "");
841 		fprintf(stderr, " %4s", (r & _RUNETYPE_X) ? "xdig" : "");
842 		fprintf(stderr, " %4s", (r & _RUNETYPE_B) ? "blnk" : "");
843 		fprintf(stderr, " %4s", (r & _RUNETYPE_R) ? "prnt" : "");
844 		fprintf(stderr, " %4s", (r & _RUNETYPE_I) ? "ideo" : "");
845 		fprintf(stderr, " %4s", (r & _RUNETYPE_T) ? "spec" : "");
846 		fprintf(stderr, " %4s", (r & _RUNETYPE_Q) ? "phon" : "");
847                 fprintf(stderr, " %1u", (unsigned)((r & _RUNETYPE_SWM)>>_RUNETYPE_SWS));
848 		fprintf(stderr, "\n");
849 	    }
850 	}
851     }
852 }
853