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