1/* $NetBSD: mklocaledb.c,v 1.1 2009/01/02 00:20:23 tnozaki Exp $ */
2
3/*-
4 * Copyright (c)2008 Citrus Project,
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 * XXX TEMPORARY IMPLEMENTATION.
31 * don't waste your time, all we need is localedef(1).
32 */
33
34#if HAVE_NBTOOL_CONFIG_H
35#include "nbtool_config.h"
36#endif
37
38#include <sys/cdefs.h>
39#if !defined(lint)
40__RCSID("$NetBSD: mklocaledb.c,v 1.1 2009/01/02 00:20:23 tnozaki Exp $");
41#endif /* not lint */
42
43#include <assert.h>
44#include <err.h>
45#include <errno.h>
46#include <limits.h>
47#include <stdint.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <unistd.h>
52
53#include "fix_grouping.h"
54
55#include "citrus_namespace.h"
56#include "citrus_bcs.h"
57#include "citrus_types.h"
58#include "citrus_region.h"
59#include "citrus_db_factory.h"
60#include "citrus_db_hash.h"
61#include "citrus_db.h"
62
63#include "citrus_lc_monetary.h"
64#include "citrus_lc_numeric.h"
65#include "citrus_lc_time.h"
66#include "citrus_lc_messages.h"
67
68void mklocaledb(const char *, FILE *, FILE *);
69
70/*
71 * TODO: -d debug options's output.
72 */
73extern int debug;
74extern void usage(void);
75
76static int
77save_as_string(struct _db_factory *df,
78    const char *key, const char *value)
79{
80	return _db_factory_addstr_by_s(df, key, value);
81}
82
83static int
84save_as_grouping(struct _db_factory *df,
85    const char *key, const char *value)
86{
87	value = __fix_locale_grouping_str(value);
88	return _db_factory_addstr_by_s(df, key, value);
89}
90
91static int
92save_as_uint8(struct _db_factory *df,
93    const char *key, const char *head)
94{
95	char *tail;
96	unsigned long int value;
97	uint8_t u8;
98
99	value = _bcs_strtoul(head, &tail, 0);
100	if (head == tail || value > 0xFF)
101		return 1;
102	u8 = (uint8_t)(value & 0xFF);
103	return _db_factory_add8_by_s(df, key, u8);
104}
105
106typedef struct {
107	const char *key;
108	int (*save)(struct _db_factory *,
109	    const char *, const char *);
110} token_t;
111
112typedef struct {
113	const char *magic, * vers_sym;
114	uint32_t version;
115	const token_t tokens[];
116} category_t;
117
118static const category_t lc_monetary = {
119    _CITRUS_LC_MONETARY_MAGIC_1,
120    _CITRUS_LC_MONETARY_SYM_VERSION,
121    _CITRUS_LC_MONETARY_VERSION,
122    {
123	{ _CITRUS_LC_MONETARY_SYM_INT_CURR_SYMBOL,    &save_as_string   },
124	{ _CITRUS_LC_MONETARY_SYM_CURRENCY_SYMBOL,    &save_as_string   },
125	{ _CITRUS_LC_MONETARY_SYM_MON_DECIMAL_POINT,  &save_as_string   },
126	{ _CITRUS_LC_MONETARY_SYM_MON_THOUSANDS_SEP,  &save_as_string   },
127	{ _CITRUS_LC_MONETARY_SYM_MON_GROUPING,       &save_as_grouping },
128	{ _CITRUS_LC_MONETARY_SYM_POSITIVE_SIGN,      &save_as_string   },
129	{ _CITRUS_LC_MONETARY_SYM_NEGATIVE_SIGN,      &save_as_string   },
130	{ _CITRUS_LC_MONETARY_SYM_INT_FRAC_DIGITS,    &save_as_uint8    },
131	{ _CITRUS_LC_MONETARY_SYM_FRAC_DIGITS,        &save_as_uint8    },
132	{ _CITRUS_LC_MONETARY_SYM_P_CS_PRECEDES,      &save_as_uint8    },
133	{ _CITRUS_LC_MONETARY_SYM_P_SEP_BY_SPACE,     &save_as_uint8    },
134	{ _CITRUS_LC_MONETARY_SYM_N_CS_PRECEDES,      &save_as_uint8    },
135	{ _CITRUS_LC_MONETARY_SYM_N_SEP_BY_SPACE,     &save_as_uint8    },
136	{ _CITRUS_LC_MONETARY_SYM_P_SIGN_POSN,        &save_as_uint8    },
137	{ _CITRUS_LC_MONETARY_SYM_N_SIGN_POSN,        &save_as_uint8    },
138	{ _CITRUS_LC_MONETARY_SYM_INT_P_CS_PRECEDES,  &save_as_uint8    },
139	{ _CITRUS_LC_MONETARY_SYM_INT_N_CS_PRECEDES,  &save_as_uint8    },
140	{ _CITRUS_LC_MONETARY_SYM_INT_P_SEP_BY_SPACE, &save_as_uint8    },
141	{ _CITRUS_LC_MONETARY_SYM_INT_N_SEP_BY_SPACE, &save_as_uint8    },
142	{ _CITRUS_LC_MONETARY_SYM_INT_P_SIGN_POSN,    &save_as_uint8    },
143	{ _CITRUS_LC_MONETARY_SYM_INT_N_SIGN_POSN,    &save_as_uint8    },
144	{ NULL },
145    },
146};
147
148static const category_t lc_numeric = {
149    _CITRUS_LC_NUMERIC_MAGIC_1,
150    _CITRUS_LC_NUMERIC_SYM_VERSION,
151    _CITRUS_LC_NUMERIC_VERSION,
152    {
153	{ _CITRUS_LC_NUMERIC_SYM_DECIMAL_POINT, &save_as_string   },
154	{ _CITRUS_LC_NUMERIC_SYM_THOUSANDS_SEP, &save_as_string   },
155	{ _CITRUS_LC_NUMERIC_SYM_GROUPING,      &save_as_grouping },
156	{ NULL },
157    },
158};
159
160static const category_t lc_time = {
161    _CITRUS_LC_TIME_MAGIC_1,
162    _CITRUS_LC_TIME_SYM_VERSION,
163    _CITRUS_LC_TIME_VERSION,
164    {
165	{ _CITRUS_LC_TIME_SYM_ABDAY_1,     &save_as_string },
166	{ _CITRUS_LC_TIME_SYM_ABDAY_2,     &save_as_string },
167	{ _CITRUS_LC_TIME_SYM_ABDAY_3,     &save_as_string },
168	{ _CITRUS_LC_TIME_SYM_ABDAY_4,     &save_as_string },
169	{ _CITRUS_LC_TIME_SYM_ABDAY_5,     &save_as_string },
170	{ _CITRUS_LC_TIME_SYM_ABDAY_6,     &save_as_string },
171	{ _CITRUS_LC_TIME_SYM_ABDAY_7,     &save_as_string },
172	{ _CITRUS_LC_TIME_SYM_DAY_1,       &save_as_string },
173	{ _CITRUS_LC_TIME_SYM_DAY_2,       &save_as_string },
174	{ _CITRUS_LC_TIME_SYM_DAY_3,       &save_as_string },
175	{ _CITRUS_LC_TIME_SYM_DAY_4,       &save_as_string },
176	{ _CITRUS_LC_TIME_SYM_DAY_5,       &save_as_string },
177	{ _CITRUS_LC_TIME_SYM_DAY_6,       &save_as_string },
178	{ _CITRUS_LC_TIME_SYM_DAY_7,       &save_as_string },
179	{ _CITRUS_LC_TIME_SYM_ABMON_1,     &save_as_string },
180	{ _CITRUS_LC_TIME_SYM_ABMON_2,     &save_as_string },
181	{ _CITRUS_LC_TIME_SYM_ABMON_3,     &save_as_string },
182	{ _CITRUS_LC_TIME_SYM_ABMON_4,     &save_as_string },
183	{ _CITRUS_LC_TIME_SYM_ABMON_5,     &save_as_string },
184	{ _CITRUS_LC_TIME_SYM_ABMON_6,     &save_as_string },
185	{ _CITRUS_LC_TIME_SYM_ABMON_7,     &save_as_string },
186	{ _CITRUS_LC_TIME_SYM_ABMON_8,     &save_as_string },
187	{ _CITRUS_LC_TIME_SYM_ABMON_9,     &save_as_string },
188	{ _CITRUS_LC_TIME_SYM_ABMON_10,    &save_as_string },
189	{ _CITRUS_LC_TIME_SYM_ABMON_11,    &save_as_string },
190	{ _CITRUS_LC_TIME_SYM_ABMON_12,    &save_as_string },
191	{ _CITRUS_LC_TIME_SYM_MON_1,       &save_as_string },
192	{ _CITRUS_LC_TIME_SYM_MON_2,       &save_as_string },
193	{ _CITRUS_LC_TIME_SYM_MON_3,       &save_as_string },
194	{ _CITRUS_LC_TIME_SYM_MON_4,       &save_as_string },
195	{ _CITRUS_LC_TIME_SYM_MON_5,       &save_as_string },
196	{ _CITRUS_LC_TIME_SYM_MON_6,       &save_as_string },
197	{ _CITRUS_LC_TIME_SYM_MON_7,       &save_as_string },
198	{ _CITRUS_LC_TIME_SYM_MON_8,       &save_as_string },
199	{ _CITRUS_LC_TIME_SYM_MON_9,       &save_as_string },
200	{ _CITRUS_LC_TIME_SYM_MON_10,      &save_as_string },
201	{ _CITRUS_LC_TIME_SYM_MON_11,      &save_as_string },
202	{ _CITRUS_LC_TIME_SYM_MON_12,      &save_as_string },
203	{ _CITRUS_LC_TIME_SYM_AM_STR,      &save_as_string },
204	{ _CITRUS_LC_TIME_SYM_PM_STR,      &save_as_string },
205	{ _CITRUS_LC_TIME_SYM_D_T_FMT,     &save_as_string },
206	{ _CITRUS_LC_TIME_SYM_D_FMT,       &save_as_string },
207	{ _CITRUS_LC_TIME_SYM_T_FMT,       &save_as_string },
208	{ _CITRUS_LC_TIME_SYM_T_FMT_AMPM,  &save_as_string },
209	{ NULL },
210    },
211};
212
213static const category_t lc_messages = {
214    _CITRUS_LC_MESSAGES_MAGIC_1,
215    _CITRUS_LC_MESSAGES_SYM_VERSION,
216    _CITRUS_LC_MESSAGES_VERSION,
217    {
218	{ _CITRUS_LC_MESSAGES_SYM_YESEXPR, &save_as_string },
219	{ _CITRUS_LC_MESSAGES_SYM_NOEXPR,  &save_as_string },
220	{ _CITRUS_LC_MESSAGES_SYM_YESSTR,  &save_as_string },
221	{ _CITRUS_LC_MESSAGES_SYM_NOSTR,   &save_as_string },
222	{ NULL },
223    },
224};
225
226void
227mklocaledb(const char *type, FILE *reader, FILE *writer)
228{
229	static const char delim[3] = { '\0', '\0', '#' };
230	const category_t *category = NULL;
231	struct _db_factory *df;
232	const token_t *token;
233	char *line;
234	size_t size;
235	void *serialized;
236	struct _region r;
237
238	_DIAGASSERT(type != NULL);
239	_DIAGASSERT(reader != NULL);
240	_DIAGASSERT(writer != NULL);
241
242	if (!strcasecmp(type, "MONETARY"))
243		category = &lc_monetary;
244	else if (!strcasecmp(type, "NUMERIC"))
245		category = &lc_numeric;
246	else if (!strcasecmp(type, "TIME"))
247		category = &lc_time;
248	else if (!strcasecmp(type, "MESSAGES"))
249		category = &lc_messages;
250	else {
251		usage();
252		/*NOTREACHED*/
253	}
254	if (_db_factory_create(&df, &_db_hash_std, NULL))
255		errx(1, "can't create db factory.\n");
256	if (_db_factory_add32_by_s(df, category->vers_sym, category->version))
257		errx(1, "can't store db.\n");
258	token = &category->tokens[0];
259	while (token->key != NULL) {
260		line = fparseln(reader, NULL,
261		    NULL, delim, FPARSELN_UNESCALL);
262		if (line == NULL)
263			errx(1, "can't read line.\n");
264		if ((*token->save)(df, token->key, (const char *)line))
265			errx(1, "can't store db.\n");
266		free(line);
267		++token;
268	}
269	size = _db_factory_calc_size(df);
270	_DIAGASSERT(size > 0);
271	serialized = malloc(size);
272	if (serialized == NULL)
273		errx(1, "can't malloc.\n");
274	_DIAGASSERT(serialized != NULL);
275	_region_init(&r, serialized, size);
276	if (_db_factory_serialize(df, category->magic, &r))
277		errx(1, "can't serialize db.\n");
278	fwrite(serialized, size, 1, writer);
279	_db_factory_free(df);
280}
281