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