1 /* Copyright (C) 1995-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; version 2 of the License, or
8 (at your option) any later version.
10 This program 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
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <http://www.gnu.org/licenses/>. */
32 #include "localedef.h"
33 #include "linereader.h"
34 #include "localeinfo.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
;
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];
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
);
107 monetary_startup (struct linereader
*lr
, struct localedef_t
*locale
,
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;
154 lr
->translate_strings
= 1;
155 lr
->return_widestr
= 0;
161 monetary_finish (struct localedef_t
*locale
, const struct charmap_t
*charmap
)
163 struct locale_monetary_t
*monetary
164 = locale
->categories
[LC_MONETARY
].monetary
;
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 a warning and create an
190 if (monetary
== NULL
)
193 No definition for %s category found"), "LC_MONETARY");
194 monetary_startup (NULL
, locale
, 0);
195 monetary
= locale
->categories
[LC_MONETARY
].monetary
;
200 #define TEST_ELEM(cat, initval) \
201 if (monetary->cat == NULL) \
204 record_error (0, 0, _("%s: field `%s' not defined"), \
205 "LC_MONETARY", #cat); \
206 monetary->cat = initval; \
209 TEST_ELEM (int_curr_symbol
, "");
210 TEST_ELEM (currency_symbol
, "");
211 TEST_ELEM (mon_decimal_point
, ".");
212 TEST_ELEM (mon_thousands_sep
, "");
213 TEST_ELEM (positive_sign
, "");
214 TEST_ELEM (negative_sign
, "");
216 /* The international currency symbol must come from ISO 4217. */
217 if (monetary
->int_curr_symbol
!= NULL
)
219 /* POSIX says this should be a 3-character symbol from ISO 4217
220 along with a 4th character that is a divider, but the POSIX
221 locale is documented as having a special case of "", and we
222 support that also, so allow other locales to be created with
223 a blank int_curr_symbol. */
224 int ics_len
= strlen (monetary
->int_curr_symbol
);
225 if (ics_len
!= 4 && ics_len
!= 0)
228 record_error (0, 0, _("\
229 %s: value of field `int_curr_symbol' has wrong length"),
232 else if (ics_len
== 4)
233 { /* Check the first three characters against ISO 4217 */
235 strncpy (symbol
, monetary
->int_curr_symbol
, 3);
237 /* A user may disable this waning for testing purposes or
238 for building a locale with a 3 letter country code that
239 was not yet supported in our ISO 4217 list.
240 See the use of --no-warnings=intcurrsym. */
241 if (bsearch (symbol
, valid_int_curr
, NR_VALID_INT_CURR
,
242 sizeof (const char *),
243 (comparison_fn_t
) curr_strcmp
) == NULL
244 && warn_int_curr_symbol
)
246 %s: value of field `int_curr_symbol' does \
247 not correspond to a valid name in ISO 4217 [--no-warnings=intcurrsym]"),
252 /* The decimal point must not be empty. This is not said explicitly
253 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
255 if (monetary
->mon_decimal_point
== NULL
)
258 record_error (0, 0, _("%s: field `%s' not defined"),
259 "LC_MONETARY", "mon_decimal_point");
260 monetary
->mon_decimal_point
= ".";
262 else if (monetary
->mon_decimal_point
[0] == '\0' && ! be_quiet
&& ! nothing
)
264 record_error (0, 0, _("\
265 %s: value for field `%s' must not be an empty string"),
266 "LC_MONETARY", "mon_decimal_point");
268 if (monetary
->mon_decimal_point_wc
== L
'\0')
269 monetary
->mon_decimal_point_wc
= L
'.';
271 if (monetary
->mon_grouping_len
== 0)
274 record_error (0, 0, _("%s: field `%s' not defined"),
275 "LC_MONETARY", "mon_grouping");
277 monetary
->mon_grouping
= (char *) "\177";
278 monetary
->mon_grouping_len
= 1;
282 #define TEST_ELEM(cat, min, max, initval) \
283 if (monetary->cat == -2) \
286 record_error (0, 0, _("%s: field `%s' not defined"), \
287 "LC_MONETARY", #cat); \
288 monetary->cat = initval; \
290 else if ((monetary->cat < min || monetary->cat > max) \
292 && !be_quiet && !nothing) \
293 record_error (0, 0, _("\
294 %s: value for field `%s' must be in range %d...%d"), \
295 "LC_MONETARY", #cat, min, max)
297 TEST_ELEM (int_frac_digits
, 1, 0, -1);
298 TEST_ELEM (frac_digits
, 1, 0, -1);
299 TEST_ELEM (p_cs_precedes
, -1, 1, -1);
300 TEST_ELEM (p_sep_by_space
, -1, 2, -1);
301 TEST_ELEM (n_cs_precedes
, -1, 1, -1);
302 TEST_ELEM (n_sep_by_space
, -1, 2, -1);
303 TEST_ELEM (p_sign_posn
, -1, 4, -1);
304 TEST_ELEM (n_sign_posn
, -1, 4, -1);
306 /* The non-POSIX.2 extensions are optional. */
307 if (monetary
->duo_int_curr_symbol
== NULL
)
308 monetary
->duo_int_curr_symbol
= monetary
->int_curr_symbol
;
309 if (monetary
->duo_currency_symbol
== NULL
)
310 monetary
->duo_currency_symbol
= monetary
->currency_symbol
;
312 if (monetary
->duo_int_frac_digits
== -2)
313 monetary
->duo_int_frac_digits
= monetary
->int_frac_digits
;
314 if (monetary
->duo_frac_digits
== -2)
315 monetary
->duo_frac_digits
= monetary
->frac_digits
;
318 #define TEST_ELEM(cat, alt, min, max) \
319 if (monetary->cat == -2) \
320 monetary->cat = monetary->alt; \
321 else if ((monetary->cat < min || monetary->cat > max) && ! nothing) \
322 record_error (0, 0, _("\
323 %s: value for field `%s' must be in range %d...%d"), \
324 "LC_MONETARY", #cat, min, max)
326 TEST_ELEM (int_p_cs_precedes
, p_cs_precedes
, -1, 1);
327 TEST_ELEM (int_p_sep_by_space
, p_sep_by_space
, -1, 2);
328 TEST_ELEM (int_n_cs_precedes
, n_cs_precedes
, -1, 1);
329 TEST_ELEM (int_n_sep_by_space
, n_sep_by_space
, -1, 2);
330 TEST_ELEM (int_p_sign_posn
, p_sign_posn
, -1, 4);
331 TEST_ELEM (int_n_sign_posn
, n_sign_posn
, -1, 4);
333 TEST_ELEM (duo_p_cs_precedes
, p_cs_precedes
, -1, 1);
334 TEST_ELEM (duo_p_sep_by_space
, p_sep_by_space
, -1, 2);
335 TEST_ELEM (duo_n_cs_precedes
, n_cs_precedes
, -1, 1);
336 TEST_ELEM (duo_n_sep_by_space
, n_sep_by_space
, -1, 2);
337 TEST_ELEM (duo_int_p_cs_precedes
, int_p_cs_precedes
, -1, 1);
338 TEST_ELEM (duo_int_p_sep_by_space
, int_p_sep_by_space
, -1, 2);
339 TEST_ELEM (duo_int_n_cs_precedes
, int_n_cs_precedes
, -1, 1);
340 TEST_ELEM (duo_int_n_sep_by_space
, int_n_sep_by_space
, -1, 2);
341 TEST_ELEM (duo_p_sign_posn
, p_sign_posn
, -1, 4);
342 TEST_ELEM (duo_n_sign_posn
, n_sign_posn
, -1, 4);
343 TEST_ELEM (duo_int_p_sign_posn
, int_p_sign_posn
, -1, 4);
344 TEST_ELEM (duo_int_n_sign_posn
, int_n_sign_posn
, -1, 4);
346 if (monetary
->uno_valid_from
== 0)
347 monetary
->uno_valid_from
= 10101;
348 if (monetary
->uno_valid_to
== 0)
349 monetary
->uno_valid_to
= 99991231;
350 if (monetary
->duo_valid_from
== 0)
351 monetary
->duo_valid_from
= 10101;
352 if (monetary
->duo_valid_to
== 0)
353 monetary
->duo_valid_to
= 99991231;
355 if (monetary
->conversion_rate
[0] == 0)
357 monetary
->conversion_rate
[0] = 1;
358 monetary
->conversion_rate
[1] = 1;
361 /* Create the crncystr entry. */
362 monetary
->crncystr
= (char *) xmalloc (strlen (monetary
->currency_symbol
)
364 monetary
->crncystr
[0] = monetary
->p_cs_precedes
? '-' : '+';
365 strcpy (&monetary
->crncystr
[1], monetary
->currency_symbol
);
370 monetary_output (struct localedef_t
*locale
, const struct charmap_t
*charmap
,
371 const char *output_path
)
373 struct locale_monetary_t
*monetary
374 = locale
->categories
[LC_MONETARY
].monetary
;
375 struct locale_file file
;
377 init_locale_data (&file
, _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY
));
378 add_locale_string (&file
, monetary
->int_curr_symbol
);
379 add_locale_string (&file
, monetary
->currency_symbol
);
380 add_locale_string (&file
, monetary
->mon_decimal_point
);
381 add_locale_string (&file
, monetary
->mon_thousands_sep
);
382 add_locale_raw_data (&file
, monetary
->mon_grouping
,
383 monetary
->mon_grouping_len
);
384 add_locale_string (&file
, monetary
->positive_sign
);
385 add_locale_string (&file
, monetary
->negative_sign
);
386 add_locale_char (&file
, monetary
->int_frac_digits
);
387 add_locale_char (&file
, monetary
->frac_digits
);
388 add_locale_char (&file
, monetary
->p_cs_precedes
);
389 add_locale_char (&file
, monetary
->p_sep_by_space
);
390 add_locale_char (&file
, monetary
->n_cs_precedes
);
391 add_locale_char (&file
, monetary
->n_sep_by_space
);
392 add_locale_char (&file
, monetary
->p_sign_posn
);
393 add_locale_char (&file
, monetary
->n_sign_posn
);
394 add_locale_string (&file
, monetary
->crncystr
);
395 add_locale_char (&file
, monetary
->int_p_cs_precedes
);
396 add_locale_char (&file
, monetary
->int_p_sep_by_space
);
397 add_locale_char (&file
, monetary
->int_n_cs_precedes
);
398 add_locale_char (&file
, monetary
->int_n_sep_by_space
);
399 add_locale_char (&file
, monetary
->int_p_sign_posn
);
400 add_locale_char (&file
, monetary
->int_n_sign_posn
);
401 add_locale_string (&file
, monetary
->duo_int_curr_symbol
);
402 add_locale_string (&file
, monetary
->duo_currency_symbol
);
403 add_locale_char (&file
, monetary
->duo_int_frac_digits
);
404 add_locale_char (&file
, monetary
->duo_frac_digits
);
405 add_locale_char (&file
, monetary
->duo_p_cs_precedes
);
406 add_locale_char (&file
, monetary
->duo_p_sep_by_space
);
407 add_locale_char (&file
, monetary
->duo_n_cs_precedes
);
408 add_locale_char (&file
, monetary
->duo_n_sep_by_space
);
409 add_locale_char (&file
, monetary
->duo_int_p_cs_precedes
);
410 add_locale_char (&file
, monetary
->duo_int_p_sep_by_space
);
411 add_locale_char (&file
, monetary
->duo_int_n_cs_precedes
);
412 add_locale_char (&file
, monetary
->duo_int_n_sep_by_space
);
413 add_locale_char (&file
, monetary
->duo_p_sign_posn
);
414 add_locale_char (&file
, monetary
->duo_n_sign_posn
);
415 add_locale_char (&file
, monetary
->duo_int_p_sign_posn
);
416 add_locale_char (&file
, monetary
->duo_int_n_sign_posn
);
417 add_locale_uint32 (&file
, monetary
->uno_valid_from
);
418 add_locale_uint32 (&file
, monetary
->uno_valid_to
);
419 add_locale_uint32 (&file
, monetary
->duo_valid_from
);
420 add_locale_uint32 (&file
, monetary
->duo_valid_to
);
421 add_locale_uint32_array (&file
, monetary
->conversion_rate
, 2);
422 add_locale_uint32 (&file
, monetary
->mon_decimal_point_wc
);
423 add_locale_uint32 (&file
, monetary
->mon_thousands_sep_wc
);
424 add_locale_string (&file
, charmap
->code_set_name
);
425 write_locale_data (output_path
, LC_MONETARY
, "LC_MONETARY", &file
);
430 curr_strcmp (const char *s1
, const char **s2
)
432 return strcmp (s1
, *s2
);
436 /* The parser for the LC_MONETARY section of the locale definition. */
438 monetary_read (struct linereader
*ldfile
, struct localedef_t
*result
,
439 const struct charmap_t
*charmap
, const char *repertoire_name
,
442 struct repertoire_t
*repertoire
= NULL
;
443 struct locale_monetary_t
*monetary
;
447 /* Get the repertoire we have to use. */
448 if (repertoire_name
!= NULL
)
449 repertoire
= repertoire_read (repertoire_name
);
451 /* The rest of the line containing `LC_MONETARY' must be free. */
452 lr_ignore_rest (ldfile
, 1);
456 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
459 while (nowtok
== tok_eol
);
461 /* If we see `copy' now we are almost done. */
462 if (nowtok
== tok_copy
)
464 handle_copy (ldfile
, charmap
, repertoire_name
, result
, tok_lc_monetary
,
465 LC_MONETARY
, "LC_MONETARY", ignore_content
);
469 /* Prepare the data structures. */
470 monetary_startup (ldfile
, result
, ignore_content
);
471 monetary
= result
->categories
[LC_MONETARY
].monetary
;
475 /* Of course we don't proceed beyond the end of file. */
476 if (nowtok
== tok_eof
)
479 /* Ignore empty lines. */
480 if (nowtok
== tok_eol
)
482 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
489 #define STR_ELEM(cat) \
491 /* Ignore the rest of the line if we don't need the input of \
493 if (ignore_content) \
495 lr_ignore_rest (ldfile, 0); \
499 now = lr_token (ldfile, charmap, result, NULL, verbose); \
500 if (now->tok != tok_string) \
502 else if (monetary->cat != NULL) \
503 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
504 "LC_MONETARY", #cat); \
505 else if (!ignore_content && now->val.str.startmb == NULL) \
507 lr_error (ldfile, _("\
508 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
509 monetary->cat = ""; \
511 else if (!ignore_content) \
512 monetary->cat = now->val.str.startmb; \
513 lr_ignore_rest (ldfile, 1); \
516 STR_ELEM (int_curr_symbol
);
517 STR_ELEM (currency_symbol
);
518 STR_ELEM (positive_sign
);
519 STR_ELEM (negative_sign
);
520 STR_ELEM (duo_int_curr_symbol
);
521 STR_ELEM (duo_currency_symbol
);
523 #define STR_ELEM_WC(cat) \
525 /* Ignore the rest of the line if we don't need the input of \
527 if (ignore_content) \
529 lr_ignore_rest (ldfile, 0); \
533 ldfile->return_widestr = 1; \
534 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
535 if (now->tok != tok_string) \
537 if (monetary->cat != NULL) \
538 lr_error (ldfile, _("\
539 %s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
540 else if (!ignore_content && now->val.str.startmb == NULL) \
542 lr_error (ldfile, _("\
543 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
544 monetary->cat = ""; \
545 monetary->cat##_wc = L'\0'; \
547 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
549 lr_error (ldfile, _("\
550 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
552 else if (!ignore_content) \
554 monetary->cat = now->val.str.startmb; \
556 if (now->val.str.startwc != NULL) \
557 monetary->cat##_wc = *now->val.str.startwc; \
559 ldfile->return_widestr = 0; \
562 STR_ELEM_WC (mon_decimal_point
);
563 STR_ELEM_WC (mon_thousands_sep
);
565 #define INT_ELEM(cat) \
567 /* Ignore the rest of the line if we don't need the input of \
569 if (ignore_content) \
571 lr_ignore_rest (ldfile, 0); \
575 now = lr_token (ldfile, charmap, result, NULL, verbose); \
576 if (now->tok != tok_minus1 && now->tok != tok_number) \
578 else if (monetary->cat != -2) \
579 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
580 "LC_MONETARY", #cat); \
581 else if (!ignore_content) \
582 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
585 INT_ELEM (int_frac_digits
);
586 INT_ELEM (frac_digits
);
587 INT_ELEM (p_cs_precedes
);
588 INT_ELEM (p_sep_by_space
);
589 INT_ELEM (n_cs_precedes
);
590 INT_ELEM (n_sep_by_space
);
591 INT_ELEM (p_sign_posn
);
592 INT_ELEM (n_sign_posn
);
593 INT_ELEM (int_p_cs_precedes
);
594 INT_ELEM (int_p_sep_by_space
);
595 INT_ELEM (int_n_cs_precedes
);
596 INT_ELEM (int_n_sep_by_space
);
597 INT_ELEM (int_p_sign_posn
);
598 INT_ELEM (int_n_sign_posn
);
599 INT_ELEM (duo_int_frac_digits
);
600 INT_ELEM (duo_frac_digits
);
601 INT_ELEM (duo_p_cs_precedes
);
602 INT_ELEM (duo_p_sep_by_space
);
603 INT_ELEM (duo_n_cs_precedes
);
604 INT_ELEM (duo_n_sep_by_space
);
605 INT_ELEM (duo_p_sign_posn
);
606 INT_ELEM (duo_n_sign_posn
);
607 INT_ELEM (duo_int_p_cs_precedes
);
608 INT_ELEM (duo_int_p_sep_by_space
);
609 INT_ELEM (duo_int_n_cs_precedes
);
610 INT_ELEM (duo_int_n_sep_by_space
);
611 INT_ELEM (duo_int_p_sign_posn
);
612 INT_ELEM (duo_int_n_sign_posn
);
613 INT_ELEM (uno_valid_from
);
614 INT_ELEM (uno_valid_to
);
615 INT_ELEM (duo_valid_from
);
616 INT_ELEM (duo_valid_to
);
618 case tok_mon_grouping
:
619 /* Ignore the rest of the line if we don't need the input of
623 lr_ignore_rest (ldfile
, 0);
627 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
628 if (now
->tok
!= tok_minus1
&& now
->tok
!= tok_number
)
634 char *grouping
= ignore_content
? NULL
: xmalloc (max
);
641 grouping
= xrealloc (grouping
, max
);
644 if (act
> 0 && grouping
[act
- 1] == '\177')
646 lr_error (ldfile
, _("\
647 %s: `-1' must be last entry in `%s' field"),
648 "LC_MONETARY", "mon_grouping");
649 lr_ignore_rest (ldfile
, 0);
653 if (now
->tok
== tok_minus1
)
656 grouping
[act
++] = '\177';
658 else if (now
->val
.num
== 0)
660 /* A value of 0 disables grouping from here on but
661 we must not store a NUL character since this
662 terminates the string. Use something different
663 which must not be used otherwise. */
665 grouping
[act
++] = '\377';
667 else if (now
->val
.num
> 126)
668 lr_error (ldfile
, _("\
669 %s: values for field `%s' must be smaller than 127"),
670 "LC_MONETARY", "mon_grouping");
671 else if (!ignore_content
)
672 grouping
[act
++] = now
->val
.num
;
674 /* Next must be semicolon. */
675 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
676 if (now
->tok
!= tok_semicolon
)
679 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
681 while (now
->tok
== tok_minus1
|| now
->tok
== tok_number
);
683 if (now
->tok
!= tok_eol
)
688 /* A single -1 means no grouping. */
689 if (act
== 1 && grouping
[0] == '\177')
691 grouping
[act
++] = '\0';
693 monetary
->mon_grouping
= xrealloc (grouping
, act
);
694 monetary
->mon_grouping_len
= act
;
699 case tok_conversion_rate
:
700 /* Ignore the rest of the line if we don't need the input of
704 lr_ignore_rest (ldfile
, 0);
708 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
709 if (now
->tok
!= tok_number
)
711 if (now
->val
.num
== 0)
713 invalid_conversion_rate
:
714 lr_error (ldfile
, _("conversion rate value cannot be zero"));
717 monetary
->conversion_rate
[0] = 1;
718 monetary
->conversion_rate
[1] = 1;
723 monetary
->conversion_rate
[0] = now
->val
.num
;
724 /* Next must be a semicolon. */
725 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
726 if (now
->tok
!= tok_semicolon
)
728 /* And another number. */
729 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
730 if (now
->tok
!= tok_number
)
732 if (now
->val
.num
== 0)
733 goto invalid_conversion_rate
;
735 monetary
->conversion_rate
[1] = now
->val
.num
;
736 /* The rest of the line must be empty. */
737 lr_ignore_rest (ldfile
, 1);
741 /* Next we assume `LC_MONETARY'. */
742 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
743 if (now
->tok
== tok_eof
)
745 if (now
->tok
== tok_eol
)
746 lr_error (ldfile
, _("%s: incomplete `END' line"), "LC_MONETARY");
747 else if (now
->tok
!= tok_lc_monetary
)
748 lr_error (ldfile
, _("\
749 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
750 lr_ignore_rest (ldfile
, now
->tok
== tok_lc_monetary
);
755 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
758 /* Prepare for the next round. */
759 now
= lr_token (ldfile
, charmap
, result
, NULL
, verbose
);
763 /* When we come here we reached the end of the file. */
764 lr_error (ldfile
, _("%s: premature end of file"), "LC_MONETARY");