xref: /minix/usr.bin/mklocale/mklocaledb.c (revision 08cbf5a0)
1 /* $NetBSD: mklocaledb.c,v 1.4 2015/06/16 22:54:10 christos 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.4 2015/06/16 22:54:10 christos 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 
68 void mklocaledb(const char *, FILE *, FILE *);
69 
70 /*
71  * TODO: -d debug options's output.
72  */
73 extern int debug;
74 extern void usage(void);
75 
76 static int
77 save_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 
83 static int
84 save_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 
91 static int
92 save_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 
106 typedef struct {
107 	const char *key;
108 	int (*save)(struct _db_factory *,
109 	    const char *, const char *);
110 } token_t;
111 
112 typedef struct {
113 	const char *magic, * vers_sym;
114 	uint32_t version;
115 	const token_t tokens[];
116 } category_t;
117 
118 static 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_P_SEP_BY_SPACE, &save_as_uint8    },
140 	{ _CITRUS_LC_MONETARY_SYM_INT_N_CS_PRECEDES,  &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 
148 static 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 
160 static 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 
213 static 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 
226 void
227 mklocaledb(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(EXIT_FAILURE, "can't create db factory");
256 	if (_db_factory_add32_by_s(df, category->vers_sym, category->version))
257 		errx(EXIT_FAILURE, "can't store db");
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(EXIT_FAILURE, "can't read line");
264 		if ((*token->save)(df, token->key, (const char *)line))
265 			errx(EXIT_FAILURE, "can't store db");
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(EXIT_FAILURE, "can't malloc");
274 	_DIAGASSERT(serialized != NULL);
275 	_region_init(&r, serialized, size);
276 	if (_db_factory_serialize(df, category->magic, &r))
277 		errx(EXIT_FAILURE, "can't serialize db");
278 	fwrite(serialized, size, 1, writer);
279 	_db_factory_free(df);
280 }
281