[BZ #2510, BZ #2830, BZ #3137, BZ #3313, BZ #3426, BZ #3465, BZ #3480, BZ #3483,...
[glibc.git] / locale / programs / ld-monetary.c
blobd493a142b568f1b8ebad9ea236fff692936cfc67
1 /* Copyright (C) 1995-1999,2000,2001,2002,2005 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
18 #ifdef HAVE_CONFIG_H
19 # include <config.h>
20 #endif
22 #include <byteswap.h>
23 #include <langinfo.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <sys/uio.h>
29 #include <assert.h>
31 #include "localedef.h"
32 #include "linereader.h"
33 #include "localeinfo.h"
34 #include "locfile.h"
37 /* The real definition of the struct for the LC_MONETARY locale. */
38 struct locale_monetary_t
40 const char *int_curr_symbol;
41 const char *currency_symbol;
42 const char *mon_decimal_point;
43 const char *mon_thousands_sep;
44 uint32_t mon_decimal_point_wc;
45 uint32_t mon_thousands_sep_wc;
46 char *mon_grouping;
47 size_t mon_grouping_len;
48 const char *positive_sign;
49 const char *negative_sign;
50 signed char int_frac_digits;
51 signed char frac_digits;
52 signed char p_cs_precedes;
53 signed char p_sep_by_space;
54 signed char n_cs_precedes;
55 signed char n_sep_by_space;
56 signed char p_sign_posn;
57 signed char n_sign_posn;
58 signed char int_p_cs_precedes;
59 signed char int_p_sep_by_space;
60 signed char int_n_cs_precedes;
61 signed char int_n_sep_by_space;
62 signed char int_p_sign_posn;
63 signed char int_n_sign_posn;
64 const char *duo_int_curr_symbol;
65 const char *duo_currency_symbol;
66 signed char duo_int_frac_digits;
67 signed char duo_frac_digits;
68 signed char duo_p_cs_precedes;
69 signed char duo_p_sep_by_space;
70 signed char duo_n_cs_precedes;
71 signed char duo_n_sep_by_space;
72 signed char duo_p_sign_posn;
73 signed char duo_n_sign_posn;
74 signed char duo_int_p_cs_precedes;
75 signed char duo_int_p_sep_by_space;
76 signed char duo_int_n_cs_precedes;
77 signed char duo_int_n_sep_by_space;
78 signed char duo_int_p_sign_posn;
79 signed char duo_int_n_sign_posn;
80 uint32_t uno_valid_from;
81 uint32_t uno_valid_to;
82 uint32_t duo_valid_from;
83 uint32_t duo_valid_to;
84 uint32_t conversion_rate[2];
85 char *crncystr;
89 /* The content iof the field int_curr_symbol has to be taken from
90 ISO-4217. We test for correct values. */
91 #define DEFINE_INT_CURR(str) str,
92 static const char *const valid_int_curr[] =
94 # include "../iso-4217.def"
96 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
97 / sizeof (valid_int_curr[0])))
98 #undef DEFINE_INT_CURR
101 /* Prototypes for local functions. */
102 static int curr_strcmp (const char *s1, const char **s2);
105 static void
106 monetary_startup (struct linereader *lr, struct localedef_t *locale,
107 int ignore_content)
109 if (!ignore_content)
111 struct locale_monetary_t *monetary;
113 locale->categories[LC_MONETARY].monetary = monetary =
114 (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
116 memset (monetary, '\0', sizeof (struct locale_monetary_t));
118 monetary->mon_grouping = NULL;
119 monetary->mon_grouping_len = 0;
121 monetary->int_frac_digits = -2;
122 monetary->frac_digits = -2;
123 monetary->p_cs_precedes = -2;
124 monetary->p_sep_by_space = -2;
125 monetary->n_cs_precedes = -2;
126 monetary->n_sep_by_space = -2;
127 monetary->p_sign_posn = -2;
128 monetary->n_sign_posn = -2;
129 monetary->int_p_cs_precedes = -2;
130 monetary->int_p_sep_by_space = -2;
131 monetary->int_n_cs_precedes = -2;
132 monetary->int_n_sep_by_space = -2;
133 monetary->int_p_sign_posn = -2;
134 monetary->int_n_sign_posn = -2;
135 monetary->duo_int_frac_digits = -2;
136 monetary->duo_frac_digits = -2;
137 monetary->duo_p_cs_precedes = -2;
138 monetary->duo_p_sep_by_space = -2;
139 monetary->duo_n_cs_precedes = -2;
140 monetary->duo_n_sep_by_space = -2;
141 monetary->duo_p_sign_posn = -2;
142 monetary->duo_n_sign_posn = -2;
143 monetary->duo_int_p_cs_precedes = -2;
144 monetary->duo_int_p_sep_by_space = -2;
145 monetary->duo_int_n_cs_precedes = -2;
146 monetary->duo_int_n_sep_by_space = -2;
147 monetary->duo_int_p_sign_posn = -2;
148 monetary->duo_int_n_sign_posn = -2;
151 if (lr != NULL)
153 lr->translate_strings = 1;
154 lr->return_widestr = 0;
159 void
160 monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
162 struct locale_monetary_t *monetary
163 = locale->categories[LC_MONETARY].monetary;
164 int nothing = 0;
166 /* Now resolve copying and also handle completely missing definitions. */
167 if (monetary == NULL)
169 /* First see whether we were supposed to copy. If yes, find the
170 actual definition. */
171 if (locale->copy_name[LC_MONETARY] != NULL)
173 /* Find the copying locale. This has to happen transitively since
174 the locale we are copying from might also copying another one. */
175 struct localedef_t *from = locale;
178 from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
179 from->repertoire_name, charmap);
180 while (from->categories[LC_MONETARY].monetary == NULL
181 && from->copy_name[LC_MONETARY] != NULL);
183 monetary = locale->categories[LC_MONETARY].monetary
184 = from->categories[LC_MONETARY].monetary;
187 /* If there is still no definition issue an warning and create an
188 empty one. */
189 if (monetary == NULL)
191 if (! be_quiet)
192 WITH_CUR_LOCALE (error (0, 0, _("\
193 No definition for %s category found"), "LC_MONETARY"));
194 monetary_startup (NULL, locale, 0);
195 monetary = locale->categories[LC_MONETARY].monetary;
196 nothing = 1;
200 #define TEST_ELEM(cat, initval) \
201 if (monetary->cat == NULL) \
203 if (! be_quiet && ! nothing) \
204 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
205 "LC_MONETARY", #cat)); \
206 monetary->cat = initval; \
209 TEST_ELEM (int_curr_symbol, "");
210 TEST_ELEM (currency_symbol, "");
211 TEST_ELEM (mon_decimal_point, ".");
212 TEST_ELEM (mon_thousands_sep, "");
213 TEST_ELEM (positive_sign, "");
214 TEST_ELEM (negative_sign, "");
216 /* The international currency symbol must come from ISO 4217. */
217 if (monetary->int_curr_symbol != NULL)
219 if (strlen (monetary->int_curr_symbol) != 4)
221 if (! be_quiet && ! nothing)
222 WITH_CUR_LOCALE (error (0, 0, _("\
223 %s: value of field `int_curr_symbol' has wrong length"),
224 "LC_MONETARY"));
226 else
227 { /* Check the first three characters against ISO 4217 */
228 char symbol[4];
229 strncpy (symbol, monetary->int_curr_symbol, 3);
230 symbol[3] = '\0';
231 if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
232 sizeof (const char *),
233 (comparison_fn_t) curr_strcmp) == NULL
234 && !be_quiet)
235 WITH_CUR_LOCALE (error (0, 0, _("\
236 %s: value of field `int_curr_symbol' does \
237 not correspond to a valid name in ISO 4217"),
238 "LC_MONETARY"));
242 /* The decimal point must not be empty. This is not said explicitly
243 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
244 != "". */
245 if (monetary->mon_decimal_point == NULL)
247 if (! be_quiet && ! nothing)
248 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
249 "LC_MONETARY", "mon_decimal_point"));
250 monetary->mon_decimal_point = ".";
252 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
254 WITH_CUR_LOCALE (error (0, 0, _("\
255 %s: value for field `%s' must not be an empty string"),
256 "LC_MONETARY", "mon_decimal_point"));
258 if (monetary->mon_decimal_point_wc == L'\0')
259 monetary->mon_decimal_point_wc = L'.';
261 if (monetary->mon_grouping_len == 0)
263 if (! be_quiet && ! nothing)
264 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
265 "LC_MONETARY", "mon_grouping"));
267 monetary->mon_grouping = (char *) "\177";
268 monetary->mon_grouping_len = 1;
271 #undef TEST_ELEM
272 #define TEST_ELEM(cat, min, max, initval) \
273 if (monetary->cat == -2) \
275 if (! be_quiet && ! nothing) \
276 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
277 "LC_MONETARY", #cat)); \
278 monetary->cat = initval; \
280 else if ((monetary->cat < min || monetary->cat > max) \
281 && !be_quiet && !nothing) \
282 WITH_CUR_LOCALE (error (0, 0, _("\
283 %s: value for field `%s' must be in range %d...%d"), \
284 "LC_MONETARY", #cat, min, max))
286 TEST_ELEM (int_frac_digits, -128, 127, -1);
287 TEST_ELEM (frac_digits, -128, 127, -1);
288 TEST_ELEM (p_cs_precedes, -1, 1, -1);
289 TEST_ELEM (p_sep_by_space, -1, 2, -1);
290 TEST_ELEM (n_cs_precedes, -1, 1, -1);
291 TEST_ELEM (n_sep_by_space, -1, 2, -1);
292 TEST_ELEM (p_sign_posn, -1, 4, -1);
293 TEST_ELEM (n_sign_posn, -1, 4, -1);
295 /* The non-POSIX.2 extensions are optional. */
296 if (monetary->duo_int_curr_symbol == NULL)
297 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
298 if (monetary->duo_currency_symbol == NULL)
299 monetary->duo_currency_symbol = monetary->currency_symbol;
301 if (monetary->duo_int_frac_digits == -2)
302 monetary->duo_int_frac_digits = monetary->int_frac_digits;
303 if (monetary->duo_frac_digits == -2)
304 monetary->duo_frac_digits = monetary->frac_digits;
306 #undef TEST_ELEM
307 #define TEST_ELEM(cat, alt, min, max) \
308 if (monetary->cat == -2) \
309 monetary->cat = monetary->alt; \
310 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
311 && ! nothing) \
312 WITH_CUR_LOCALE (error (0, 0, _("\
313 %s: value for field `%s' must be in range %d...%d"), \
314 "LC_MONETARY", #cat, min, max))
316 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
317 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
318 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
319 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
320 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
321 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
323 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
324 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
325 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
326 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
327 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
328 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
329 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
330 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
331 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
332 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
333 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
334 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
336 if (monetary->uno_valid_from == 0)
337 monetary->uno_valid_from = 10101;
338 if (monetary->uno_valid_to == 0)
339 monetary->uno_valid_to = 99991231;
340 if (monetary->duo_valid_from == 0)
341 monetary->duo_valid_from = 10101;
342 if (monetary->duo_valid_to == 0)
343 monetary->duo_valid_to = 99991231;
345 if (monetary->conversion_rate[0] == 0)
347 monetary->conversion_rate[0] = 1;
348 monetary->conversion_rate[1] = 1;
351 /* Create the crncystr entry. */
352 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
353 + 2);
354 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
355 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
359 void
360 monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
361 const char *output_path)
363 struct locale_monetary_t *monetary
364 = locale->categories[LC_MONETARY].monetary;
365 struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
366 struct locale_file data;
367 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
368 size_t cnt = 0;
370 data.magic = LIMAGIC (LC_MONETARY);
371 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
372 iov[cnt].iov_base = (void *) &data;
373 iov[cnt].iov_len = sizeof (data);
374 ++cnt;
376 iov[cnt].iov_base = (void *) idx;
377 iov[cnt].iov_len = sizeof (idx);
378 ++cnt;
380 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
381 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
382 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
383 ++cnt;
385 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
386 iov[cnt].iov_base = (void *) monetary->currency_symbol;
387 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
388 ++cnt;
390 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
391 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
392 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
393 ++cnt;
395 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
396 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
397 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
398 ++cnt;
400 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
401 iov[cnt].iov_base = monetary->mon_grouping;
402 iov[cnt].iov_len = monetary->mon_grouping_len;
403 ++cnt;
405 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
406 iov[cnt].iov_base = (void *) monetary->positive_sign;
407 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
408 ++cnt;
410 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
411 iov[cnt].iov_base = (void *) monetary->negative_sign;
412 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
413 ++cnt;
415 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
416 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
417 iov[cnt].iov_len = 1;
418 ++cnt;
420 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
421 iov[cnt].iov_base = (void *) &monetary->frac_digits;
422 iov[cnt].iov_len = 1;
423 ++cnt;
425 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
426 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
427 iov[cnt].iov_len = 1;
428 ++cnt;
430 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
431 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
432 iov[cnt].iov_len = 1;
433 ++cnt;
435 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
436 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
437 iov[cnt].iov_len = 1;
438 ++cnt;
440 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
441 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
442 iov[cnt].iov_len = 1;
443 ++cnt;
445 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
446 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
447 iov[cnt].iov_len = 1;
448 ++cnt;
450 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
451 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
452 iov[cnt].iov_len = 1;
453 ++cnt;
455 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
456 iov[cnt].iov_base = (void *) monetary->crncystr;
457 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
458 ++cnt;
460 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
461 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
462 iov[cnt].iov_len = 1;
463 ++cnt;
465 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
466 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
467 iov[cnt].iov_len = 1;
468 ++cnt;
470 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
471 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
472 iov[cnt].iov_len = 1;
473 ++cnt;
475 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
476 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
477 iov[cnt].iov_len = 1;
478 ++cnt;
480 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
481 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
482 iov[cnt].iov_len = 1;
483 ++cnt;
485 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
486 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
487 iov[cnt].iov_len = 1;
488 ++cnt;
490 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
491 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
492 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
493 ++cnt;
495 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
496 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
497 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
498 ++cnt;
500 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
501 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
502 iov[cnt].iov_len = 1;
503 ++cnt;
505 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
506 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
507 iov[cnt].iov_len = 1;
508 ++cnt;
510 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
511 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
512 iov[cnt].iov_len = 1;
513 ++cnt;
515 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
516 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
517 iov[cnt].iov_len = 1;
518 ++cnt;
520 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
521 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
522 iov[cnt].iov_len = 1;
523 ++cnt;
525 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
526 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
527 iov[cnt].iov_len = 1;
528 ++cnt;
530 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
531 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
532 iov[cnt].iov_len = 1;
533 ++cnt;
535 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
536 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
537 iov[cnt].iov_len = 1;
538 ++cnt;
540 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
541 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
542 iov[cnt].iov_len = 1;
543 ++cnt;
545 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
546 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
547 iov[cnt].iov_len = 1;
548 ++cnt;
550 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
551 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
552 iov[cnt].iov_len = 1;
553 ++cnt;
555 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
556 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
557 iov[cnt].iov_len = 1;
558 ++cnt;
560 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
561 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
562 iov[cnt].iov_len = 1;
563 ++cnt;
565 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
566 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
567 iov[cnt].iov_len = 1;
568 ++cnt;
570 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
572 /* Align following data */
573 iov[cnt].iov_base = (void *) "\0\0";
574 iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
575 idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
576 ++cnt;
578 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
579 iov[cnt].iov_len = sizeof(uint32_t);
580 ++cnt;
582 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
583 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
584 iov[cnt].iov_len = sizeof(uint32_t);
585 ++cnt;
587 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
588 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
589 iov[cnt].iov_len = sizeof(uint32_t);
590 ++cnt;
592 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
593 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
594 iov[cnt].iov_len = sizeof(uint32_t);
595 ++cnt;
597 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
598 iov[cnt].iov_base = (void *) monetary->conversion_rate;
599 iov[cnt].iov_len = 2 * sizeof(uint32_t);
600 ++cnt;
602 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
603 iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
604 iov[cnt].iov_len = sizeof (uint32_t);
605 ++cnt;
607 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
608 iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
609 iov[cnt].iov_len = sizeof (uint32_t);
610 ++cnt;
612 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
613 iov[cnt].iov_base = (void *) charmap->code_set_name;
614 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
615 ++cnt;
617 assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
619 write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
620 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
624 static int
625 curr_strcmp (const char *s1, const char **s2)
627 return strcmp (s1, *s2);
631 /* The parser for the LC_MONETARY section of the locale definition. */
632 void
633 monetary_read (struct linereader *ldfile, struct localedef_t *result,
634 const struct charmap_t *charmap, const char *repertoire_name,
635 int ignore_content)
637 struct repertoire_t *repertoire = NULL;
638 struct locale_monetary_t *monetary;
639 struct token *now;
640 enum token_t nowtok;
642 /* Get the repertoire we have to use. */
643 if (repertoire_name != NULL)
644 repertoire = repertoire_read (repertoire_name);
646 /* The rest of the line containing `LC_MONETARY' must be free. */
647 lr_ignore_rest (ldfile, 1);
651 now = lr_token (ldfile, charmap, result, NULL, verbose);
652 nowtok = now->tok;
654 while (nowtok == tok_eol);
656 /* If we see `copy' now we are almost done. */
657 if (nowtok == tok_copy)
659 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
660 LC_MONETARY, "LC_MONETARY", ignore_content);
661 return;
664 /* Prepare the data structures. */
665 monetary_startup (ldfile, result, ignore_content);
666 monetary = result->categories[LC_MONETARY].monetary;
668 while (1)
670 /* Of course we don't proceed beyond the end of file. */
671 if (nowtok == tok_eof)
672 break;
674 /* Ignore empty lines. */
675 if (nowtok == tok_eol)
677 now = lr_token (ldfile, charmap, result, NULL, verbose);
678 nowtok = now->tok;
679 continue;
682 switch (nowtok)
684 #define STR_ELEM(cat) \
685 case tok_##cat: \
686 /* Ignore the rest of the line if we don't need the input of \
687 this line. */ \
688 if (ignore_content) \
690 lr_ignore_rest (ldfile, 0); \
691 break; \
694 now = lr_token (ldfile, charmap, result, NULL, verbose); \
695 if (now->tok != tok_string) \
696 goto err_label; \
697 else if (monetary->cat != NULL) \
698 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
699 "LC_MONETARY", #cat); \
700 else if (!ignore_content && now->val.str.startmb == NULL) \
702 lr_error (ldfile, _("\
703 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
704 monetary->cat = ""; \
706 else if (!ignore_content) \
707 monetary->cat = now->val.str.startmb; \
708 lr_ignore_rest (ldfile, 1); \
709 break
711 STR_ELEM (int_curr_symbol);
712 STR_ELEM (currency_symbol);
713 STR_ELEM (positive_sign);
714 STR_ELEM (negative_sign);
715 STR_ELEM (duo_int_curr_symbol);
716 STR_ELEM (duo_currency_symbol);
718 #define STR_ELEM_WC(cat) \
719 case tok_##cat: \
720 /* Ignore the rest of the line if we don't need the input of \
721 this line. */ \
722 if (ignore_content) \
724 lr_ignore_rest (ldfile, 0); \
725 break; \
728 ldfile->return_widestr = 1; \
729 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
730 if (now->tok != tok_string) \
731 goto err_label; \
732 if (monetary->cat != NULL) \
733 lr_error (ldfile, _("\
734 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
735 else if (!ignore_content && now->val.str.startmb == NULL) \
737 lr_error (ldfile, _("\
738 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
739 monetary->cat = ""; \
740 monetary->cat##_wc = L'\0'; \
742 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
744 lr_error (ldfile, _("\
745 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
747 else if (!ignore_content) \
749 monetary->cat = now->val.str.startmb; \
751 if (now->val.str.startwc != NULL) \
752 monetary->cat##_wc = *now->val.str.startwc; \
754 ldfile->return_widestr = 0; \
755 break
757 STR_ELEM_WC (mon_decimal_point);
758 STR_ELEM_WC (mon_thousands_sep);
760 #define INT_ELEM(cat) \
761 case tok_##cat: \
762 /* Ignore the rest of the line if we don't need the input of \
763 this line. */ \
764 if (ignore_content) \
766 lr_ignore_rest (ldfile, 0); \
767 break; \
770 now = lr_token (ldfile, charmap, result, NULL, verbose); \
771 if (now->tok != tok_minus1 && now->tok != tok_number) \
772 goto err_label; \
773 else if (monetary->cat != -2) \
774 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
775 "LC_MONETARY", #cat); \
776 else if (!ignore_content) \
777 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
778 break
780 INT_ELEM (int_frac_digits);
781 INT_ELEM (frac_digits);
782 INT_ELEM (p_cs_precedes);
783 INT_ELEM (p_sep_by_space);
784 INT_ELEM (n_cs_precedes);
785 INT_ELEM (n_sep_by_space);
786 INT_ELEM (p_sign_posn);
787 INT_ELEM (n_sign_posn);
788 INT_ELEM (int_p_cs_precedes);
789 INT_ELEM (int_p_sep_by_space);
790 INT_ELEM (int_n_cs_precedes);
791 INT_ELEM (int_n_sep_by_space);
792 INT_ELEM (int_p_sign_posn);
793 INT_ELEM (int_n_sign_posn);
794 INT_ELEM (duo_int_frac_digits);
795 INT_ELEM (duo_frac_digits);
796 INT_ELEM (duo_p_cs_precedes);
797 INT_ELEM (duo_p_sep_by_space);
798 INT_ELEM (duo_n_cs_precedes);
799 INT_ELEM (duo_n_sep_by_space);
800 INT_ELEM (duo_p_sign_posn);
801 INT_ELEM (duo_n_sign_posn);
802 INT_ELEM (duo_int_p_cs_precedes);
803 INT_ELEM (duo_int_p_sep_by_space);
804 INT_ELEM (duo_int_n_cs_precedes);
805 INT_ELEM (duo_int_n_sep_by_space);
806 INT_ELEM (duo_int_p_sign_posn);
807 INT_ELEM (duo_int_n_sign_posn);
808 INT_ELEM (uno_valid_from);
809 INT_ELEM (uno_valid_to);
810 INT_ELEM (duo_valid_from);
811 INT_ELEM (duo_valid_to);
813 case tok_mon_grouping:
814 /* Ignore the rest of the line if we don't need the input of
815 this line. */
816 if (ignore_content)
818 lr_ignore_rest (ldfile, 0);
819 break;
822 now = lr_token (ldfile, charmap, result, NULL, verbose);
823 if (now->tok != tok_minus1 && now->tok != tok_number)
824 goto err_label;
825 else
827 size_t act = 0;
828 size_t max = 10;
829 char *grouping = ignore_content ? NULL : xmalloc (max);
833 if (act + 1 >= max)
835 max *= 2;
836 grouping = xrealloc (grouping, max);
839 if (act > 0 && grouping[act - 1] == '\177')
841 lr_error (ldfile, _("\
842 %s: `-1' must be last entry in `%s' field"),
843 "LC_MONETARY", "mon_grouping");
844 lr_ignore_rest (ldfile, 0);
845 break;
848 if (now->tok == tok_minus1)
850 if (!ignore_content)
851 grouping[act++] = '\177';
853 else if (now->val.num == 0)
855 /* A value of 0 disables grouping from here on but
856 we must not store a NUL character since this
857 terminates the string. Use something different
858 which must not be used otherwise. */
859 if (!ignore_content)
860 grouping[act++] = '\377';
862 else if (now->val.num > 126)
863 lr_error (ldfile, _("\
864 %s: values for field `%s' must be smaller than 127"),
865 "LC_MONETARY", "mon_grouping");
866 else if (!ignore_content)
867 grouping[act++] = now->val.num;
869 /* Next must be semicolon. */
870 now = lr_token (ldfile, charmap, result, NULL, verbose);
871 if (now->tok != tok_semicolon)
872 break;
874 now = lr_token (ldfile, charmap, result, NULL, verbose);
876 while (now->tok == tok_minus1 || now->tok == tok_number);
878 if (now->tok != tok_eol)
879 goto err_label;
881 if (!ignore_content)
883 grouping[act++] = '\0';
885 monetary->mon_grouping = xrealloc (grouping, act);
886 monetary->mon_grouping_len = act;
889 break;
891 case tok_conversion_rate:
892 /* Ignore the rest of the line if we don't need the input of
893 this line. */
894 if (ignore_content)
896 lr_ignore_rest (ldfile, 0);
897 break;
900 now = lr_token (ldfile, charmap, result, NULL, verbose);
901 if (now->tok != tok_number)
902 goto err_label;
903 if (now->val.num == 0)
905 invalid_conversion_rate:
906 lr_error (ldfile, _("conversion rate value cannot be zero"));
907 if (!ignore_content)
909 monetary->conversion_rate[0] = 1;
910 monetary->conversion_rate[1] = 1;
912 break;
914 if (!ignore_content)
915 monetary->conversion_rate[0] = now->val.num;
916 /* Next must be a semicolon. */
917 now = lr_token (ldfile, charmap, result, NULL, verbose);
918 if (now->tok != tok_semicolon)
919 goto err_label;
920 /* And another number. */
921 now = lr_token (ldfile, charmap, result, NULL, verbose);
922 if (now->tok != tok_number)
923 goto err_label;
924 if (now->val.num == 0)
925 goto invalid_conversion_rate;
926 if (!ignore_content)
927 monetary->conversion_rate[1] = now->val.num;
928 /* The rest of the line must be empty. */
929 lr_ignore_rest (ldfile, 1);
930 break;
932 case tok_end:
933 /* Next we assume `LC_MONETARY'. */
934 now = lr_token (ldfile, charmap, result, NULL, verbose);
935 if (now->tok == tok_eof)
936 break;
937 if (now->tok == tok_eol)
938 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
939 else if (now->tok != tok_lc_monetary)
940 lr_error (ldfile, _("\
941 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
942 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
943 return;
945 default:
946 err_label:
947 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
950 /* Prepare for the next round. */
951 now = lr_token (ldfile, charmap, result, NULL, verbose);
952 nowtok = now->tok;
955 /* When we come here we reached the end of the file. */
956 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");