1 /* Copyright (C) 1995-2022 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published
6 by the Free Software Foundation; version 2 of the License, or
7 (at your option) any later version.
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, see <https://www.gnu.org/licenses/>. */
31 #include "localedef.h"
32 #include "linereader.h"
33 #include "localeinfo.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
;
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];
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
);
106 monetary_startup (struct linereader
*lr
, struct localedef_t
*locale
,
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;
153 lr
->translate_strings
= 1;
154 lr
->return_widestr
= 0;
160 monetary_finish (struct localedef_t
*locale
, const struct charmap_t
*charmap
)
162 struct locale_monetary_t
*monetary
163 = locale
->categories
[LC_MONETARY
].monetary
;
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 a warning and create an
189 if (monetary
== NULL
)
192 No definition for %s category found"), "LC_MONETARY");
193 monetary_startup (NULL
, locale
, 0);
194 monetary
= locale
->categories
[LC_MONETARY
].monetary
;
199 /* Generally speaking there are 3 standards the define the default,
200 warning, and error behaviour of LC_MONETARY. They are ISO/IEC TR 30112,
201 ISO/IEC 9899:2018 (ISO C17), and POSIX.1-2017. Within 30112 we have the
202 definition of a standard i18n FDCC-set, which for LC_MONETARY has the
203 following default values:
206 mon_decimal_point "<U002C>" i.e. ","
208 mon_grouping "\177" i.e. CHAR_MAX
210 negative_sign "<U002E>" i.e. "."
219 Under 30112 a keyword that is not provided implies an empty string ""
220 for string values or a -1 for integer values, and indicates the value
221 is unspecified with no default implied. No errors are considered.
222 The exception is mon_grouping which is a string with a terminating
224 For POSIX Issue 7 we have:
225 https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap07.html
226 and again values not provided default to "" or -1, and indicate the value
227 is not available to the locale. The exception is mon_grouping which is
228 a string with a terminating CHAR_MAX. For the POSIX locale the values of
229 LC_MONETARY should be:
234 mon_grouping "\177" i.e. CHAR_MAX
246 int_p_sep_by_space -1
248 int_n_sep_by_space -1
251 Like with 30112, POSIX also considers no error if the keywords are
252 missing, only that if the cateory as a whole is missing the referencing
253 of the category results in unspecified behaviour.
254 For ISO C17 there is no default value provided, but the localeconv
255 specification in 7.11.2.1 admits that members of char * type may point
256 to "" to indicate a value is not available or is of length zero.
257 The exception is decimal_point (not mon_decimal_point) which must be a
258 defined non-empty string. The values of char, which are generally
259 mapped to integer values in 30112 and POSIX, must be non-negative
260 numbers that map to CHAR_MAX when a value is not available in the
262 In ISO C17 for the "C" locale all values are empty strings "", or
263 CHAR_MAX, with the exception of decimal_point which is "." (defined
264 in LC_NUMERIC). ISO C17 makes no exception for mon_grouping like
265 30112 and POSIX, but a value of "" is functionally equivalent to
266 "\177" since neither defines a grouping (though the latter terminates
269 Lastly, we must consider the legacy C/POSIX locale that implemented
270 as a builtin in glibc and wether a default value mapping to the
271 C/POSIX locale may benefit the user from a compatibility perspective.
273 Thus given 30112, POSIX, ISO C, and the builtin C/POSIX locale we
274 need to pick appropriate defaults below. */
276 /* The members of LC_MONETARY are handled in the order of their definition
277 in locale/categories.def. Please keep them in that order. */
279 /* The purpose of TEST_ELEM is to define a default value for the fields
280 in the category if the field was not defined in the cateory. If the
281 category was present but we didn't see a definition for the field then
282 we also issue a warning, otherwise the only warning you get is the one
283 earlier when a default category is created (completely missing category).
284 This missing field warning is glibc-specific since no standard requires
285 this warning, but we consider it valuable to print a warning for all
286 missing fields in the category. */
287 #define TEST_ELEM(cat, initval) \
288 if (monetary->cat == NULL) \
291 record_warning (_("%s: field `%s' not defined"), \
292 "LC_MONETARY", #cat); \
293 monetary->cat = initval; \
296 /* Keyword: int_curr_symbol. */
297 TEST_ELEM (int_curr_symbol
, "");
298 /* The international currency symbol must come from ISO 4217. */
299 if (monetary
->int_curr_symbol
!= NULL
)
301 /* POSIX says this should be a 3-character symbol from ISO 4217
302 along with a 4th character that is a divider, but the POSIX
303 locale is documented as having a special case of "", and we
304 support that also, so allow other locales to be created with
305 a blank int_curr_symbol. */
306 int ics_len
= strlen (monetary
->int_curr_symbol
);
307 if (ics_len
!= 4 && ics_len
!= 0)
310 record_error (0, 0, _("\
311 %s: value of field `int_curr_symbol' has wrong length"),
314 else if (ics_len
== 4)
315 { /* Check the first three characters against ISO 4217 */
317 strncpy (symbol
, monetary
->int_curr_symbol
, 3);
319 /* A user may disable this waning for testing purposes or
320 for building a locale with a 3 letter country code that
321 was not yet supported in our ISO 4217 list.
322 See the use of --no-warnings=intcurrsym. */
323 if (bsearch (symbol
, valid_int_curr
, NR_VALID_INT_CURR
,
324 sizeof (const char *),
325 (comparison_fn_t
) curr_strcmp
) == NULL
326 && warn_int_curr_symbol
)
328 %s: value of field `int_curr_symbol' does \
329 not correspond to a valid name in ISO 4217 [--no-warnings=intcurrsym]"),
334 /* Keyword: currency_symbol */
335 TEST_ELEM (currency_symbol
, "");
337 /* Keyword: mon_decimal_point */
338 /* ISO C17 7.11.2.1.3 explicitly allows mon_decimal_point to be the
339 empty string e.g. "". This indicates the value is not available in the
340 current locale or is of zero length. However, if the value was never
341 defined then we issue a warning and use a glibc-specific default. ISO
342 30112 in the i18n FDCC-Set uses <U002C> ",", and POSIX Issue 7 in the
343 POSIX locale uses "". It is specific to glibc that the default is <U002E>
344 "."; we retain this existing behaviour for backwards compatibility. */
345 if (monetary
->mon_decimal_point
== NULL
)
348 record_warning (_("%s: field `%s' not defined, using defaults"),
349 "LC_MONETARY", "mon_decimal_point");
350 monetary
->mon_decimal_point
= ".";
351 monetary
->mon_decimal_point_wc
= L
'.';
354 /* Keyword: mon_thousands_sep */
355 if (monetary
->mon_thousands_sep
== NULL
)
358 record_warning (_("%s: field `%s' not defined, using defaults"),
359 "LC_MONETARY", "mon_thousands_sep");
360 monetary
->mon_thousands_sep
= "";
361 monetary
->mon_thousands_sep_wc
= L
'\0';
364 /* Keyword: mon_grouping */
365 if (monetary
->mon_grouping_len
== 0)
368 record_warning (_("%s: field `%s' not defined"),
369 "LC_MONETARY", "mon_grouping");
370 /* Missing entries are given 1 element in their bytearray with
371 a value of CHAR_MAX which indicates that "No further grouping
372 is to be performed" (functionally equivalent to ISO C's "C"
373 locale default of ""). */
374 monetary
->mon_grouping
= (char *) "\177";
375 monetary
->mon_grouping_len
= 1;
378 /* Keyword: positive_sign */
379 TEST_ELEM (positive_sign
, "");
381 /* Keyword: negative_sign */
382 TEST_ELEM (negative_sign
, "");
385 #define TEST_ELEM(cat, min, max, initval) \
386 if (monetary->cat == -2) \
389 record_warning (_("%s: field `%s' not defined"), \
390 "LC_MONETARY", #cat); \
391 monetary->cat = initval; \
393 else if ((monetary->cat < min || monetary->cat > max) \
395 && !be_quiet && !nothing) \
396 record_error (0, 0, _("\
397 %s: value for field `%s' must be in range %d...%d"), \
398 "LC_MONETARY", #cat, min, max)
400 TEST_ELEM (int_frac_digits
, 1, 0, -1);
401 TEST_ELEM (frac_digits
, 1, 0, -1);
402 TEST_ELEM (p_cs_precedes
, -1, 1, -1);
403 TEST_ELEM (p_sep_by_space
, -1, 2, -1);
404 TEST_ELEM (n_cs_precedes
, -1, 1, -1);
405 TEST_ELEM (n_sep_by_space
, -1, 2, -1);
406 TEST_ELEM (p_sign_posn
, -1, 4, -1);
407 TEST_ELEM (n_sign_posn
, -1, 4, -1);
409 /* Keyword: crncystr */
410 monetary
->crncystr
= (char *) xmalloc (strlen (monetary
->currency_symbol
)
412 monetary
->crncystr
[0] = monetary
->p_cs_precedes
? '-' : '+';
413 strcpy (&monetary
->crncystr
[1], monetary
->currency_symbol
);
416 #define TEST_ELEM(cat, alt, min, max) \
417 if (monetary->cat == -2) \
418 monetary->cat = monetary->alt; \
419 else if ((monetary->cat < min || monetary->cat > max) && ! nothing) \
420 record_error (0, 0, _("\
421 %s: value for field `%s' must be in range %d...%d"), \
422 "LC_MONETARY", #cat, min, max)
424 TEST_ELEM (int_p_cs_precedes
, p_cs_precedes
, -1, 1);
425 TEST_ELEM (int_p_sep_by_space
, p_sep_by_space
, -1, 2);
426 TEST_ELEM (int_n_cs_precedes
, n_cs_precedes
, -1, 1);
427 TEST_ELEM (int_n_sep_by_space
, n_sep_by_space
, -1, 2);
428 TEST_ELEM (int_p_sign_posn
, p_sign_posn
, -1, 4);
429 TEST_ELEM (int_n_sign_posn
, n_sign_posn
, -1, 4);
431 /* The non-POSIX.2 extensions are optional. */
432 if (monetary
->duo_int_curr_symbol
== NULL
)
433 monetary
->duo_int_curr_symbol
= monetary
->int_curr_symbol
;
434 if (monetary
->duo_currency_symbol
== NULL
)
435 monetary
->duo_currency_symbol
= monetary
->currency_symbol
;
437 if (monetary
->duo_int_frac_digits
== -2)
438 monetary
->duo_int_frac_digits
= monetary
->int_frac_digits
;
439 if (monetary
->duo_frac_digits
== -2)
440 monetary
->duo_frac_digits
= monetary
->frac_digits
;
442 TEST_ELEM (duo_p_cs_precedes
, p_cs_precedes
, -1, 1);
443 TEST_ELEM (duo_p_sep_by_space
, p_sep_by_space
, -1, 2);
444 TEST_ELEM (duo_n_cs_precedes
, n_cs_precedes
, -1, 1);
445 TEST_ELEM (duo_n_sep_by_space
, n_sep_by_space
, -1, 2);
446 TEST_ELEM (duo_int_p_cs_precedes
, int_p_cs_precedes
, -1, 1);
447 TEST_ELEM (duo_int_p_sep_by_space
, int_p_sep_by_space
, -1, 2);
448 TEST_ELEM (duo_int_n_cs_precedes
, int_n_cs_precedes
, -1, 1);
449 TEST_ELEM (duo_int_n_sep_by_space
, int_n_sep_by_space
, -1, 2);
450 TEST_ELEM (duo_p_sign_posn
, p_sign_posn
, -1, 4);
451 TEST_ELEM (duo_n_sign_posn
, n_sign_posn
, -1, 4);
452 TEST_ELEM (duo_int_p_sign_posn
, int_p_sign_posn
, -1, 4);
453 TEST_ELEM (duo_int_n_sign_posn
, int_n_sign_posn
, -1, 4);
455 if (monetary
->uno_valid_from
== 0)
456 monetary
->uno_valid_from
= 10101;
457 if (monetary
->uno_valid_to
== 0)
458 monetary
->uno_valid_to
= 99991231;
459 if (monetary
->duo_valid_from
== 0)
460 monetary
->duo_valid_from
= 10101;
461 if (monetary
->duo_valid_to
== 0)
462 monetary
->duo_valid_to
= 99991231;
464 /* Keyword: conversion_rate */
465 if (monetary
->conversion_rate
[0] == 0)
467 monetary
->conversion_rate
[0] = 1;
468 monetary
->conversion_rate
[1] = 1;
471 /* A value for monetary-decimal-point-wc was set when
472 monetary_decimal_point was set, likewise for monetary-thousands-sep-wc. */
477 monetary_output (struct localedef_t
*locale
, const struct charmap_t
*charmap
,
478 const char *output_path
)
480 struct locale_monetary_t
*monetary
481 = locale
->categories
[LC_MONETARY
].monetary
;
482 struct locale_file file
;
484 init_locale_data (&file
, _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
));
485 add_locale_string (&file
, monetary
->int_curr_symbol
);
486 add_locale_string (&file
, monetary
->currency_symbol
);
487 add_locale_string (&file
, monetary
->mon_decimal_point
);
488 add_locale_string (&file
, monetary
->mon_thousands_sep
);
489 add_locale_raw_data (&file
, monetary
->mon_grouping
,
490 monetary
->mon_grouping_len
);
491 add_locale_string (&file
, monetary
->positive_sign
);
492 add_locale_string (&file
, monetary
->negative_sign
);
493 add_locale_char (&file
, monetary
->int_frac_digits
);
494 add_locale_char (&file
, monetary
->frac_digits
);
495 add_locale_char (&file
, monetary
->p_cs_precedes
);
496 add_locale_char (&file
, monetary
->p_sep_by_space
);
497 add_locale_char (&file
, monetary
->n_cs_precedes
);
498 add_locale_char (&file
, monetary
->n_sep_by_space
);
499 add_locale_char (&file
, monetary
->p_sign_posn
);
500 add_locale_char (&file
, monetary
->n_sign_posn
);
501 add_locale_string (&file
, monetary
->crncystr
);
502 add_locale_char (&file
, monetary
->int_p_cs_precedes
);
503 add_locale_char (&file
, monetary
->int_p_sep_by_space
);
504 add_locale_char (&file
, monetary
->int_n_cs_precedes
);
505 add_locale_char (&file
, monetary
->int_n_sep_by_space
);
506 add_locale_char (&file
, monetary
->int_p_sign_posn
);
507 add_locale_char (&file
, monetary
->int_n_sign_posn
);
508 add_locale_string (&file
, monetary
->duo_int_curr_symbol
);
509 add_locale_string (&file
, monetary
->duo_currency_symbol
);
510 add_locale_char (&file
, monetary
->duo_int_frac_digits
);
511 add_locale_char (&file
, monetary
->duo_frac_digits
);
512 add_locale_char (&file
, monetary
->duo_p_cs_precedes
);
513 add_locale_char (&file
, monetary
->duo_p_sep_by_space
);
514 add_locale_char (&file
, monetary
->duo_n_cs_precedes
);
515 add_locale_char (&file
, monetary
->duo_n_sep_by_space
);
516 add_locale_char (&file
, monetary
->duo_int_p_cs_precedes
);
517 add_locale_char (&file
, monetary
->duo_int_p_sep_by_space
);
518 add_locale_char (&file
, monetary
->duo_int_n_cs_precedes
);
519 add_locale_char (&file
, monetary
->duo_int_n_sep_by_space
);
520 add_locale_char (&file
, monetary
->duo_p_sign_posn
);
521 add_locale_char (&file
, monetary
->duo_n_sign_posn
);
522 add_locale_char (&file
, monetary
->duo_int_p_sign_posn
);
523 add_locale_char (&file
, monetary
->duo_int_n_sign_posn
);
524 add_locale_uint32 (&file
, monetary
->uno_valid_from
);
525 add_locale_uint32 (&file
, monetary
->uno_valid_to
);
526 add_locale_uint32 (&file
, monetary
->duo_valid_from
);
527 add_locale_uint32 (&file
, monetary
->duo_valid_to
);
528 add_locale_uint32_array (&file
, monetary
->conversion_rate
, 2);
529 add_locale_uint32 (&file
, monetary
->mon_decimal_point_wc
);
530 add_locale_uint32 (&file
, monetary
->mon_thousands_sep_wc
);
531 add_locale_string (&file
, charmap
->code_set_name
);
532 write_locale_data (output_path
, LC_MONETARY
, "LC_MONETARY", &file
);
537 curr_strcmp (const char *s1
, const char **s2
)
539 return strcmp (s1
, *s2
);
543 /* The parser for the LC_MONETARY section of the locale definition. */
545 monetary_read (struct linereader
*ldfile
, struct localedef_t
*result
,
546 const struct charmap_t
*charmap
, const char *repertoire_name
,
549 struct repertoire_t
*repertoire
= NULL
;
550 struct locale_monetary_t
*monetary
;
554 /* Get the repertoire we have to use. */
555 if (repertoire_name
!= NULL
)
556 repertoire
= repertoire_read (repertoire_name
);
558 /* The rest of the line containing `LC_MONETARY' must be free. */
559 lr_ignore_rest (ldfile
, 1);
563 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
566 while (nowtok
== tok_eol
);
568 /* If we see `copy' now we are almost done. */
569 if (nowtok
== tok_copy
)
571 handle_copy (ldfile
, charmap
, repertoire_name
, result
, tok_lc_monetary
,
572 LC_MONETARY
, "LC_MONETARY", ignore_content
);
576 /* Prepare the data structures. */
577 monetary_startup (ldfile
, result
, ignore_content
);
578 monetary
= result
->categories
[LC_MONETARY
].monetary
;
582 /* Of course we don't proceed beyond the end of file. */
583 if (nowtok
== tok_eof
)
586 /* Ignore empty lines. */
587 if (nowtok
== tok_eol
)
589 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
596 #define STR_ELEM(cat) \
598 /* Ignore the rest of the line if we don't need the input of \
600 if (ignore_content) \
602 lr_ignore_rest (ldfile, 0); \
606 now = lr_token (ldfile, charmap, result, NULL, verbose); \
607 if (now->tok != tok_string) \
609 else if (monetary->cat != NULL) \
610 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
611 "LC_MONETARY", #cat); \
612 else if (!ignore_content && now->val.str.startmb == NULL) \
614 lr_error (ldfile, _("\
615 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
616 monetary->cat = ""; \
618 else if (!ignore_content) \
619 monetary->cat = now->val.str.startmb; \
620 lr_ignore_rest (ldfile, 1); \
623 STR_ELEM (int_curr_symbol
);
624 STR_ELEM (currency_symbol
);
625 STR_ELEM (positive_sign
);
626 STR_ELEM (negative_sign
);
627 STR_ELEM (duo_int_curr_symbol
);
628 STR_ELEM (duo_currency_symbol
);
630 #define STR_ELEM_WC(cat) \
632 /* Ignore the rest of the line if we don't need the input of \
634 if (ignore_content) \
636 lr_ignore_rest (ldfile, 0); \
640 ldfile->return_widestr = 1; \
641 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
642 if (now->tok != tok_string) \
644 if (monetary->cat != NULL) \
645 lr_error (ldfile, _("\
646 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
647 else if (!ignore_content && now->val.str.startmb == NULL) \
649 lr_error (ldfile, _("\
650 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
651 monetary->cat = ""; \
652 monetary->cat##_wc = L'\0'; \
654 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
656 lr_error (ldfile, _("\
657 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
659 else if (!ignore_content) \
661 monetary->cat = now->val.str.startmb; \
663 if (now->val.str.startwc != NULL) \
664 monetary->cat##_wc = *now->val.str.startwc; \
666 ldfile->return_widestr = 0; \
669 STR_ELEM_WC (mon_decimal_point
);
670 STR_ELEM_WC (mon_thousands_sep
);
672 #define INT_ELEM(cat) \
674 /* Ignore the rest of the line if we don't need the input of \
676 if (ignore_content) \
678 lr_ignore_rest (ldfile, 0); \
682 now = lr_token (ldfile, charmap, result, NULL, verbose); \
683 if (now->tok != tok_minus1 && now->tok != tok_number) \
685 else if (monetary->cat != -2) \
686 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
687 "LC_MONETARY", #cat); \
688 else if (!ignore_content) \
689 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
692 INT_ELEM (int_frac_digits
);
693 INT_ELEM (frac_digits
);
694 INT_ELEM (p_cs_precedes
);
695 INT_ELEM (p_sep_by_space
);
696 INT_ELEM (n_cs_precedes
);
697 INT_ELEM (n_sep_by_space
);
698 INT_ELEM (p_sign_posn
);
699 INT_ELEM (n_sign_posn
);
700 INT_ELEM (int_p_cs_precedes
);
701 INT_ELEM (int_p_sep_by_space
);
702 INT_ELEM (int_n_cs_precedes
);
703 INT_ELEM (int_n_sep_by_space
);
704 INT_ELEM (int_p_sign_posn
);
705 INT_ELEM (int_n_sign_posn
);
706 INT_ELEM (duo_int_frac_digits
);
707 INT_ELEM (duo_frac_digits
);
708 INT_ELEM (duo_p_cs_precedes
);
709 INT_ELEM (duo_p_sep_by_space
);
710 INT_ELEM (duo_n_cs_precedes
);
711 INT_ELEM (duo_n_sep_by_space
);
712 INT_ELEM (duo_p_sign_posn
);
713 INT_ELEM (duo_n_sign_posn
);
714 INT_ELEM (duo_int_p_cs_precedes
);
715 INT_ELEM (duo_int_p_sep_by_space
);
716 INT_ELEM (duo_int_n_cs_precedes
);
717 INT_ELEM (duo_int_n_sep_by_space
);
718 INT_ELEM (duo_int_p_sign_posn
);
719 INT_ELEM (duo_int_n_sign_posn
);
720 INT_ELEM (uno_valid_from
);
721 INT_ELEM (uno_valid_to
);
722 INT_ELEM (duo_valid_from
);
723 INT_ELEM (duo_valid_to
);
725 case tok_mon_grouping
:
726 /* Ignore the rest of the line if we don't need the input of
730 lr_ignore_rest (ldfile
, 0);
734 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
735 if (now
->tok
!= tok_minus1
&& now
->tok
!= tok_number
)
741 char *grouping
= ignore_content
? NULL
: xmalloc (max
);
748 grouping
= xrealloc (grouping
, max
);
751 if (act
> 0 && grouping
[act
- 1] == '\177')
753 lr_error (ldfile
, _("\
754 %s: `-1' must be last entry in `%s' field"),
755 "LC_MONETARY", "mon_grouping");
756 lr_ignore_rest (ldfile
, 0);
760 if (now
->tok
== tok_minus1
)
763 grouping
[act
++] = '\177';
765 else if (now
->val
.num
== 0)
767 /* A value of 0 disables grouping from here on but
768 we must not store a NUL character since this
769 terminates the string. Use something different
770 which must not be used otherwise. */
772 grouping
[act
++] = '\377';
774 else if (now
->val
.num
> 126)
775 lr_error (ldfile
, _("\
776 %s: values for field `%s' must be smaller than 127"),
777 "LC_MONETARY", "mon_grouping");
778 else if (!ignore_content
)
779 grouping
[act
++] = now
->val
.num
;
781 /* Next must be semicolon. */
782 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
783 if (now
->tok
!= tok_semicolon
)
786 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
788 while (now
->tok
== tok_minus1
|| now
->tok
== tok_number
);
790 if (now
->tok
!= tok_eol
)
795 /* A single -1 means no grouping. */
796 if (act
== 1 && grouping
[0] == '\177')
798 grouping
[act
++] = '\0';
800 monetary
->mon_grouping
= xrealloc (grouping
, act
);
801 monetary
->mon_grouping_len
= act
;
806 case tok_conversion_rate
:
807 /* Ignore the rest of the line if we don't need the input of
811 lr_ignore_rest (ldfile
, 0);
815 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
816 if (now
->tok
!= tok_number
)
818 if (now
->val
.num
== 0)
820 invalid_conversion_rate
:
821 lr_error (ldfile
, _("conversion rate value cannot be zero"));
824 monetary
->conversion_rate
[0] = 1;
825 monetary
->conversion_rate
[1] = 1;
830 monetary
->conversion_rate
[0] = now
->val
.num
;
831 /* Next must be a semicolon. */
832 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
833 if (now
->tok
!= tok_semicolon
)
835 /* And another number. */
836 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
837 if (now
->tok
!= tok_number
)
839 if (now
->val
.num
== 0)
840 goto invalid_conversion_rate
;
842 monetary
->conversion_rate
[1] = now
->val
.num
;
843 /* The rest of the line must be empty. */
844 lr_ignore_rest (ldfile
, 1);
848 /* Next we assume `LC_MONETARY'. */
849 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
850 if (now
->tok
== tok_eof
)
852 if (now
->tok
== tok_eol
)
853 lr_error (ldfile
, _("%s: incomplete `END' line"), "LC_MONETARY");
854 else if (now
->tok
!= tok_lc_monetary
)
855 lr_error (ldfile
, _("\
856 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
857 lr_ignore_rest (ldfile
, now
->tok
== tok_lc_monetary
);
862 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
865 /* Prepare for the next round. */
866 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
870 /* When we come here we reached the end of the file. */
871 lr_error (ldfile
, _("%s: premature end of file"), "LC_MONETARY");