xref: /netbsd/usr.bin/mklocale/mklocaledb.c (revision 43e4027d)
1*43e4027dSchristos /* $NetBSD: mklocaledb.c,v 1.4 2015/06/16 22:54:10 christos Exp $ */
252ed7b03Stnozaki 
352ed7b03Stnozaki /*-
452ed7b03Stnozaki  * Copyright (c)2008 Citrus Project,
552ed7b03Stnozaki  * All rights reserved.
652ed7b03Stnozaki  *
752ed7b03Stnozaki  * Redistribution and use in source and binary forms, with or without
852ed7b03Stnozaki  * modification, are permitted provided that the following conditions
952ed7b03Stnozaki  * are met:
1052ed7b03Stnozaki  * 1. Redistributions of source code must retain the above copyright
1152ed7b03Stnozaki  *    notice, this list of conditions and the following disclaimer.
1252ed7b03Stnozaki  * 2. Redistributions in binary form must reproduce the above copyright
1352ed7b03Stnozaki  *    notice, this list of conditions and the following disclaimer in the
1452ed7b03Stnozaki  *    documentation and/or other materials provided with the distribution.
1552ed7b03Stnozaki  *
1652ed7b03Stnozaki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1752ed7b03Stnozaki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1852ed7b03Stnozaki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1952ed7b03Stnozaki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2052ed7b03Stnozaki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2152ed7b03Stnozaki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2252ed7b03Stnozaki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2352ed7b03Stnozaki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2452ed7b03Stnozaki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2552ed7b03Stnozaki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2652ed7b03Stnozaki  * SUCH DAMAGE.
2752ed7b03Stnozaki  */
2852ed7b03Stnozaki 
2952ed7b03Stnozaki /*
3052ed7b03Stnozaki  * XXX TEMPORARY IMPLEMENTATION.
3152ed7b03Stnozaki  * don't waste your time, all we need is localedef(1).
3252ed7b03Stnozaki  */
3352ed7b03Stnozaki 
3452ed7b03Stnozaki #if HAVE_NBTOOL_CONFIG_H
3552ed7b03Stnozaki #include "nbtool_config.h"
3652ed7b03Stnozaki #endif
3752ed7b03Stnozaki 
38b5d75fbcSdogcow #include <sys/cdefs.h>
39b5d75fbcSdogcow #if !defined(lint)
40*43e4027dSchristos __RCSID("$NetBSD: mklocaledb.c,v 1.4 2015/06/16 22:54:10 christos Exp $");
41b5d75fbcSdogcow #endif /* not lint */
42b5d75fbcSdogcow 
4352ed7b03Stnozaki #include <assert.h>
4452ed7b03Stnozaki #include <err.h>
4552ed7b03Stnozaki #include <errno.h>
4652ed7b03Stnozaki #include <limits.h>
4752ed7b03Stnozaki #include <stdint.h>
4852ed7b03Stnozaki #include <stdio.h>
4952ed7b03Stnozaki #include <stdlib.h>
5052ed7b03Stnozaki #include <string.h>
5152ed7b03Stnozaki #include <unistd.h>
5252ed7b03Stnozaki 
5352ed7b03Stnozaki #include "fix_grouping.h"
5452ed7b03Stnozaki 
5552ed7b03Stnozaki #include "citrus_namespace.h"
5652ed7b03Stnozaki #include "citrus_bcs.h"
5752ed7b03Stnozaki #include "citrus_types.h"
5852ed7b03Stnozaki #include "citrus_region.h"
5952ed7b03Stnozaki #include "citrus_db_factory.h"
6052ed7b03Stnozaki #include "citrus_db_hash.h"
6152ed7b03Stnozaki #include "citrus_db.h"
6252ed7b03Stnozaki 
6352ed7b03Stnozaki #include "citrus_lc_monetary.h"
6452ed7b03Stnozaki #include "citrus_lc_numeric.h"
6552ed7b03Stnozaki #include "citrus_lc_time.h"
6652ed7b03Stnozaki #include "citrus_lc_messages.h"
6752ed7b03Stnozaki 
6852ed7b03Stnozaki void mklocaledb(const char *, FILE *, FILE *);
6952ed7b03Stnozaki 
7052ed7b03Stnozaki /*
7152ed7b03Stnozaki  * TODO: -d debug options's output.
7252ed7b03Stnozaki  */
7352ed7b03Stnozaki extern int debug;
7452ed7b03Stnozaki extern void usage(void);
7552ed7b03Stnozaki 
7652ed7b03Stnozaki static int
save_as_string(struct _db_factory * df,const char * key,const char * value)7752ed7b03Stnozaki save_as_string(struct _db_factory *df,
7852ed7b03Stnozaki     const char *key, const char *value)
7952ed7b03Stnozaki {
8052ed7b03Stnozaki 	return _db_factory_addstr_by_s(df, key, value);
8152ed7b03Stnozaki }
8252ed7b03Stnozaki 
8352ed7b03Stnozaki static int
save_as_grouping(struct _db_factory * df,const char * key,const char * value)8452ed7b03Stnozaki save_as_grouping(struct _db_factory *df,
8552ed7b03Stnozaki     const char *key, const char *value)
8652ed7b03Stnozaki {
8752ed7b03Stnozaki 	value = __fix_locale_grouping_str(value);
8852ed7b03Stnozaki 	return _db_factory_addstr_by_s(df, key, value);
8952ed7b03Stnozaki }
9052ed7b03Stnozaki 
9152ed7b03Stnozaki static int
save_as_uint8(struct _db_factory * df,const char * key,const char * head)9252ed7b03Stnozaki save_as_uint8(struct _db_factory *df,
9352ed7b03Stnozaki     const char *key, const char *head)
9452ed7b03Stnozaki {
9552ed7b03Stnozaki 	char *tail;
9652ed7b03Stnozaki 	unsigned long int value;
9752ed7b03Stnozaki 	uint8_t u8;
9852ed7b03Stnozaki 
9952ed7b03Stnozaki 	value = _bcs_strtoul(head, &tail, 0);
10052ed7b03Stnozaki 	if (head == tail || value > 0xFF)
10152ed7b03Stnozaki 		return 1;
10252ed7b03Stnozaki 	u8 = (uint8_t)(value & 0xFF);
10352ed7b03Stnozaki 	return _db_factory_add8_by_s(df, key, u8);
10452ed7b03Stnozaki }
10552ed7b03Stnozaki 
10652ed7b03Stnozaki typedef struct {
10752ed7b03Stnozaki 	const char *key;
10852ed7b03Stnozaki 	int (*save)(struct _db_factory *,
10952ed7b03Stnozaki 	    const char *, const char *);
11052ed7b03Stnozaki } token_t;
11152ed7b03Stnozaki 
11252ed7b03Stnozaki typedef struct {
11352ed7b03Stnozaki 	const char *magic, * vers_sym;
11452ed7b03Stnozaki 	uint32_t version;
11552ed7b03Stnozaki 	const token_t tokens[];
11652ed7b03Stnozaki } category_t;
11752ed7b03Stnozaki 
11852ed7b03Stnozaki static const category_t lc_monetary = {
11952ed7b03Stnozaki     _CITRUS_LC_MONETARY_MAGIC_1,
12052ed7b03Stnozaki     _CITRUS_LC_MONETARY_SYM_VERSION,
12152ed7b03Stnozaki     _CITRUS_LC_MONETARY_VERSION,
12252ed7b03Stnozaki     {
12352ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_CURR_SYMBOL,    &save_as_string   },
12452ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_CURRENCY_SYMBOL,    &save_as_string   },
12552ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_MON_DECIMAL_POINT,  &save_as_string   },
12652ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_MON_THOUSANDS_SEP,  &save_as_string   },
12752ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_MON_GROUPING,       &save_as_grouping },
12852ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_POSITIVE_SIGN,      &save_as_string   },
12952ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_NEGATIVE_SIGN,      &save_as_string   },
13052ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_FRAC_DIGITS,    &save_as_uint8    },
13152ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_FRAC_DIGITS,        &save_as_uint8    },
13252ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_P_CS_PRECEDES,      &save_as_uint8    },
13352ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_P_SEP_BY_SPACE,     &save_as_uint8    },
13452ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_N_CS_PRECEDES,      &save_as_uint8    },
13552ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_N_SEP_BY_SPACE,     &save_as_uint8    },
13652ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_P_SIGN_POSN,        &save_as_uint8    },
13752ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_N_SIGN_POSN,        &save_as_uint8    },
13852ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_P_CS_PRECEDES,  &save_as_uint8    },
13952ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_P_SEP_BY_SPACE, &save_as_uint8    },
1407294909aSjoerg 	{ _CITRUS_LC_MONETARY_SYM_INT_N_CS_PRECEDES,  &save_as_uint8    },
14152ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_N_SEP_BY_SPACE, &save_as_uint8    },
14252ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_P_SIGN_POSN,    &save_as_uint8    },
14352ed7b03Stnozaki 	{ _CITRUS_LC_MONETARY_SYM_INT_N_SIGN_POSN,    &save_as_uint8    },
14452ed7b03Stnozaki 	{ NULL },
14552ed7b03Stnozaki     },
14652ed7b03Stnozaki };
14752ed7b03Stnozaki 
14852ed7b03Stnozaki static const category_t lc_numeric = {
14952ed7b03Stnozaki     _CITRUS_LC_NUMERIC_MAGIC_1,
15052ed7b03Stnozaki     _CITRUS_LC_NUMERIC_SYM_VERSION,
15152ed7b03Stnozaki     _CITRUS_LC_NUMERIC_VERSION,
15252ed7b03Stnozaki     {
15352ed7b03Stnozaki 	{ _CITRUS_LC_NUMERIC_SYM_DECIMAL_POINT, &save_as_string   },
15452ed7b03Stnozaki 	{ _CITRUS_LC_NUMERIC_SYM_THOUSANDS_SEP, &save_as_string   },
15552ed7b03Stnozaki 	{ _CITRUS_LC_NUMERIC_SYM_GROUPING,      &save_as_grouping },
15652ed7b03Stnozaki 	{ NULL },
15752ed7b03Stnozaki     },
15852ed7b03Stnozaki };
15952ed7b03Stnozaki 
16052ed7b03Stnozaki static const category_t lc_time = {
16152ed7b03Stnozaki     _CITRUS_LC_TIME_MAGIC_1,
16252ed7b03Stnozaki     _CITRUS_LC_TIME_SYM_VERSION,
16352ed7b03Stnozaki     _CITRUS_LC_TIME_VERSION,
16452ed7b03Stnozaki     {
16552ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_1,     &save_as_string },
16652ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_2,     &save_as_string },
16752ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_3,     &save_as_string },
16852ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_4,     &save_as_string },
16952ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_5,     &save_as_string },
17052ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_6,     &save_as_string },
17152ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABDAY_7,     &save_as_string },
17252ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_1,       &save_as_string },
17352ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_2,       &save_as_string },
17452ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_3,       &save_as_string },
17552ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_4,       &save_as_string },
17652ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_5,       &save_as_string },
17752ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_6,       &save_as_string },
17852ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_DAY_7,       &save_as_string },
17952ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_1,     &save_as_string },
18052ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_2,     &save_as_string },
18152ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_3,     &save_as_string },
18252ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_4,     &save_as_string },
18352ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_5,     &save_as_string },
18452ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_6,     &save_as_string },
18552ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_7,     &save_as_string },
18652ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_8,     &save_as_string },
18752ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_9,     &save_as_string },
18852ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_10,    &save_as_string },
18952ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_11,    &save_as_string },
19052ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_ABMON_12,    &save_as_string },
19152ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_1,       &save_as_string },
19252ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_2,       &save_as_string },
19352ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_3,       &save_as_string },
19452ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_4,       &save_as_string },
19552ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_5,       &save_as_string },
19652ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_6,       &save_as_string },
19752ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_7,       &save_as_string },
19852ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_8,       &save_as_string },
19952ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_9,       &save_as_string },
20052ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_10,      &save_as_string },
20152ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_11,      &save_as_string },
20252ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_MON_12,      &save_as_string },
20352ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_AM_STR,      &save_as_string },
20452ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_PM_STR,      &save_as_string },
20552ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_D_T_FMT,     &save_as_string },
20652ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_D_FMT,       &save_as_string },
20752ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_T_FMT,       &save_as_string },
20852ed7b03Stnozaki 	{ _CITRUS_LC_TIME_SYM_T_FMT_AMPM,  &save_as_string },
20952ed7b03Stnozaki 	{ NULL },
21052ed7b03Stnozaki     },
21152ed7b03Stnozaki };
21252ed7b03Stnozaki 
21352ed7b03Stnozaki static const category_t lc_messages = {
21452ed7b03Stnozaki     _CITRUS_LC_MESSAGES_MAGIC_1,
21552ed7b03Stnozaki     _CITRUS_LC_MESSAGES_SYM_VERSION,
21652ed7b03Stnozaki     _CITRUS_LC_MESSAGES_VERSION,
21752ed7b03Stnozaki     {
21852ed7b03Stnozaki 	{ _CITRUS_LC_MESSAGES_SYM_YESEXPR, &save_as_string },
21952ed7b03Stnozaki 	{ _CITRUS_LC_MESSAGES_SYM_NOEXPR,  &save_as_string },
22052ed7b03Stnozaki 	{ _CITRUS_LC_MESSAGES_SYM_YESSTR,  &save_as_string },
22152ed7b03Stnozaki 	{ _CITRUS_LC_MESSAGES_SYM_NOSTR,   &save_as_string },
22252ed7b03Stnozaki 	{ NULL },
22352ed7b03Stnozaki     },
22452ed7b03Stnozaki };
22552ed7b03Stnozaki 
22652ed7b03Stnozaki void
mklocaledb(const char * type,FILE * reader,FILE * writer)22752ed7b03Stnozaki mklocaledb(const char *type, FILE *reader, FILE *writer)
22852ed7b03Stnozaki {
22952ed7b03Stnozaki 	static const char delim[3] = { '\0', '\0', '#' };
23052ed7b03Stnozaki 	const category_t *category = NULL;
23152ed7b03Stnozaki 	struct _db_factory *df;
23252ed7b03Stnozaki 	const token_t *token;
23352ed7b03Stnozaki 	char *line;
23452ed7b03Stnozaki 	size_t size;
23552ed7b03Stnozaki 	void *serialized;
23652ed7b03Stnozaki 	struct _region r;
23752ed7b03Stnozaki 
23852ed7b03Stnozaki 	_DIAGASSERT(type != NULL);
23952ed7b03Stnozaki 	_DIAGASSERT(reader != NULL);
24052ed7b03Stnozaki 	_DIAGASSERT(writer != NULL);
24152ed7b03Stnozaki 
24252ed7b03Stnozaki 	if (!strcasecmp(type, "MONETARY"))
24352ed7b03Stnozaki 		category = &lc_monetary;
24452ed7b03Stnozaki 	else if (!strcasecmp(type, "NUMERIC"))
24552ed7b03Stnozaki 		category = &lc_numeric;
24652ed7b03Stnozaki 	else if (!strcasecmp(type, "TIME"))
24752ed7b03Stnozaki 		category = &lc_time;
24852ed7b03Stnozaki 	else if (!strcasecmp(type, "MESSAGES"))
24952ed7b03Stnozaki 		category = &lc_messages;
25052ed7b03Stnozaki 	else {
25152ed7b03Stnozaki 		usage();
25252ed7b03Stnozaki 		/*NOTREACHED*/
25352ed7b03Stnozaki 	}
25452ed7b03Stnozaki 	if (_db_factory_create(&df, &_db_hash_std, NULL))
255*43e4027dSchristos 		errx(EXIT_FAILURE, "can't create db factory");
25652ed7b03Stnozaki 	if (_db_factory_add32_by_s(df, category->vers_sym, category->version))
257*43e4027dSchristos 		errx(EXIT_FAILURE, "can't store db");
25852ed7b03Stnozaki 	token = &category->tokens[0];
25952ed7b03Stnozaki 	while (token->key != NULL) {
26052ed7b03Stnozaki 		line = fparseln(reader, NULL,
26152ed7b03Stnozaki 		    NULL, delim, FPARSELN_UNESCALL);
26252ed7b03Stnozaki 		if (line == NULL)
263*43e4027dSchristos 			errx(EXIT_FAILURE, "can't read line");
26452ed7b03Stnozaki 		if ((*token->save)(df, token->key, (const char *)line))
265*43e4027dSchristos 			errx(EXIT_FAILURE, "can't store db");
26652ed7b03Stnozaki 		free(line);
26752ed7b03Stnozaki 		++token;
26852ed7b03Stnozaki 	}
26952ed7b03Stnozaki 	size = _db_factory_calc_size(df);
27052ed7b03Stnozaki 	_DIAGASSERT(size > 0);
27152ed7b03Stnozaki 	serialized = malloc(size);
27252ed7b03Stnozaki 	if (serialized == NULL)
273*43e4027dSchristos 		errx(EXIT_FAILURE, "can't malloc");
27452ed7b03Stnozaki 	_DIAGASSERT(serialized != NULL);
27552ed7b03Stnozaki 	_region_init(&r, serialized, size);
27652ed7b03Stnozaki 	if (_db_factory_serialize(df, category->magic, &r))
277*43e4027dSchristos 		errx(EXIT_FAILURE, "can't serialize db");
27852ed7b03Stnozaki 	fwrite(serialized, size, 1, writer);
27952ed7b03Stnozaki 	_db_factory_free(df);
28052ed7b03Stnozaki }
281