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