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