(pthread_handle_create): Start the child thread with the cancel signal blocked, so...
[glibc.git] / locale / programs / ld-monetary.c
blob08a10fdcc10023c79c00525345f6d4f509e69ef3
1 /* Copyright (C) 1995-1999, 2000, 2001 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 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 "linereader.h"
34 #include "localedef.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, 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 error (0, 0, _("No definition for %s category found"),
195 "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 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 error (0, 0, _("\
225 %s: value of field `int_curr_symbol' has wrong length"),
226 "LC_MONETARY");
228 else if (bsearch (monetary->int_curr_symbol, valid_int_curr,
229 NR_VALID_INT_CURR, sizeof (const char *),
230 (comparison_fn_t) curr_strcmp) == NULL
231 && !be_quiet)
232 error (0, 0, _("\
233 %s: value of field `int_curr_symbol' does \
234 not correspond to a valid name in ISO 4217"),
235 "LC_MONETARY");
238 /* The decimal point must not be empty. This is not said explicitly
239 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
240 != "". */
241 if (monetary->mon_decimal_point == NULL)
243 if (! be_quiet && ! nothing)
244 error (0, 0, _("%s: field `%s' not defined"),
245 "LC_MONETARY", "mon_decimal_point");
246 monetary->mon_decimal_point = ".";
248 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
250 error (0, 0, _("\
251 %s: value for field `%s' must not be the empty string"),
252 "LC_MONETARY", "mon_decimal_point");
254 if (monetary->mon_decimal_point_wc == L'\0')
255 monetary->mon_decimal_point_wc = L'.';
257 if (monetary->mon_grouping_len == 0)
259 if (! be_quiet && ! nothing)
260 error (0, 0, _("%s: field `%s' not defined"),
261 "LC_MONETARY", "mon_grouping");
263 monetary->mon_grouping = (char *) "\177";
264 monetary->mon_grouping_len = 1;
267 #undef TEST_ELEM
268 #define TEST_ELEM(cat, min, max, initval) \
269 if (monetary->cat == -2) \
271 if (! be_quiet && ! nothing) \
272 error (0, 0, _("%s: field `%s' not defined"), \
273 "LC_MONETARY", #cat); \
274 monetary->cat = initval; \
276 else if ((monetary->cat < min || monetary->cat > max) \
277 && !be_quiet && !nothing) \
278 error (0, 0, _(" \
279 %s: value for field `%s' must be in range %d...%d"), \
280 "LC_MONETARY", #cat, min, max)
282 TEST_ELEM (int_frac_digits, -128, 127, -1);
283 TEST_ELEM (frac_digits, -128, 127, -1);
284 TEST_ELEM (p_cs_precedes, -1, 1, -1);
285 TEST_ELEM (p_sep_by_space, -1, 2, -1);
286 TEST_ELEM (n_cs_precedes, -1, 1, -1);
287 TEST_ELEM (n_sep_by_space, -1, 2, -1);
288 TEST_ELEM (p_sign_posn, -1, 4, -1);
289 TEST_ELEM (n_sign_posn, -1, 4, -1);
291 /* The non-POSIX.2 extensions are optional. */
292 if (monetary->duo_int_curr_symbol == NULL)
293 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
294 if (monetary->duo_currency_symbol == NULL)
295 monetary->duo_currency_symbol = monetary->currency_symbol;
297 if (monetary->duo_int_frac_digits == -2)
298 monetary->duo_int_frac_digits = monetary->int_frac_digits;
299 if (monetary->duo_frac_digits == -2)
300 monetary->duo_frac_digits = monetary->frac_digits;
302 #undef TEST_ELEM
303 #define TEST_ELEM(cat, alt, min, max) \
304 if (monetary->cat == -2) \
305 monetary->cat = monetary->alt; \
306 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
307 && ! nothing) \
308 error (0, 0, _("\
309 %s: value for field `%s' must be in range %d...%d"), \
310 "LC_MONETARY", #cat, min, max)
312 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
313 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
314 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
315 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
316 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
317 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
319 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
320 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
321 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
322 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
323 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
324 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
325 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
326 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
327 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
328 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
329 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
330 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
332 if (monetary->uno_valid_from == 0)
333 monetary->uno_valid_from = 10101;
334 if (monetary->uno_valid_to == 0)
335 monetary->uno_valid_to = 99991231;
336 if (monetary->duo_valid_from == 0)
337 monetary->duo_valid_from = 10101;
338 if (monetary->duo_valid_to == 0)
339 monetary->duo_valid_to = 99991231;
341 if (monetary->conversion_rate[0] == 0)
343 monetary->conversion_rate[0] = 1;
344 monetary->conversion_rate[1] = 1;
347 /* Create the crncystr entry. */
348 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
349 + 2);
350 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
351 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
355 void
356 monetary_output (struct localedef_t *locale, struct charmap_t *charmap,
357 const char *output_path)
359 struct locale_monetary_t *monetary
360 = locale->categories[LC_MONETARY].monetary;
361 struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
362 struct locale_file data;
363 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
364 size_t cnt = 0;
366 data.magic = LIMAGIC (LC_MONETARY);
367 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
368 iov[cnt].iov_base = (void *) &data;
369 iov[cnt].iov_len = sizeof (data);
370 ++cnt;
372 iov[cnt].iov_base = (void *) idx;
373 iov[cnt].iov_len = sizeof (idx);
374 ++cnt;
376 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
377 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
378 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
379 ++cnt;
381 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
382 iov[cnt].iov_base = (void *) monetary->currency_symbol;
383 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
384 ++cnt;
386 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
387 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
388 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
389 ++cnt;
391 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
392 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
393 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
394 ++cnt;
396 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
397 iov[cnt].iov_base = monetary->mon_grouping;
398 iov[cnt].iov_len = monetary->mon_grouping_len;
399 ++cnt;
401 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
402 iov[cnt].iov_base = (void *) monetary->positive_sign;
403 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
404 ++cnt;
406 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
407 iov[cnt].iov_base = (void *) monetary->negative_sign;
408 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
409 ++cnt;
411 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
412 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
413 iov[cnt].iov_len = 1;
414 ++cnt;
416 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
417 iov[cnt].iov_base = (void *) &monetary->frac_digits;
418 iov[cnt].iov_len = 1;
419 ++cnt;
421 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
422 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
423 iov[cnt].iov_len = 1;
424 ++cnt;
426 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
427 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
428 iov[cnt].iov_len = 1;
429 ++cnt;
431 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
432 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
433 iov[cnt].iov_len = 1;
434 ++cnt;
436 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
437 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
438 iov[cnt].iov_len = 1;
439 ++cnt;
441 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
442 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
443 iov[cnt].iov_len = 1;
444 ++cnt;
446 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
447 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
448 iov[cnt].iov_len = 1;
449 ++cnt;
451 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
452 iov[cnt].iov_base = (void *) monetary->crncystr;
453 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
454 ++cnt;
456 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
457 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
458 iov[cnt].iov_len = 1;
459 ++cnt;
461 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
462 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
463 iov[cnt].iov_len = 1;
464 ++cnt;
466 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
467 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
468 iov[cnt].iov_len = 1;
469 ++cnt;
471 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
472 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
473 iov[cnt].iov_len = 1;
474 ++cnt;
476 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
477 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
478 iov[cnt].iov_len = 1;
479 ++cnt;
481 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
482 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
483 iov[cnt].iov_len = 1;
484 ++cnt;
486 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
487 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
488 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
489 ++cnt;
491 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
492 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
493 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
494 ++cnt;
496 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
497 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
498 iov[cnt].iov_len = 1;
499 ++cnt;
501 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
502 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
503 iov[cnt].iov_len = 1;
504 ++cnt;
506 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
507 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
508 iov[cnt].iov_len = 1;
509 ++cnt;
511 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
512 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
513 iov[cnt].iov_len = 1;
514 ++cnt;
516 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
517 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
518 iov[cnt].iov_len = 1;
519 ++cnt;
521 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
522 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
523 iov[cnt].iov_len = 1;
524 ++cnt;
526 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
527 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
528 iov[cnt].iov_len = 1;
529 ++cnt;
531 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
532 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
533 iov[cnt].iov_len = 1;
534 ++cnt;
536 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
537 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
538 iov[cnt].iov_len = 1;
539 ++cnt;
541 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
542 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
543 iov[cnt].iov_len = 1;
544 ++cnt;
546 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
547 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
548 iov[cnt].iov_len = 1;
549 ++cnt;
551 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
552 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
553 iov[cnt].iov_len = 1;
554 ++cnt;
556 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
557 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
558 iov[cnt].iov_len = 1;
559 ++cnt;
561 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
562 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
563 iov[cnt].iov_len = 1;
564 ++cnt;
566 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
568 /* Align following data */
569 iov[cnt].iov_base = (void *) "\0\0";
570 iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
571 idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
572 ++cnt;
574 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
575 iov[cnt].iov_len = sizeof(uint32_t);
576 ++cnt;
578 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
579 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
580 iov[cnt].iov_len = sizeof(uint32_t);
581 ++cnt;
583 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
584 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
585 iov[cnt].iov_len = sizeof(uint32_t);
586 ++cnt;
588 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
589 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
590 iov[cnt].iov_len = sizeof(uint32_t);
591 ++cnt;
593 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
594 iov[cnt].iov_base = (void *) monetary->conversion_rate;
595 iov[cnt].iov_len = 2 * sizeof(uint32_t);
596 ++cnt;
598 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
599 iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
600 iov[cnt].iov_len = sizeof (uint32_t);
601 ++cnt;
603 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
604 iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
605 iov[cnt].iov_len = sizeof (uint32_t);
606 ++cnt;
608 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
609 iov[cnt].iov_base = (void *) charmap->code_set_name;
610 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
611 ++cnt;
613 assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
615 write_locale_data (output_path, "LC_MONETARY",
616 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
620 static int
621 curr_strcmp (const char *s1, const char **s2)
623 return strcmp (s1, *s2);
627 /* The parser for the LC_MONETARY section of the locale definition. */
628 void
629 monetary_read (struct linereader *ldfile, struct localedef_t *result,
630 struct charmap_t *charmap, const char *repertoire_name,
631 int ignore_content)
633 struct repertoire_t *repertoire = NULL;
634 struct locale_monetary_t *monetary;
635 struct token *now;
636 enum token_t nowtok;
638 /* Get the repertoire we have to use. */
639 if (repertoire_name != NULL)
640 repertoire = repertoire_read (repertoire_name);
642 /* The rest of the line containing `LC_MONETARY' must be free. */
643 lr_ignore_rest (ldfile, 1);
647 now = lr_token (ldfile, charmap, NULL, verbose);
648 nowtok = now->tok;
650 while (nowtok == tok_eol);
652 /* If we see `copy' now we are almost done. */
653 if (nowtok == tok_copy)
655 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
656 LC_MONETARY, "LC_MONETARY", ignore_content);
657 return;
660 /* Prepare the data structures. */
661 monetary_startup (ldfile, result, ignore_content);
662 monetary = result->categories[LC_MONETARY].monetary;
664 while (1)
666 /* Of course we don't proceed beyond the end of file. */
667 if (nowtok == tok_eof)
668 break;
670 /* Ignore empty lines. */
671 if (nowtok == tok_eol)
673 now = lr_token (ldfile, charmap, NULL, verbose);
674 nowtok = now->tok;
675 continue;
678 switch (nowtok)
680 #define STR_ELEM(cat) \
681 case tok_##cat: \
682 /* Ignore the rest of the line if we don't need the input of \
683 this line. */ \
684 if (ignore_content) \
686 lr_ignore_rest (ldfile, 0); \
687 break; \
690 now = lr_token (ldfile, charmap, NULL, verbose); \
691 if (now->tok != tok_string) \
692 goto err_label; \
693 else if (monetary->cat != NULL) \
694 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
695 "LC_MONETARY", #cat); \
696 else if (!ignore_content && now->val.str.startmb == NULL) \
698 lr_error (ldfile, _("\
699 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
700 monetary->cat = ""; \
702 else if (!ignore_content) \
703 monetary->cat = now->val.str.startmb; \
704 lr_ignore_rest (ldfile, 1); \
705 break
707 STR_ELEM (int_curr_symbol);
708 STR_ELEM (currency_symbol);
709 STR_ELEM (positive_sign);
710 STR_ELEM (negative_sign);
711 STR_ELEM (duo_int_curr_symbol);
712 STR_ELEM (duo_currency_symbol);
714 #define STR_ELEM_WC(cat) \
715 case tok_##cat: \
716 /* Ignore the rest of the line if we don't need the input of \
717 this line. */ \
718 if (ignore_content) \
720 lr_ignore_rest (ldfile, 0); \
721 break; \
724 ldfile->return_widestr = 1; \
725 now = lr_token (ldfile, charmap, repertoire, verbose); \
726 if (now->tok != tok_string) \
727 goto err_label; \
728 if (monetary->cat != NULL) \
729 lr_error (ldfile, _("\
730 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
731 else if (!ignore_content && now->val.str.startmb == NULL) \
733 lr_error (ldfile, _("\
734 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
735 monetary->cat = ""; \
736 monetary->cat##_wc = L'\0'; \
738 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
740 lr_error (ldfile, _("\
741 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
743 else if (!ignore_content) \
745 monetary->cat = now->val.str.startmb; \
747 if (now->val.str.startwc != NULL) \
748 monetary->cat##_wc = *now->val.str.startwc; \
750 ldfile->return_widestr = 0; \
751 break
753 STR_ELEM_WC (mon_decimal_point);
754 STR_ELEM_WC (mon_thousands_sep);
756 #define INT_ELEM(cat) \
757 case tok_##cat: \
758 /* Ignore the rest of the line if we don't need the input of \
759 this line. */ \
760 if (ignore_content) \
762 lr_ignore_rest (ldfile, 0); \
763 break; \
766 now = lr_token (ldfile, charmap, NULL, verbose); \
767 if (now->tok != tok_minus1 && now->tok != tok_number) \
768 goto err_label; \
769 else if (monetary->cat != -2) \
770 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
771 "LC_MONETARY", #cat); \
772 else if (!ignore_content) \
773 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
774 break
776 INT_ELEM (int_frac_digits);
777 INT_ELEM (frac_digits);
778 INT_ELEM (p_cs_precedes);
779 INT_ELEM (p_sep_by_space);
780 INT_ELEM (n_cs_precedes);
781 INT_ELEM (n_sep_by_space);
782 INT_ELEM (p_sign_posn);
783 INT_ELEM (n_sign_posn);
784 INT_ELEM (int_p_cs_precedes);
785 INT_ELEM (int_p_sep_by_space);
786 INT_ELEM (int_n_cs_precedes);
787 INT_ELEM (int_n_sep_by_space);
788 INT_ELEM (int_p_sign_posn);
789 INT_ELEM (int_n_sign_posn);
790 INT_ELEM (duo_int_frac_digits);
791 INT_ELEM (duo_frac_digits);
792 INT_ELEM (duo_p_cs_precedes);
793 INT_ELEM (duo_p_sep_by_space);
794 INT_ELEM (duo_n_cs_precedes);
795 INT_ELEM (duo_n_sep_by_space);
796 INT_ELEM (duo_p_sign_posn);
797 INT_ELEM (duo_n_sign_posn);
798 INT_ELEM (duo_int_p_cs_precedes);
799 INT_ELEM (duo_int_p_sep_by_space);
800 INT_ELEM (duo_int_n_cs_precedes);
801 INT_ELEM (duo_int_n_sep_by_space);
802 INT_ELEM (duo_int_p_sign_posn);
803 INT_ELEM (duo_int_n_sign_posn);
804 INT_ELEM (uno_valid_from);
805 INT_ELEM (uno_valid_to);
806 INT_ELEM (duo_valid_from);
807 INT_ELEM (duo_valid_to);
809 case tok_mon_grouping:
810 /* Ignore the rest of the line if we don't need the input of
811 this line. */
812 if (ignore_content)
814 lr_ignore_rest (ldfile, 0);
815 break;
818 now = lr_token (ldfile, charmap, NULL, verbose);
819 if (now->tok != tok_minus1 && now->tok != tok_number)
820 goto err_label;
821 else
823 size_t act = 0;
824 size_t max = 10;
825 char *grouping = ignore_content ? NULL : xmalloc (max);
829 if (act + 1 >= max)
831 max *= 2;
832 grouping = xrealloc (grouping, max);
835 if (act > 0 && grouping[act - 1] == '\177')
837 lr_error (ldfile, _("\
838 %s: `-1' must be last entry in `%s' field"),
839 "LC_MONETARY", "mon_grouping");
840 lr_ignore_rest (ldfile, 0);
841 break;
844 if (now->tok == tok_minus1)
846 if (!ignore_content)
847 grouping[act++] = '\177';
849 else if (now->val.num == 0)
851 /* A value of 0 disables grouping from here on but
852 we must not store a NUL character since this
853 terminates the string. Use something different
854 which must not be used otherwise. */
855 if (!ignore_content)
856 grouping[act++] = '\377';
858 else if (now->val.num > 126)
859 lr_error (ldfile, _("\
860 %s: values for field `%s' must be smaller than 127"),
861 "LC_MONETARY", "mon_grouping");
862 else if (!ignore_content)
863 grouping[act++] = now->val.num;
865 /* Next must be semicolon. */
866 now = lr_token (ldfile, charmap, NULL, verbose);
867 if (now->tok != tok_semicolon)
868 break;
870 now = lr_token (ldfile, charmap, NULL, verbose);
872 while (now->tok == tok_minus1 || now->tok == tok_number);
874 if (now->tok != tok_eol)
875 goto err_label;
877 if (!ignore_content)
879 grouping[act++] = '\0';
881 monetary->mon_grouping = xrealloc (grouping, act);
882 monetary->mon_grouping_len = act;
885 break;
887 case tok_conversion_rate:
888 /* Ignore the rest of the line if we don't need the input of
889 this line. */
890 if (ignore_content)
892 lr_ignore_rest (ldfile, 0);
893 break;
896 now = lr_token (ldfile, charmap, NULL, verbose);
897 if (now->tok != tok_number)
898 goto err_label;
899 if (now->val.num == 0)
901 invalid_conversion_rate:
902 lr_error (ldfile, _("conversion rate value cannot be zero"));
903 if (!ignore_content)
905 monetary->conversion_rate[0] = 1;
906 monetary->conversion_rate[1] = 1;
908 break;
910 if (!ignore_content)
911 monetary->conversion_rate[0] = now->val.num;
912 /* Next must be a semicolon. */
913 now = lr_token (ldfile, charmap, NULL, verbose);
914 if (now->tok != tok_semicolon)
915 goto err_label;
916 /* And another number. */
917 now = lr_token (ldfile, charmap, NULL, verbose);
918 if (now->tok != tok_number)
919 goto err_label;
920 if (now->val.num == 0)
921 goto invalid_conversion_rate;
922 if (!ignore_content)
923 monetary->conversion_rate[1] = now->val.num;
924 /* The rest of the line must be empty. */
925 lr_ignore_rest (ldfile, 1);
926 break;
928 case tok_end:
929 /* Next we assume `LC_MONETARY'. */
930 now = lr_token (ldfile, charmap, NULL, verbose);
931 if (now->tok == tok_eof)
932 break;
933 if (now->tok == tok_eol)
934 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
935 else if (now->tok != tok_lc_monetary)
936 lr_error (ldfile, _("\
937 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
938 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
939 return;
941 default:
942 err_label:
943 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
946 /* Prepare for the next round. */
947 now = lr_token (ldfile, charmap, NULL, verbose);
948 nowtok = now->tok;
951 /* When we come here we reached the end of the file. */
952 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");