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