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