* locale/programs/charmap-dir.c (charmap_aliases): Use %ms instead of
[glibc/pb-stable.git] / locale / programs / ld-monetary.c
blobb8d291e7fc16ea8c060588eac15ddce70fabcf12
1 /* Copyright (C) 1995-1999,2000,2001,2002,2005,2007
2 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published
8 by the Free Software Foundation; version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
24 #include <byteswap.h>
25 #include <langinfo.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/uio.h>
31 #include <assert.h>
33 #include "localedef.h"
34 #include "linereader.h"
35 #include "localeinfo.h"
36 #include "locfile.h"
39 /* The real definition of the struct for the LC_MONETARY locale. */
40 struct locale_monetary_t
42 const char *int_curr_symbol;
43 const char *currency_symbol;
44 const char *mon_decimal_point;
45 const char *mon_thousands_sep;
46 uint32_t mon_decimal_point_wc;
47 uint32_t mon_thousands_sep_wc;
48 char *mon_grouping;
49 size_t mon_grouping_len;
50 const char *positive_sign;
51 const char *negative_sign;
52 signed char int_frac_digits;
53 signed char frac_digits;
54 signed char p_cs_precedes;
55 signed char p_sep_by_space;
56 signed char n_cs_precedes;
57 signed char n_sep_by_space;
58 signed char p_sign_posn;
59 signed char n_sign_posn;
60 signed char int_p_cs_precedes;
61 signed char int_p_sep_by_space;
62 signed char int_n_cs_precedes;
63 signed char int_n_sep_by_space;
64 signed char int_p_sign_posn;
65 signed char int_n_sign_posn;
66 const char *duo_int_curr_symbol;
67 const char *duo_currency_symbol;
68 signed char duo_int_frac_digits;
69 signed char duo_frac_digits;
70 signed char duo_p_cs_precedes;
71 signed char duo_p_sep_by_space;
72 signed char duo_n_cs_precedes;
73 signed char duo_n_sep_by_space;
74 signed char duo_p_sign_posn;
75 signed char duo_n_sign_posn;
76 signed char duo_int_p_cs_precedes;
77 signed char duo_int_p_sep_by_space;
78 signed char duo_int_n_cs_precedes;
79 signed char duo_int_n_sep_by_space;
80 signed char duo_int_p_sign_posn;
81 signed char duo_int_n_sign_posn;
82 uint32_t uno_valid_from;
83 uint32_t uno_valid_to;
84 uint32_t duo_valid_from;
85 uint32_t duo_valid_to;
86 uint32_t conversion_rate[2];
87 char *crncystr;
91 /* The content iof the field int_curr_symbol has to be taken from
92 ISO-4217. We test for correct values. */
93 #define DEFINE_INT_CURR(str) str,
94 static const char *const valid_int_curr[] =
96 # include "../iso-4217.def"
98 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
99 / sizeof (valid_int_curr[0])))
100 #undef DEFINE_INT_CURR
103 /* Prototypes for local functions. */
104 static int curr_strcmp (const char *s1, const char **s2);
107 static void
108 monetary_startup (struct linereader *lr, struct localedef_t *locale,
109 int ignore_content)
111 if (!ignore_content)
113 struct locale_monetary_t *monetary;
115 locale->categories[LC_MONETARY].monetary = monetary =
116 (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
118 memset (monetary, '\0', sizeof (struct locale_monetary_t));
120 monetary->mon_grouping = NULL;
121 monetary->mon_grouping_len = 0;
123 monetary->int_frac_digits = -2;
124 monetary->frac_digits = -2;
125 monetary->p_cs_precedes = -2;
126 monetary->p_sep_by_space = -2;
127 monetary->n_cs_precedes = -2;
128 monetary->n_sep_by_space = -2;
129 monetary->p_sign_posn = -2;
130 monetary->n_sign_posn = -2;
131 monetary->int_p_cs_precedes = -2;
132 monetary->int_p_sep_by_space = -2;
133 monetary->int_n_cs_precedes = -2;
134 monetary->int_n_sep_by_space = -2;
135 monetary->int_p_sign_posn = -2;
136 monetary->int_n_sign_posn = -2;
137 monetary->duo_int_frac_digits = -2;
138 monetary->duo_frac_digits = -2;
139 monetary->duo_p_cs_precedes = -2;
140 monetary->duo_p_sep_by_space = -2;
141 monetary->duo_n_cs_precedes = -2;
142 monetary->duo_n_sep_by_space = -2;
143 monetary->duo_p_sign_posn = -2;
144 monetary->duo_n_sign_posn = -2;
145 monetary->duo_int_p_cs_precedes = -2;
146 monetary->duo_int_p_sep_by_space = -2;
147 monetary->duo_int_n_cs_precedes = -2;
148 monetary->duo_int_n_sep_by_space = -2;
149 monetary->duo_int_p_sign_posn = -2;
150 monetary->duo_int_n_sign_posn = -2;
153 if (lr != NULL)
155 lr->translate_strings = 1;
156 lr->return_widestr = 0;
161 void
162 monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
164 struct locale_monetary_t *monetary
165 = locale->categories[LC_MONETARY].monetary;
166 int nothing = 0;
168 /* Now resolve copying and also handle completely missing definitions. */
169 if (monetary == NULL)
171 /* First see whether we were supposed to copy. If yes, find the
172 actual definition. */
173 if (locale->copy_name[LC_MONETARY] != NULL)
175 /* Find the copying locale. This has to happen transitively since
176 the locale we are copying from might also copying another one. */
177 struct localedef_t *from = locale;
180 from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
181 from->repertoire_name, charmap);
182 while (from->categories[LC_MONETARY].monetary == NULL
183 && from->copy_name[LC_MONETARY] != NULL);
185 monetary = locale->categories[LC_MONETARY].monetary
186 = from->categories[LC_MONETARY].monetary;
189 /* If there is still no definition issue an warning and create an
190 empty one. */
191 if (monetary == NULL)
193 if (! be_quiet)
194 WITH_CUR_LOCALE (error (0, 0, _("\
195 No definition for %s category found"), "LC_MONETARY"));
196 monetary_startup (NULL, locale, 0);
197 monetary = locale->categories[LC_MONETARY].monetary;
198 nothing = 1;
202 #define TEST_ELEM(cat, initval) \
203 if (monetary->cat == NULL) \
205 if (! be_quiet && ! nothing) \
206 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
207 "LC_MONETARY", #cat)); \
208 monetary->cat = initval; \
211 TEST_ELEM (int_curr_symbol, "");
212 TEST_ELEM (currency_symbol, "");
213 TEST_ELEM (mon_decimal_point, ".");
214 TEST_ELEM (mon_thousands_sep, "");
215 TEST_ELEM (positive_sign, "");
216 TEST_ELEM (negative_sign, "");
218 /* The international currency symbol must come from ISO 4217. */
219 if (monetary->int_curr_symbol != NULL)
221 if (strlen (monetary->int_curr_symbol) != 4)
223 if (! be_quiet && ! nothing)
224 WITH_CUR_LOCALE (error (0, 0, _("\
225 %s: value of field `int_curr_symbol' has wrong length"),
226 "LC_MONETARY"));
228 else
229 { /* Check the first three characters against ISO 4217 */
230 char symbol[4];
231 strncpy (symbol, monetary->int_curr_symbol, 3);
232 symbol[3] = '\0';
233 if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
234 sizeof (const char *),
235 (comparison_fn_t) curr_strcmp) == NULL
236 && !be_quiet)
237 WITH_CUR_LOCALE (error (0, 0, _("\
238 %s: value of field `int_curr_symbol' does \
239 not correspond to a valid name in ISO 4217"),
240 "LC_MONETARY"));
244 /* The decimal point must not be empty. This is not said explicitly
245 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
246 != "". */
247 if (monetary->mon_decimal_point == NULL)
249 if (! be_quiet && ! nothing)
250 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
251 "LC_MONETARY", "mon_decimal_point"));
252 monetary->mon_decimal_point = ".";
254 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
256 WITH_CUR_LOCALE (error (0, 0, _("\
257 %s: value for field `%s' must not be an empty string"),
258 "LC_MONETARY", "mon_decimal_point"));
260 if (monetary->mon_decimal_point_wc == L'\0')
261 monetary->mon_decimal_point_wc = L'.';
263 if (monetary->mon_grouping_len == 0)
265 if (! be_quiet && ! nothing)
266 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
267 "LC_MONETARY", "mon_grouping"));
269 monetary->mon_grouping = (char *) "\177";
270 monetary->mon_grouping_len = 1;
273 #undef TEST_ELEM
274 #define TEST_ELEM(cat, min, max, initval) \
275 if (monetary->cat == -2) \
277 if (! be_quiet && ! nothing) \
278 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
279 "LC_MONETARY", #cat)); \
280 monetary->cat = initval; \
282 else if ((monetary->cat < min || monetary->cat > max) \
283 && min < max \
284 && !be_quiet && !nothing) \
285 WITH_CUR_LOCALE (error (0, 0, _("\
286 %s: value for field `%s' must be in range %d...%d"), \
287 "LC_MONETARY", #cat, min, max))
289 TEST_ELEM (int_frac_digits, 1, 0, -1);
290 TEST_ELEM (frac_digits, 1, 0, -1);
291 TEST_ELEM (p_cs_precedes, -1, 1, -1);
292 TEST_ELEM (p_sep_by_space, -1, 2, -1);
293 TEST_ELEM (n_cs_precedes, -1, 1, -1);
294 TEST_ELEM (n_sep_by_space, -1, 2, -1);
295 TEST_ELEM (p_sign_posn, -1, 4, -1);
296 TEST_ELEM (n_sign_posn, -1, 4, -1);
298 /* The non-POSIX.2 extensions are optional. */
299 if (monetary->duo_int_curr_symbol == NULL)
300 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
301 if (monetary->duo_currency_symbol == NULL)
302 monetary->duo_currency_symbol = monetary->currency_symbol;
304 if (monetary->duo_int_frac_digits == -2)
305 monetary->duo_int_frac_digits = monetary->int_frac_digits;
306 if (monetary->duo_frac_digits == -2)
307 monetary->duo_frac_digits = monetary->frac_digits;
309 #undef TEST_ELEM
310 #define TEST_ELEM(cat, alt, min, max) \
311 if (monetary->cat == -2) \
312 monetary->cat = monetary->alt; \
313 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
314 && ! nothing) \
315 WITH_CUR_LOCALE (error (0, 0, _("\
316 %s: value for field `%s' must be in range %d...%d"), \
317 "LC_MONETARY", #cat, min, max))
319 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
320 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
321 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
322 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
323 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
324 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
326 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
327 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
328 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
329 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
330 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
331 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
332 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
333 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
334 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
335 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
336 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
337 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
339 if (monetary->uno_valid_from == 0)
340 monetary->uno_valid_from = 10101;
341 if (monetary->uno_valid_to == 0)
342 monetary->uno_valid_to = 99991231;
343 if (monetary->duo_valid_from == 0)
344 monetary->duo_valid_from = 10101;
345 if (monetary->duo_valid_to == 0)
346 monetary->duo_valid_to = 99991231;
348 if (monetary->conversion_rate[0] == 0)
350 monetary->conversion_rate[0] = 1;
351 monetary->conversion_rate[1] = 1;
354 /* Create the crncystr entry. */
355 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
356 + 2);
357 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
358 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
362 void
363 monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
364 const char *output_path)
366 struct locale_monetary_t *monetary
367 = locale->categories[LC_MONETARY].monetary;
368 struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
369 struct locale_file data;
370 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
371 size_t cnt = 0;
373 data.magic = LIMAGIC (LC_MONETARY);
374 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
375 iov[cnt].iov_base = (void *) &data;
376 iov[cnt].iov_len = sizeof (data);
377 ++cnt;
379 iov[cnt].iov_base = (void *) idx;
380 iov[cnt].iov_len = sizeof (idx);
381 ++cnt;
383 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
384 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
385 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
386 ++cnt;
388 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
389 iov[cnt].iov_base = (void *) monetary->currency_symbol;
390 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
391 ++cnt;
393 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
394 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
395 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
396 ++cnt;
398 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
399 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
400 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
401 ++cnt;
403 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
404 iov[cnt].iov_base = monetary->mon_grouping;
405 iov[cnt].iov_len = monetary->mon_grouping_len;
406 ++cnt;
408 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
409 iov[cnt].iov_base = (void *) monetary->positive_sign;
410 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
411 ++cnt;
413 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
414 iov[cnt].iov_base = (void *) monetary->negative_sign;
415 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
416 ++cnt;
418 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
419 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
420 iov[cnt].iov_len = 1;
421 ++cnt;
423 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
424 iov[cnt].iov_base = (void *) &monetary->frac_digits;
425 iov[cnt].iov_len = 1;
426 ++cnt;
428 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
429 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
430 iov[cnt].iov_len = 1;
431 ++cnt;
433 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
434 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
435 iov[cnt].iov_len = 1;
436 ++cnt;
438 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
439 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
440 iov[cnt].iov_len = 1;
441 ++cnt;
443 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
444 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
445 iov[cnt].iov_len = 1;
446 ++cnt;
448 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
449 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
450 iov[cnt].iov_len = 1;
451 ++cnt;
453 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
454 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
455 iov[cnt].iov_len = 1;
456 ++cnt;
458 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
459 iov[cnt].iov_base = (void *) monetary->crncystr;
460 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
461 ++cnt;
463 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
464 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
465 iov[cnt].iov_len = 1;
466 ++cnt;
468 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
469 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
470 iov[cnt].iov_len = 1;
471 ++cnt;
473 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
474 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
475 iov[cnt].iov_len = 1;
476 ++cnt;
478 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
479 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
480 iov[cnt].iov_len = 1;
481 ++cnt;
483 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
484 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
485 iov[cnt].iov_len = 1;
486 ++cnt;
488 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
489 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
490 iov[cnt].iov_len = 1;
491 ++cnt;
493 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
494 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
495 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
496 ++cnt;
498 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
499 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
500 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
501 ++cnt;
503 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
504 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
505 iov[cnt].iov_len = 1;
506 ++cnt;
508 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
509 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
510 iov[cnt].iov_len = 1;
511 ++cnt;
513 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
514 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
515 iov[cnt].iov_len = 1;
516 ++cnt;
518 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
519 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
520 iov[cnt].iov_len = 1;
521 ++cnt;
523 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
524 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
525 iov[cnt].iov_len = 1;
526 ++cnt;
528 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
529 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
530 iov[cnt].iov_len = 1;
531 ++cnt;
533 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
534 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
535 iov[cnt].iov_len = 1;
536 ++cnt;
538 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
539 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
540 iov[cnt].iov_len = 1;
541 ++cnt;
543 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
544 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
545 iov[cnt].iov_len = 1;
546 ++cnt;
548 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
549 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
550 iov[cnt].iov_len = 1;
551 ++cnt;
553 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
554 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
555 iov[cnt].iov_len = 1;
556 ++cnt;
558 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
559 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
560 iov[cnt].iov_len = 1;
561 ++cnt;
563 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
564 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
565 iov[cnt].iov_len = 1;
566 ++cnt;
568 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
569 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
570 iov[cnt].iov_len = 1;
571 ++cnt;
573 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
575 /* Align following data */
576 iov[cnt].iov_base = (void *) "\0\0";
577 iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
578 idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
579 ++cnt;
581 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
582 iov[cnt].iov_len = sizeof(uint32_t);
583 ++cnt;
585 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
586 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
587 iov[cnt].iov_len = sizeof(uint32_t);
588 ++cnt;
590 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
591 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
592 iov[cnt].iov_len = sizeof(uint32_t);
593 ++cnt;
595 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
596 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
597 iov[cnt].iov_len = sizeof(uint32_t);
598 ++cnt;
600 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
601 iov[cnt].iov_base = (void *) monetary->conversion_rate;
602 iov[cnt].iov_len = 2 * sizeof(uint32_t);
603 ++cnt;
605 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
606 iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
607 iov[cnt].iov_len = sizeof (uint32_t);
608 ++cnt;
610 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
611 iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
612 iov[cnt].iov_len = sizeof (uint32_t);
613 ++cnt;
615 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
616 iov[cnt].iov_base = (void *) charmap->code_set_name;
617 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
618 ++cnt;
620 assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
622 write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
623 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
627 static int
628 curr_strcmp (const char *s1, const char **s2)
630 return strcmp (s1, *s2);
634 /* The parser for the LC_MONETARY section of the locale definition. */
635 void
636 monetary_read (struct linereader *ldfile, struct localedef_t *result,
637 const struct charmap_t *charmap, const char *repertoire_name,
638 int ignore_content)
640 struct repertoire_t *repertoire = NULL;
641 struct locale_monetary_t *monetary;
642 struct token *now;
643 enum token_t nowtok;
645 /* Get the repertoire we have to use. */
646 if (repertoire_name != NULL)
647 repertoire = repertoire_read (repertoire_name);
649 /* The rest of the line containing `LC_MONETARY' must be free. */
650 lr_ignore_rest (ldfile, 1);
654 now = lr_token (ldfile, charmap, result, NULL, verbose);
655 nowtok = now->tok;
657 while (nowtok == tok_eol);
659 /* If we see `copy' now we are almost done. */
660 if (nowtok == tok_copy)
662 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
663 LC_MONETARY, "LC_MONETARY", ignore_content);
664 return;
667 /* Prepare the data structures. */
668 monetary_startup (ldfile, result, ignore_content);
669 monetary = result->categories[LC_MONETARY].monetary;
671 while (1)
673 /* Of course we don't proceed beyond the end of file. */
674 if (nowtok == tok_eof)
675 break;
677 /* Ignore empty lines. */
678 if (nowtok == tok_eol)
680 now = lr_token (ldfile, charmap, result, NULL, verbose);
681 nowtok = now->tok;
682 continue;
685 switch (nowtok)
687 #define STR_ELEM(cat) \
688 case tok_##cat: \
689 /* Ignore the rest of the line if we don't need the input of \
690 this line. */ \
691 if (ignore_content) \
693 lr_ignore_rest (ldfile, 0); \
694 break; \
697 now = lr_token (ldfile, charmap, result, NULL, verbose); \
698 if (now->tok != tok_string) \
699 goto err_label; \
700 else if (monetary->cat != NULL) \
701 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
702 "LC_MONETARY", #cat); \
703 else if (!ignore_content && now->val.str.startmb == NULL) \
705 lr_error (ldfile, _("\
706 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
707 monetary->cat = ""; \
709 else if (!ignore_content) \
710 monetary->cat = now->val.str.startmb; \
711 lr_ignore_rest (ldfile, 1); \
712 break
714 STR_ELEM (int_curr_symbol);
715 STR_ELEM (currency_symbol);
716 STR_ELEM (positive_sign);
717 STR_ELEM (negative_sign);
718 STR_ELEM (duo_int_curr_symbol);
719 STR_ELEM (duo_currency_symbol);
721 #define STR_ELEM_WC(cat) \
722 case tok_##cat: \
723 /* Ignore the rest of the line if we don't need the input of \
724 this line. */ \
725 if (ignore_content) \
727 lr_ignore_rest (ldfile, 0); \
728 break; \
731 ldfile->return_widestr = 1; \
732 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
733 if (now->tok != tok_string) \
734 goto err_label; \
735 if (monetary->cat != NULL) \
736 lr_error (ldfile, _("\
737 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
738 else if (!ignore_content && now->val.str.startmb == NULL) \
740 lr_error (ldfile, _("\
741 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
742 monetary->cat = ""; \
743 monetary->cat##_wc = L'\0'; \
745 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
747 lr_error (ldfile, _("\
748 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
750 else if (!ignore_content) \
752 monetary->cat = now->val.str.startmb; \
754 if (now->val.str.startwc != NULL) \
755 monetary->cat##_wc = *now->val.str.startwc; \
757 ldfile->return_widestr = 0; \
758 break
760 STR_ELEM_WC (mon_decimal_point);
761 STR_ELEM_WC (mon_thousands_sep);
763 #define INT_ELEM(cat) \
764 case tok_##cat: \
765 /* Ignore the rest of the line if we don't need the input of \
766 this line. */ \
767 if (ignore_content) \
769 lr_ignore_rest (ldfile, 0); \
770 break; \
773 now = lr_token (ldfile, charmap, result, NULL, verbose); \
774 if (now->tok != tok_minus1 && now->tok != tok_number) \
775 goto err_label; \
776 else if (monetary->cat != -2) \
777 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
778 "LC_MONETARY", #cat); \
779 else if (!ignore_content) \
780 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
781 break
783 INT_ELEM (int_frac_digits);
784 INT_ELEM (frac_digits);
785 INT_ELEM (p_cs_precedes);
786 INT_ELEM (p_sep_by_space);
787 INT_ELEM (n_cs_precedes);
788 INT_ELEM (n_sep_by_space);
789 INT_ELEM (p_sign_posn);
790 INT_ELEM (n_sign_posn);
791 INT_ELEM (int_p_cs_precedes);
792 INT_ELEM (int_p_sep_by_space);
793 INT_ELEM (int_n_cs_precedes);
794 INT_ELEM (int_n_sep_by_space);
795 INT_ELEM (int_p_sign_posn);
796 INT_ELEM (int_n_sign_posn);
797 INT_ELEM (duo_int_frac_digits);
798 INT_ELEM (duo_frac_digits);
799 INT_ELEM (duo_p_cs_precedes);
800 INT_ELEM (duo_p_sep_by_space);
801 INT_ELEM (duo_n_cs_precedes);
802 INT_ELEM (duo_n_sep_by_space);
803 INT_ELEM (duo_p_sign_posn);
804 INT_ELEM (duo_n_sign_posn);
805 INT_ELEM (duo_int_p_cs_precedes);
806 INT_ELEM (duo_int_p_sep_by_space);
807 INT_ELEM (duo_int_n_cs_precedes);
808 INT_ELEM (duo_int_n_sep_by_space);
809 INT_ELEM (duo_int_p_sign_posn);
810 INT_ELEM (duo_int_n_sign_posn);
811 INT_ELEM (uno_valid_from);
812 INT_ELEM (uno_valid_to);
813 INT_ELEM (duo_valid_from);
814 INT_ELEM (duo_valid_to);
816 case tok_mon_grouping:
817 /* Ignore the rest of the line if we don't need the input of
818 this line. */
819 if (ignore_content)
821 lr_ignore_rest (ldfile, 0);
822 break;
825 now = lr_token (ldfile, charmap, result, NULL, verbose);
826 if (now->tok != tok_minus1 && now->tok != tok_number)
827 goto err_label;
828 else
830 size_t act = 0;
831 size_t max = 10;
832 char *grouping = ignore_content ? NULL : xmalloc (max);
836 if (act + 1 >= max)
838 max *= 2;
839 grouping = xrealloc (grouping, max);
842 if (act > 0 && grouping[act - 1] == '\177')
844 lr_error (ldfile, _("\
845 %s: `-1' must be last entry in `%s' field"),
846 "LC_MONETARY", "mon_grouping");
847 lr_ignore_rest (ldfile, 0);
848 break;
851 if (now->tok == tok_minus1)
853 if (!ignore_content)
854 grouping[act++] = '\177';
856 else if (now->val.num == 0)
858 /* A value of 0 disables grouping from here on but
859 we must not store a NUL character since this
860 terminates the string. Use something different
861 which must not be used otherwise. */
862 if (!ignore_content)
863 grouping[act++] = '\377';
865 else if (now->val.num > 126)
866 lr_error (ldfile, _("\
867 %s: values for field `%s' must be smaller than 127"),
868 "LC_MONETARY", "mon_grouping");
869 else if (!ignore_content)
870 grouping[act++] = now->val.num;
872 /* Next must be semicolon. */
873 now = lr_token (ldfile, charmap, result, NULL, verbose);
874 if (now->tok != tok_semicolon)
875 break;
877 now = lr_token (ldfile, charmap, result, NULL, verbose);
879 while (now->tok == tok_minus1 || now->tok == tok_number);
881 if (now->tok != tok_eol)
882 goto err_label;
884 if (!ignore_content)
886 grouping[act++] = '\0';
888 monetary->mon_grouping = xrealloc (grouping, act);
889 monetary->mon_grouping_len = act;
892 break;
894 case tok_conversion_rate:
895 /* Ignore the rest of the line if we don't need the input of
896 this line. */
897 if (ignore_content)
899 lr_ignore_rest (ldfile, 0);
900 break;
903 now = lr_token (ldfile, charmap, result, NULL, verbose);
904 if (now->tok != tok_number)
905 goto err_label;
906 if (now->val.num == 0)
908 invalid_conversion_rate:
909 lr_error (ldfile, _("conversion rate value cannot be zero"));
910 if (!ignore_content)
912 monetary->conversion_rate[0] = 1;
913 monetary->conversion_rate[1] = 1;
915 break;
917 if (!ignore_content)
918 monetary->conversion_rate[0] = now->val.num;
919 /* Next must be a semicolon. */
920 now = lr_token (ldfile, charmap, result, NULL, verbose);
921 if (now->tok != tok_semicolon)
922 goto err_label;
923 /* And another number. */
924 now = lr_token (ldfile, charmap, result, NULL, verbose);
925 if (now->tok != tok_number)
926 goto err_label;
927 if (now->val.num == 0)
928 goto invalid_conversion_rate;
929 if (!ignore_content)
930 monetary->conversion_rate[1] = now->val.num;
931 /* The rest of the line must be empty. */
932 lr_ignore_rest (ldfile, 1);
933 break;
935 case tok_end:
936 /* Next we assume `LC_MONETARY'. */
937 now = lr_token (ldfile, charmap, result, NULL, verbose);
938 if (now->tok == tok_eof)
939 break;
940 if (now->tok == tok_eol)
941 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
942 else if (now->tok != tok_lc_monetary)
943 lr_error (ldfile, _("\
944 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
945 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
946 return;
948 default:
949 err_label:
950 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
953 /* Prepare for the next round. */
954 now = lr_token (ldfile, charmap, result, NULL, verbose);
955 nowtok = now->tok;
958 /* When we come here we reached the end of the file. */
959 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");