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