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