PowerPC: remove branch prediction from rint implementation
[glibc.git] / locale / programs / ld-monetary.c
blob07e7b3f3f59ca107a191c39aaee0e99cc68747ec
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, see <http://www.gnu.org/licenses/>. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <byteswap.h>
24 #include <langinfo.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/uio.h>
30 #include <assert.h>
32 #include "localedef.h"
33 #include "linereader.h"
34 #include "localeinfo.h"
35 #include "locfile.h"
38 /* The real definition of the struct for the LC_MONETARY locale. */
39 struct locale_monetary_t
41 const char *int_curr_symbol;
42 const char *currency_symbol;
43 const char *mon_decimal_point;
44 const char *mon_thousands_sep;
45 uint32_t mon_decimal_point_wc;
46 uint32_t mon_thousands_sep_wc;
47 char *mon_grouping;
48 size_t mon_grouping_len;
49 const char *positive_sign;
50 const char *negative_sign;
51 signed char int_frac_digits;
52 signed char frac_digits;
53 signed char p_cs_precedes;
54 signed char p_sep_by_space;
55 signed char n_cs_precedes;
56 signed char n_sep_by_space;
57 signed char p_sign_posn;
58 signed char n_sign_posn;
59 signed char int_p_cs_precedes;
60 signed char int_p_sep_by_space;
61 signed char int_n_cs_precedes;
62 signed char int_n_sep_by_space;
63 signed char int_p_sign_posn;
64 signed char int_n_sign_posn;
65 const char *duo_int_curr_symbol;
66 const char *duo_currency_symbol;
67 signed char duo_int_frac_digits;
68 signed char duo_frac_digits;
69 signed char duo_p_cs_precedes;
70 signed char duo_p_sep_by_space;
71 signed char duo_n_cs_precedes;
72 signed char duo_n_sep_by_space;
73 signed char duo_p_sign_posn;
74 signed char duo_n_sign_posn;
75 signed char duo_int_p_cs_precedes;
76 signed char duo_int_p_sep_by_space;
77 signed char duo_int_n_cs_precedes;
78 signed char duo_int_n_sep_by_space;
79 signed char duo_int_p_sign_posn;
80 signed char duo_int_n_sign_posn;
81 uint32_t uno_valid_from;
82 uint32_t uno_valid_to;
83 uint32_t duo_valid_from;
84 uint32_t duo_valid_to;
85 uint32_t conversion_rate[2];
86 char *crncystr;
90 /* The content iof the field int_curr_symbol has to be taken from
91 ISO-4217. We test for correct values. */
92 #define DEFINE_INT_CURR(str) str,
93 static const char *const valid_int_curr[] =
95 # include "../iso-4217.def"
97 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
98 / sizeof (valid_int_curr[0])))
99 #undef DEFINE_INT_CURR
102 /* Prototypes for local functions. */
103 static int curr_strcmp (const char *s1, const char **s2);
106 static void
107 monetary_startup (struct linereader *lr, struct localedef_t *locale,
108 int ignore_content)
110 if (!ignore_content)
112 struct locale_monetary_t *monetary;
114 locale->categories[LC_MONETARY].monetary = monetary =
115 (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
117 memset (monetary, '\0', sizeof (struct locale_monetary_t));
119 monetary->mon_grouping = NULL;
120 monetary->mon_grouping_len = 0;
122 monetary->int_frac_digits = -2;
123 monetary->frac_digits = -2;
124 monetary->p_cs_precedes = -2;
125 monetary->p_sep_by_space = -2;
126 monetary->n_cs_precedes = -2;
127 monetary->n_sep_by_space = -2;
128 monetary->p_sign_posn = -2;
129 monetary->n_sign_posn = -2;
130 monetary->int_p_cs_precedes = -2;
131 monetary->int_p_sep_by_space = -2;
132 monetary->int_n_cs_precedes = -2;
133 monetary->int_n_sep_by_space = -2;
134 monetary->int_p_sign_posn = -2;
135 monetary->int_n_sign_posn = -2;
136 monetary->duo_int_frac_digits = -2;
137 monetary->duo_frac_digits = -2;
138 monetary->duo_p_cs_precedes = -2;
139 monetary->duo_p_sep_by_space = -2;
140 monetary->duo_n_cs_precedes = -2;
141 monetary->duo_n_sep_by_space = -2;
142 monetary->duo_p_sign_posn = -2;
143 monetary->duo_n_sign_posn = -2;
144 monetary->duo_int_p_cs_precedes = -2;
145 monetary->duo_int_p_sep_by_space = -2;
146 monetary->duo_int_n_cs_precedes = -2;
147 monetary->duo_int_n_sep_by_space = -2;
148 monetary->duo_int_p_sign_posn = -2;
149 monetary->duo_int_n_sign_posn = -2;
152 if (lr != NULL)
154 lr->translate_strings = 1;
155 lr->return_widestr = 0;
160 void
161 monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
163 struct locale_monetary_t *monetary
164 = locale->categories[LC_MONETARY].monetary;
165 int nothing = 0;
167 /* Now resolve copying and also handle completely missing definitions. */
168 if (monetary == NULL)
170 /* First see whether we were supposed to copy. If yes, find the
171 actual definition. */
172 if (locale->copy_name[LC_MONETARY] != NULL)
174 /* Find the copying locale. This has to happen transitively since
175 the locale we are copying from might also copying another one. */
176 struct localedef_t *from = locale;
179 from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
180 from->repertoire_name, charmap);
181 while (from->categories[LC_MONETARY].monetary == NULL
182 && from->copy_name[LC_MONETARY] != NULL);
184 monetary = locale->categories[LC_MONETARY].monetary
185 = from->categories[LC_MONETARY].monetary;
188 /* If there is still no definition issue an warning and create an
189 empty one. */
190 if (monetary == NULL)
192 if (! be_quiet)
193 WITH_CUR_LOCALE (error (0, 0, _("\
194 No definition for %s category found"), "LC_MONETARY"));
195 monetary_startup (NULL, locale, 0);
196 monetary = locale->categories[LC_MONETARY].monetary;
197 nothing = 1;
201 #define TEST_ELEM(cat, initval) \
202 if (monetary->cat == NULL) \
204 if (! be_quiet && ! nothing) \
205 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
206 "LC_MONETARY", #cat)); \
207 monetary->cat = initval; \
210 TEST_ELEM (int_curr_symbol, "");
211 TEST_ELEM (currency_symbol, "");
212 TEST_ELEM (mon_decimal_point, ".");
213 TEST_ELEM (mon_thousands_sep, "");
214 TEST_ELEM (positive_sign, "");
215 TEST_ELEM (negative_sign, "");
217 /* The international currency symbol must come from ISO 4217. */
218 if (monetary->int_curr_symbol != NULL)
220 if (strlen (monetary->int_curr_symbol) != 4)
222 if (! be_quiet && ! nothing)
223 WITH_CUR_LOCALE (error (0, 0, _("\
224 %s: value of field `int_curr_symbol' has wrong length"),
225 "LC_MONETARY"));
227 else
228 { /* Check the first three characters against ISO 4217 */
229 char symbol[4];
230 strncpy (symbol, monetary->int_curr_symbol, 3);
231 symbol[3] = '\0';
232 if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
233 sizeof (const char *),
234 (comparison_fn_t) curr_strcmp) == NULL
235 && !be_quiet)
236 WITH_CUR_LOCALE (error (0, 0, _("\
237 %s: value of field `int_curr_symbol' does \
238 not correspond to a valid name in ISO 4217"),
239 "LC_MONETARY"));
243 /* The decimal point must not be empty. This is not said explicitly
244 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
245 != "". */
246 if (monetary->mon_decimal_point == NULL)
248 if (! be_quiet && ! nothing)
249 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
250 "LC_MONETARY", "mon_decimal_point"));
251 monetary->mon_decimal_point = ".";
253 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
255 WITH_CUR_LOCALE (error (0, 0, _("\
256 %s: value for field `%s' must not be an empty string"),
257 "LC_MONETARY", "mon_decimal_point"));
259 if (monetary->mon_decimal_point_wc == L'\0')
260 monetary->mon_decimal_point_wc = L'.';
262 if (monetary->mon_grouping_len == 0)
264 if (! be_quiet && ! nothing)
265 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
266 "LC_MONETARY", "mon_grouping"));
268 monetary->mon_grouping = (char *) "\177";
269 monetary->mon_grouping_len = 1;
272 #undef TEST_ELEM
273 #define TEST_ELEM(cat, min, max, initval) \
274 if (monetary->cat == -2) \
276 if (! be_quiet && ! nothing) \
277 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
278 "LC_MONETARY", #cat)); \
279 monetary->cat = initval; \
281 else if ((monetary->cat < min || monetary->cat > max) \
282 && min < max \
283 && !be_quiet && !nothing) \
284 WITH_CUR_LOCALE (error (0, 0, _("\
285 %s: value for field `%s' must be in range %d...%d"), \
286 "LC_MONETARY", #cat, min, max))
288 TEST_ELEM (int_frac_digits, 1, 0, -1);
289 TEST_ELEM (frac_digits, 1, 0, -1);
290 TEST_ELEM (p_cs_precedes, -1, 1, -1);
291 TEST_ELEM (p_sep_by_space, -1, 2, -1);
292 TEST_ELEM (n_cs_precedes, -1, 1, -1);
293 TEST_ELEM (n_sep_by_space, -1, 2, -1);
294 TEST_ELEM (p_sign_posn, -1, 4, -1);
295 TEST_ELEM (n_sign_posn, -1, 4, -1);
297 /* The non-POSIX.2 extensions are optional. */
298 if (monetary->duo_int_curr_symbol == NULL)
299 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
300 if (monetary->duo_currency_symbol == NULL)
301 monetary->duo_currency_symbol = monetary->currency_symbol;
303 if (monetary->duo_int_frac_digits == -2)
304 monetary->duo_int_frac_digits = monetary->int_frac_digits;
305 if (monetary->duo_frac_digits == -2)
306 monetary->duo_frac_digits = monetary->frac_digits;
308 #undef TEST_ELEM
309 #define TEST_ELEM(cat, alt, min, max) \
310 if (monetary->cat == -2) \
311 monetary->cat = monetary->alt; \
312 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
313 && ! nothing) \
314 WITH_CUR_LOCALE (error (0, 0, _("\
315 %s: value for field `%s' must be in range %d...%d"), \
316 "LC_MONETARY", #cat, min, max))
318 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
319 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
320 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
321 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
322 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
323 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
325 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
326 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
327 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
328 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
329 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
330 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
331 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
332 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
333 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
334 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
335 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
336 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
338 if (monetary->uno_valid_from == 0)
339 monetary->uno_valid_from = 10101;
340 if (monetary->uno_valid_to == 0)
341 monetary->uno_valid_to = 99991231;
342 if (monetary->duo_valid_from == 0)
343 monetary->duo_valid_from = 10101;
344 if (monetary->duo_valid_to == 0)
345 monetary->duo_valid_to = 99991231;
347 if (monetary->conversion_rate[0] == 0)
349 monetary->conversion_rate[0] = 1;
350 monetary->conversion_rate[1] = 1;
353 /* Create the crncystr entry. */
354 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
355 + 2);
356 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
357 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
361 void
362 monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
363 const char *output_path)
365 struct locale_monetary_t *monetary
366 = locale->categories[LC_MONETARY].monetary;
367 struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
368 struct locale_file data;
369 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
370 size_t cnt = 0;
372 data.magic = LIMAGIC (LC_MONETARY);
373 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
374 iov[cnt].iov_base = (void *) &data;
375 iov[cnt].iov_len = sizeof (data);
376 ++cnt;
378 iov[cnt].iov_base = (void *) idx;
379 iov[cnt].iov_len = sizeof (idx);
380 ++cnt;
382 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
383 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
384 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
385 ++cnt;
387 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
388 iov[cnt].iov_base = (void *) monetary->currency_symbol;
389 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
390 ++cnt;
392 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
393 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
394 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
395 ++cnt;
397 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
398 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
399 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
400 ++cnt;
402 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
403 iov[cnt].iov_base = monetary->mon_grouping;
404 iov[cnt].iov_len = monetary->mon_grouping_len;
405 ++cnt;
407 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
408 iov[cnt].iov_base = (void *) monetary->positive_sign;
409 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
410 ++cnt;
412 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
413 iov[cnt].iov_base = (void *) monetary->negative_sign;
414 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
415 ++cnt;
417 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
418 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
419 iov[cnt].iov_len = 1;
420 ++cnt;
422 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
423 iov[cnt].iov_base = (void *) &monetary->frac_digits;
424 iov[cnt].iov_len = 1;
425 ++cnt;
427 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
428 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
429 iov[cnt].iov_len = 1;
430 ++cnt;
432 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
433 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
434 iov[cnt].iov_len = 1;
435 ++cnt;
437 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
438 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
439 iov[cnt].iov_len = 1;
440 ++cnt;
442 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
443 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
444 iov[cnt].iov_len = 1;
445 ++cnt;
447 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
448 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
449 iov[cnt].iov_len = 1;
450 ++cnt;
452 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
453 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
454 iov[cnt].iov_len = 1;
455 ++cnt;
457 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
458 iov[cnt].iov_base = (void *) monetary->crncystr;
459 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
460 ++cnt;
462 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
463 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
464 iov[cnt].iov_len = 1;
465 ++cnt;
467 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
468 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
469 iov[cnt].iov_len = 1;
470 ++cnt;
472 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
473 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
474 iov[cnt].iov_len = 1;
475 ++cnt;
477 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
478 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
479 iov[cnt].iov_len = 1;
480 ++cnt;
482 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
483 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
484 iov[cnt].iov_len = 1;
485 ++cnt;
487 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
488 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
489 iov[cnt].iov_len = 1;
490 ++cnt;
492 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
493 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
494 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
495 ++cnt;
497 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
498 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
499 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
500 ++cnt;
502 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
503 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
504 iov[cnt].iov_len = 1;
505 ++cnt;
507 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
508 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
509 iov[cnt].iov_len = 1;
510 ++cnt;
512 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
513 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
514 iov[cnt].iov_len = 1;
515 ++cnt;
517 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
518 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
519 iov[cnt].iov_len = 1;
520 ++cnt;
522 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
523 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
524 iov[cnt].iov_len = 1;
525 ++cnt;
527 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
528 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
529 iov[cnt].iov_len = 1;
530 ++cnt;
532 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
533 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
534 iov[cnt].iov_len = 1;
535 ++cnt;
537 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
538 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
539 iov[cnt].iov_len = 1;
540 ++cnt;
542 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
543 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
544 iov[cnt].iov_len = 1;
545 ++cnt;
547 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
548 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
549 iov[cnt].iov_len = 1;
550 ++cnt;
552 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
553 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
554 iov[cnt].iov_len = 1;
555 ++cnt;
557 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
558 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
559 iov[cnt].iov_len = 1;
560 ++cnt;
562 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
563 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
564 iov[cnt].iov_len = 1;
565 ++cnt;
567 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
568 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
569 iov[cnt].iov_len = 1;
570 ++cnt;
572 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
574 /* Align following data */
575 iov[cnt].iov_base = (void *) "\0\0";
576 iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
577 idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
578 ++cnt;
580 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
581 iov[cnt].iov_len = sizeof(uint32_t);
582 ++cnt;
584 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
585 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
586 iov[cnt].iov_len = sizeof(uint32_t);
587 ++cnt;
589 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
590 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
591 iov[cnt].iov_len = sizeof(uint32_t);
592 ++cnt;
594 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
595 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
596 iov[cnt].iov_len = sizeof(uint32_t);
597 ++cnt;
599 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
600 iov[cnt].iov_base = (void *) monetary->conversion_rate;
601 iov[cnt].iov_len = 2 * sizeof(uint32_t);
602 ++cnt;
604 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
605 iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
606 iov[cnt].iov_len = sizeof (uint32_t);
607 ++cnt;
609 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
610 iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
611 iov[cnt].iov_len = sizeof (uint32_t);
612 ++cnt;
614 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
615 iov[cnt].iov_base = (void *) charmap->code_set_name;
616 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
617 ++cnt;
619 assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
621 write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
622 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
626 static int
627 curr_strcmp (const char *s1, const char **s2)
629 return strcmp (s1, *s2);
633 /* The parser for the LC_MONETARY section of the locale definition. */
634 void
635 monetary_read (struct linereader *ldfile, struct localedef_t *result,
636 const struct charmap_t *charmap, const char *repertoire_name,
637 int ignore_content)
639 struct repertoire_t *repertoire = NULL;
640 struct locale_monetary_t *monetary;
641 struct token *now;
642 enum token_t nowtok;
644 /* Get the repertoire we have to use. */
645 if (repertoire_name != NULL)
646 repertoire = repertoire_read (repertoire_name);
648 /* The rest of the line containing `LC_MONETARY' must be free. */
649 lr_ignore_rest (ldfile, 1);
653 now = lr_token (ldfile, charmap, result, NULL, verbose);
654 nowtok = now->tok;
656 while (nowtok == tok_eol);
658 /* If we see `copy' now we are almost done. */
659 if (nowtok == tok_copy)
661 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
662 LC_MONETARY, "LC_MONETARY", ignore_content);
663 return;
666 /* Prepare the data structures. */
667 monetary_startup (ldfile, result, ignore_content);
668 monetary = result->categories[LC_MONETARY].monetary;
670 while (1)
672 /* Of course we don't proceed beyond the end of file. */
673 if (nowtok == tok_eof)
674 break;
676 /* Ignore empty lines. */
677 if (nowtok == tok_eol)
679 now = lr_token (ldfile, charmap, result, NULL, verbose);
680 nowtok = now->tok;
681 continue;
684 switch (nowtok)
686 #define STR_ELEM(cat) \
687 case tok_##cat: \
688 /* Ignore the rest of the line if we don't need the input of \
689 this line. */ \
690 if (ignore_content) \
692 lr_ignore_rest (ldfile, 0); \
693 break; \
696 now = lr_token (ldfile, charmap, result, NULL, verbose); \
697 if (now->tok != tok_string) \
698 goto err_label; \
699 else if (monetary->cat != NULL) \
700 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
701 "LC_MONETARY", #cat); \
702 else if (!ignore_content && now->val.str.startmb == NULL) \
704 lr_error (ldfile, _("\
705 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
706 monetary->cat = ""; \
708 else if (!ignore_content) \
709 monetary->cat = now->val.str.startmb; \
710 lr_ignore_rest (ldfile, 1); \
711 break
713 STR_ELEM (int_curr_symbol);
714 STR_ELEM (currency_symbol);
715 STR_ELEM (positive_sign);
716 STR_ELEM (negative_sign);
717 STR_ELEM (duo_int_curr_symbol);
718 STR_ELEM (duo_currency_symbol);
720 #define STR_ELEM_WC(cat) \
721 case tok_##cat: \
722 /* Ignore the rest of the line if we don't need the input of \
723 this line. */ \
724 if (ignore_content) \
726 lr_ignore_rest (ldfile, 0); \
727 break; \
730 ldfile->return_widestr = 1; \
731 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
732 if (now->tok != tok_string) \
733 goto err_label; \
734 if (monetary->cat != NULL) \
735 lr_error (ldfile, _("\
736 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
737 else if (!ignore_content && now->val.str.startmb == NULL) \
739 lr_error (ldfile, _("\
740 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
741 monetary->cat = ""; \
742 monetary->cat##_wc = L'\0'; \
744 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
746 lr_error (ldfile, _("\
747 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
749 else if (!ignore_content) \
751 monetary->cat = now->val.str.startmb; \
753 if (now->val.str.startwc != NULL) \
754 monetary->cat##_wc = *now->val.str.startwc; \
756 ldfile->return_widestr = 0; \
757 break
759 STR_ELEM_WC (mon_decimal_point);
760 STR_ELEM_WC (mon_thousands_sep);
762 #define INT_ELEM(cat) \
763 case tok_##cat: \
764 /* Ignore the rest of the line if we don't need the input of \
765 this line. */ \
766 if (ignore_content) \
768 lr_ignore_rest (ldfile, 0); \
769 break; \
772 now = lr_token (ldfile, charmap, result, NULL, verbose); \
773 if (now->tok != tok_minus1 && now->tok != tok_number) \
774 goto err_label; \
775 else if (monetary->cat != -2) \
776 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
777 "LC_MONETARY", #cat); \
778 else if (!ignore_content) \
779 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
780 break
782 INT_ELEM (int_frac_digits);
783 INT_ELEM (frac_digits);
784 INT_ELEM (p_cs_precedes);
785 INT_ELEM (p_sep_by_space);
786 INT_ELEM (n_cs_precedes);
787 INT_ELEM (n_sep_by_space);
788 INT_ELEM (p_sign_posn);
789 INT_ELEM (n_sign_posn);
790 INT_ELEM (int_p_cs_precedes);
791 INT_ELEM (int_p_sep_by_space);
792 INT_ELEM (int_n_cs_precedes);
793 INT_ELEM (int_n_sep_by_space);
794 INT_ELEM (int_p_sign_posn);
795 INT_ELEM (int_n_sign_posn);
796 INT_ELEM (duo_int_frac_digits);
797 INT_ELEM (duo_frac_digits);
798 INT_ELEM (duo_p_cs_precedes);
799 INT_ELEM (duo_p_sep_by_space);
800 INT_ELEM (duo_n_cs_precedes);
801 INT_ELEM (duo_n_sep_by_space);
802 INT_ELEM (duo_p_sign_posn);
803 INT_ELEM (duo_n_sign_posn);
804 INT_ELEM (duo_int_p_cs_precedes);
805 INT_ELEM (duo_int_p_sep_by_space);
806 INT_ELEM (duo_int_n_cs_precedes);
807 INT_ELEM (duo_int_n_sep_by_space);
808 INT_ELEM (duo_int_p_sign_posn);
809 INT_ELEM (duo_int_n_sign_posn);
810 INT_ELEM (uno_valid_from);
811 INT_ELEM (uno_valid_to);
812 INT_ELEM (duo_valid_from);
813 INT_ELEM (duo_valid_to);
815 case tok_mon_grouping:
816 /* Ignore the rest of the line if we don't need the input of
817 this line. */
818 if (ignore_content)
820 lr_ignore_rest (ldfile, 0);
821 break;
824 now = lr_token (ldfile, charmap, result, NULL, verbose);
825 if (now->tok != tok_minus1 && now->tok != tok_number)
826 goto err_label;
827 else
829 size_t act = 0;
830 size_t max = 10;
831 char *grouping = ignore_content ? NULL : xmalloc (max);
835 if (act + 1 >= max)
837 max *= 2;
838 grouping = xrealloc (grouping, max);
841 if (act > 0 && grouping[act - 1] == '\177')
843 lr_error (ldfile, _("\
844 %s: `-1' must be last entry in `%s' field"),
845 "LC_MONETARY", "mon_grouping");
846 lr_ignore_rest (ldfile, 0);
847 break;
850 if (now->tok == tok_minus1)
852 if (!ignore_content)
853 grouping[act++] = '\177';
855 else if (now->val.num == 0)
857 /* A value of 0 disables grouping from here on but
858 we must not store a NUL character since this
859 terminates the string. Use something different
860 which must not be used otherwise. */
861 if (!ignore_content)
862 grouping[act++] = '\377';
864 else if (now->val.num > 126)
865 lr_error (ldfile, _("\
866 %s: values for field `%s' must be smaller than 127"),
867 "LC_MONETARY", "mon_grouping");
868 else if (!ignore_content)
869 grouping[act++] = now->val.num;
871 /* Next must be semicolon. */
872 now = lr_token (ldfile, charmap, result, NULL, verbose);
873 if (now->tok != tok_semicolon)
874 break;
876 now = lr_token (ldfile, charmap, result, NULL, verbose);
878 while (now->tok == tok_minus1 || now->tok == tok_number);
880 if (now->tok != tok_eol)
881 goto err_label;
883 if (!ignore_content)
885 grouping[act++] = '\0';
887 monetary->mon_grouping = xrealloc (grouping, act);
888 monetary->mon_grouping_len = act;
891 break;
893 case tok_conversion_rate:
894 /* Ignore the rest of the line if we don't need the input of
895 this line. */
896 if (ignore_content)
898 lr_ignore_rest (ldfile, 0);
899 break;
902 now = lr_token (ldfile, charmap, result, NULL, verbose);
903 if (now->tok != tok_number)
904 goto err_label;
905 if (now->val.num == 0)
907 invalid_conversion_rate:
908 lr_error (ldfile, _("conversion rate value cannot be zero"));
909 if (!ignore_content)
911 monetary->conversion_rate[0] = 1;
912 monetary->conversion_rate[1] = 1;
914 break;
916 if (!ignore_content)
917 monetary->conversion_rate[0] = now->val.num;
918 /* Next must be a semicolon. */
919 now = lr_token (ldfile, charmap, result, NULL, verbose);
920 if (now->tok != tok_semicolon)
921 goto err_label;
922 /* And another number. */
923 now = lr_token (ldfile, charmap, result, NULL, verbose);
924 if (now->tok != tok_number)
925 goto err_label;
926 if (now->val.num == 0)
927 goto invalid_conversion_rate;
928 if (!ignore_content)
929 monetary->conversion_rate[1] = now->val.num;
930 /* The rest of the line must be empty. */
931 lr_ignore_rest (ldfile, 1);
932 break;
934 case tok_end:
935 /* Next we assume `LC_MONETARY'. */
936 now = lr_token (ldfile, charmap, result, NULL, verbose);
937 if (now->tok == tok_eof)
938 break;
939 if (now->tok == tok_eol)
940 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
941 else if (now->tok != tok_lc_monetary)
942 lr_error (ldfile, _("\
943 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
944 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
945 return;
947 default:
948 err_label:
949 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
952 /* Prepare for the next round. */
953 now = lr_token (ldfile, charmap, result, NULL, verbose);
954 nowtok = now->tok;
957 /* When we come here we reached the end of the file. */
958 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");