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