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