]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/ld-monetary.c
Prefer https to http for gnu.org and fsf.org URLs
[thirdparty/glibc.git] / locale / programs / ld-monetary.c
CommitLineData
04277e02 1/* Copyright (C) 1995-2019 Free Software Foundation, Inc.
c84142e8 2 This file is part of the GNU C Library.
4b10dd6c 3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
19bc17a9 4
43bc8ac6 5 This program is free software; you can redistribute it and/or modify
2e2efe65
RM
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.
19bc17a9 9
43bc8ac6 10 This program is distributed in the hope that it will be useful,
c84142e8 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
43bc8ac6
UD
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
19bc17a9 14
43bc8ac6 15 You should have received a copy of the GNU General Public License
5a82c748 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
19bc17a9
RM
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
4b10dd6c 22#include <byteswap.h>
19bc17a9
RM
23#include <langinfo.h>
24#include <limits.h>
25#include <stdlib.h>
26#include <string.h>
e054f494 27#include <stdint.h>
4b10dd6c 28#include <sys/uio.h>
19bc17a9 29
19bc17a9
RM
30#include <assert.h>
31
4b10dd6c 32#include "localedef.h"
f2b98f97 33#include "linereader.h"
19bc17a9 34#include "localeinfo.h"
4b10dd6c 35#include "locfile.h"
19bc17a9
RM
36
37
4b10dd6c 38/* The real definition of the struct for the LC_MONETARY locale. */
19bc17a9
RM
39struct locale_monetary_t
40{
41 const char *int_curr_symbol;
42 const char *currency_symbol;
43 const char *mon_decimal_point;
44 const char *mon_thousands_sep;
4295702f
UD
45 uint32_t mon_decimal_point_wc;
46 uint32_t mon_thousands_sep_wc;
19bc17a9 47 char *mon_grouping;
4b10dd6c 48 size_t mon_grouping_len;
19bc17a9
RM
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;
4b10dd6c
UD
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];
a58a4763 86 char *crncystr;
19bc17a9
RM
87};
88
89
4b10dd6c 90/* The content iof the field int_curr_symbol has to be taken from
19bc17a9
RM
91 ISO-4217. We test for correct values. */
92#define DEFINE_INT_CURR(str) str,
93static const char *const valid_int_curr[] =
94 {
95# include "../iso-4217.def"
96 };
97#define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
98 / sizeof (valid_int_curr[0])))
99#undef DEFINE_INT_CURR
100
101
102/* Prototypes for local functions. */
4b10dd6c 103static int curr_strcmp (const char *s1, const char **s2);
19bc17a9
RM
104
105
4b10dd6c 106static void
19bc17a9 107monetary_startup (struct linereader *lr, struct localedef_t *locale,
4b10dd6c 108 int ignore_content)
19bc17a9 109{
4b10dd6c
UD
110 if (!ignore_content)
111 {
112 struct locale_monetary_t *monetary;
113
114 locale->categories[LC_MONETARY].monetary = monetary =
115 (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
116
117 memset (monetary, '\0', sizeof (struct locale_monetary_t));
118
119 monetary->mon_grouping = NULL;
120 monetary->mon_grouping_len = 0;
121
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;
150 }
19bc17a9 151
b9eb05d6
UD
152 if (lr != NULL)
153 {
154 lr->translate_strings = 1;
0d54f746 155 lr->return_widestr = 0;
b9eb05d6 156 }
19bc17a9
RM
157}
158
159
160void
47e8b443 161monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
19bc17a9
RM
162{
163 struct locale_monetary_t *monetary
164 = locale->categories[LC_MONETARY].monetary;
b9eb05d6
UD
165 int nothing = 0;
166
167 /* Now resolve copying and also handle completely missing definitions. */
168 if (monetary == NULL)
169 {
170 /* First see whether we were supposed to copy. If yes, find the
171 actual definition. */
172 if (locale->copy_name[LC_MONETARY] != NULL)
173 {
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;
177
178 do
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);
183
184 monetary = locale->categories[LC_MONETARY].monetary
185 = from->categories[LC_MONETARY].monetary;
186 }
187
f16491eb 188 /* If there is still no definition issue a warning and create an
b9eb05d6
UD
189 empty one. */
190 if (monetary == NULL)
191 {
f16491eb
CD
192 record_warning (_("\
193No definition for %s category found"), "LC_MONETARY");
b9eb05d6
UD
194 monetary_startup (NULL, locale, 0);
195 monetary = locale->categories[LC_MONETARY].monetary;
196 nothing = 1;
197 }
198 }
19bc17a9 199
443470c3 200#define TEST_ELEM(cat, initval) \
f6ada7ad 201 if (monetary->cat == NULL) \
4b10dd6c 202 { \
f16491eb
CD
203 if (! nothing) \
204 record_error (0, 0, _("%s: field `%s' not defined"), \
205 "LC_MONETARY", #cat); \
443470c3 206 monetary->cat = initval; \
4b10dd6c 207 }
19bc17a9 208
443470c3
UD
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, "");
19bc17a9
RM
215
216 /* The international currency symbol must come from ISO 4217. */
217 if (monetary->int_curr_symbol != NULL)
218 {
a3e23a2c
CD
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)
880f421f 226 {
f16491eb
CD
227 if (! nothing)
228 record_error (0, 0, _("\
4b10dd6c 229%s: value of field `int_curr_symbol' has wrong length"),
f16491eb 230 "LC_MONETARY");
880f421f 231 }
a3e23a2c 232 else if (ics_len == 4)
ab18a27d
UD
233 { /* Check the first three characters against ISO 4217 */
234 char symbol[4];
235 strncpy (symbol, monetary->int_curr_symbol, 3);
236 symbol[3] = '\0';
02eec681
CD
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. */
ab18a27d
UD
241 if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
242 sizeof (const char *),
02eec681
CD
243 (comparison_fn_t) curr_strcmp) == NULL
244 && warn_int_curr_symbol)
f16491eb 245 record_warning (_("\
4b10dd6c 246%s: value of field `int_curr_symbol' does \
02eec681 247not correspond to a valid name in ISO 4217 [--no-warnings=intcurrsym]"),
f16491eb 248 "LC_MONETARY");
ab18a27d 249 }
19bc17a9
RM
250 }
251
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
254 != "". */
f6ada7ad
UD
255 if (monetary->mon_decimal_point == NULL)
256 {
f16491eb
CD
257 if (! nothing)
258 record_error (0, 0, _("%s: field `%s' not defined"),
259 "LC_MONETARY", "mon_decimal_point");
443470c3 260 monetary->mon_decimal_point = ".";
f6ada7ad
UD
261 }
262 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
19bc17a9 263 {
f16491eb 264 record_error (0, 0, _("\
11bf311e 265%s: value for field `%s' must not be an empty string"),
f16491eb 266 "LC_MONETARY", "mon_decimal_point");
19bc17a9 267 }
4295702f
UD
268 if (monetary->mon_decimal_point_wc == L'\0')
269 monetary->mon_decimal_point_wc = L'.';
19bc17a9 270
f1d8b804
UD
271 if (monetary->mon_grouping_len == 0)
272 {
f16491eb
CD
273 if (! nothing)
274 record_error (0, 0, _("%s: field `%s' not defined"),
275 "LC_MONETARY", "mon_grouping");
f1d8b804 276
575b273b 277 monetary->mon_grouping = (char *) "\177";
f1d8b804
UD
278 monetary->mon_grouping_len = 1;
279 }
19bc17a9
RM
280
281#undef TEST_ELEM
443470c3 282#define TEST_ELEM(cat, min, max, initval) \
f6ada7ad
UD
283 if (monetary->cat == -2) \
284 { \
f16491eb
CD
285 if (! nothing) \
286 record_error (0, 0, _("%s: field `%s' not defined"), \
287 "LC_MONETARY", #cat); \
443470c3 288 monetary->cat = initval; \
f6ada7ad 289 } \
443470c3 290 else if ((monetary->cat < min || monetary->cat > max) \
cedb4109 291 && min < max \
443470c3 292 && !be_quiet && !nothing) \
f16491eb 293 record_error (0, 0, _("\
4b10dd6c 294%s: value for field `%s' must be in range %d...%d"), \
f16491eb 295 "LC_MONETARY", #cat, min, max)
19bc17a9 296
cedb4109
UD
297 TEST_ELEM (int_frac_digits, 1, 0, -1);
298 TEST_ELEM (frac_digits, 1, 0, -1);
443470c3
UD
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);
4b10dd6c
UD
305
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;
311
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;
316
317#undef TEST_ELEM
318#define TEST_ELEM(cat, alt, min, max) \
b9eb05d6 319 if (monetary->cat == -2) \
4b10dd6c 320 monetary->cat = monetary->alt; \
f16491eb
CD
321 else if ((monetary->cat < min || monetary->cat > max) && ! nothing) \
322 record_error (0, 0, _("\
4b10dd6c 323%s: value for field `%s' must be in range %d...%d"), \
f16491eb 324 "LC_MONETARY", #cat, min, max)
4b10dd6c
UD
325
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);
332
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);
345
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;
354
355 if (monetary->conversion_rate[0] == 0)
356 {
357 monetary->conversion_rate[0] = 1;
358 monetary->conversion_rate[1] = 1;
359 }
a58a4763
UD
360
361 /* Create the crncystr entry. */
362 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
363 + 2);
364 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
365 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
19bc17a9
RM
366}
367
368
369void
47e8b443 370monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
4b10dd6c 371 const char *output_path)
19bc17a9
RM
372{
373 struct locale_monetary_t *monetary
374 = locale->categories[LC_MONETARY].monetary;
1ecbb381
RS
375 struct locale_file file;
376
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);
19bc17a9
RM
426}
427
428
4b10dd6c
UD
429static int
430curr_strcmp (const char *s1, const char **s2)
431{
432 return strcmp (s1, *s2);
433}
434
435
436/* The parser for the LC_MONETARY section of the locale definition. */
19bc17a9 437void
4b10dd6c 438monetary_read (struct linereader *ldfile, struct localedef_t *result,
47e8b443 439 const struct charmap_t *charmap, const char *repertoire_name,
4b10dd6c 440 int ignore_content)
19bc17a9 441{
0d54f746 442 struct repertoire_t *repertoire = NULL;
4b10dd6c
UD
443 struct locale_monetary_t *monetary;
444 struct token *now;
445 enum token_t nowtok;
446
0d54f746
UD
447 /* Get the repertoire we have to use. */
448 if (repertoire_name != NULL)
449 repertoire = repertoire_read (repertoire_name);
450
4b10dd6c
UD
451 /* The rest of the line containing `LC_MONETARY' must be free. */
452 lr_ignore_rest (ldfile, 1);
453
454 do
455 {
47e8b443 456 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
457 nowtok = now->tok;
458 }
459 while (nowtok == tok_eol);
460
461 /* If we see `copy' now we are almost done. */
462 if (nowtok == tok_copy)
463 {
01ff9d0b 464 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
b9eb05d6 465 LC_MONETARY, "LC_MONETARY", ignore_content);
4b10dd6c
UD
466 return;
467 }
468
469 /* Prepare the data structures. */
470 monetary_startup (ldfile, result, ignore_content);
471 monetary = result->categories[LC_MONETARY].monetary;
19bc17a9 472
4b10dd6c 473 while (1)
19bc17a9 474 {
4b10dd6c
UD
475 /* Of course we don't proceed beyond the end of file. */
476 if (nowtok == tok_eof)
477 break;
478
42d7c593 479 /* Ignore empty lines. */
4b10dd6c 480 if (nowtok == tok_eol)
19bc17a9 481 {
47e8b443 482 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
483 nowtok = now->tok;
484 continue;
19bc17a9 485 }
4b10dd6c
UD
486
487 switch (nowtok)
19bc17a9 488 {
4b10dd6c
UD
489#define STR_ELEM(cat) \
490 case tok_##cat: \
b9eb05d6
UD
491 /* Ignore the rest of the line if we don't need the input of \
492 this line. */ \
493 if (ignore_content) \
494 { \
495 lr_ignore_rest (ldfile, 0); \
496 break; \
497 } \
498 \
47e8b443 499 now = lr_token (ldfile, charmap, result, NULL, verbose); \
4b10dd6c
UD
500 if (now->tok != tok_string) \
501 goto err_label; \
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) \
506 { \
507 lr_error (ldfile, _("\
508%s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
509 monetary->cat = ""; \
510 } \
511 else if (!ignore_content) \
512 monetary->cat = now->val.str.startmb; \
513 lr_ignore_rest (ldfile, 1); \
514 break
515
516 STR_ELEM (int_curr_symbol);
517 STR_ELEM (currency_symbol);
4b10dd6c
UD
518 STR_ELEM (positive_sign);
519 STR_ELEM (negative_sign);
520 STR_ELEM (duo_int_curr_symbol);
521 STR_ELEM (duo_currency_symbol);
522
4295702f
UD
523#define STR_ELEM_WC(cat) \
524 case tok_##cat: \
525 /* Ignore the rest of the line if we don't need the input of \
526 this line. */ \
527 if (ignore_content) \
528 { \
529 lr_ignore_rest (ldfile, 0); \
530 break; \
531 } \
532 \
0d54f746 533 ldfile->return_widestr = 1; \
47e8b443 534 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
4295702f
UD
535 if (now->tok != tok_string) \
536 goto err_label; \
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) \
541 { \
542 lr_error (ldfile, _("\
543%s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
544 monetary->cat = ""; \
545 monetary->cat##_wc = L'\0'; \
546 } \
aec103d3 547 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
4295702f
UD
548 { \
549 lr_error (ldfile, _("\
550%s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
551 } \
552 else if (!ignore_content) \
553 { \
554 monetary->cat = now->val.str.startmb; \
555 \
556 if (now->val.str.startwc != NULL) \
557 monetary->cat##_wc = *now->val.str.startwc; \
558 } \
0d54f746 559 ldfile->return_widestr = 0; \
4295702f
UD
560 break
561
562 STR_ELEM_WC (mon_decimal_point);
563 STR_ELEM_WC (mon_thousands_sep);
564
4b10dd6c
UD
565#define INT_ELEM(cat) \
566 case tok_##cat: \
b9eb05d6
UD
567 /* Ignore the rest of the line if we don't need the input of \
568 this line. */ \
569 if (ignore_content) \
570 { \
571 lr_ignore_rest (ldfile, 0); \
572 break; \
573 } \
574 \
47e8b443 575 now = lr_token (ldfile, charmap, result, NULL, verbose); \
4b10dd6c
UD
576 if (now->tok != tok_minus1 && now->tok != tok_number) \
577 goto err_label; \
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; \
583 break
584
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);
617
618 case tok_mon_grouping:
b9eb05d6
UD
619 /* Ignore the rest of the line if we don't need the input of
620 this line. */
621 if (ignore_content)
622 {
623 lr_ignore_rest (ldfile, 0);
624 break;
625 }
626
47e8b443 627 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
628 if (now->tok != tok_minus1 && now->tok != tok_number)
629 goto err_label;
19bc17a9 630 else
4b10dd6c
UD
631 {
632 size_t act = 0;
633 size_t max = 10;
634 char *grouping = ignore_content ? NULL : xmalloc (max);
635
636 do
637 {
638 if (act + 1 >= max)
639 {
640 max *= 2;
641 grouping = xrealloc (grouping, max);
642 }
643
644 if (act > 0 && grouping[act - 1] == '\177')
645 {
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);
650 break;
651 }
652
653 if (now->tok == tok_minus1)
654 {
655 if (!ignore_content)
656 grouping[act++] = '\177';
657 }
658 else if (now->val.num == 0)
659 {
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. */
664 if (!ignore_content)
665 grouping[act++] = '\377';
666 }
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;
673
674 /* Next must be semicolon. */
47e8b443 675 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
676 if (now->tok != tok_semicolon)
677 break;
678
47e8b443 679 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
680 }
681 while (now->tok == tok_minus1 || now->tok == tok_number);
682
683 if (now->tok != tok_eol)
684 goto err_label;
685
686 if (!ignore_content)
687 {
a7931fcf
AS
688 /* A single -1 means no grouping. */
689 if (act == 1 && grouping[0] == '\177')
690 act--;
4b10dd6c
UD
691 grouping[act++] = '\0';
692
693 monetary->mon_grouping = xrealloc (grouping, act);
694 monetary->mon_grouping_len = act;
695 }
696 }
697 break;
698
699 case tok_conversion_rate:
b9eb05d6
UD
700 /* Ignore the rest of the line if we don't need the input of
701 this line. */
702 if (ignore_content)
703 {
704 lr_ignore_rest (ldfile, 0);
705 break;
706 }
707
47e8b443 708 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
709 if (now->tok != tok_number)
710 goto err_label;
711 if (now->val.num == 0)
712 {
713 invalid_conversion_rate:
6d77214d 714 lr_error (ldfile, _("conversion rate value cannot be zero"));
4b10dd6c
UD
715 if (!ignore_content)
716 {
717 monetary->conversion_rate[0] = 1;
718 monetary->conversion_rate[1] = 1;
719 }
720 break;
721 }
722 if (!ignore_content)
723 monetary->conversion_rate[0] = now->val.num;
724 /* Next must be a semicolon. */
47e8b443 725 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
726 if (now->tok != tok_semicolon)
727 goto err_label;
728 /* And another number. */
47e8b443 729 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
730 if (now->tok != tok_number)
731 goto err_label;
732 if (now->val.num == 0)
733 goto invalid_conversion_rate;
734 if (!ignore_content)
735 monetary->conversion_rate[1] = now->val.num;
736 /* The rest of the line must be empty. */
737 lr_ignore_rest (ldfile, 1);
738 break;
739
740 case tok_end:
741 /* Next we assume `LC_MONETARY'. */
47e8b443 742 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
743 if (now->tok == tok_eof)
744 break;
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);
751 return;
752
753 default:
754 err_label:
755 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
19bc17a9 756 }
19bc17a9 757
4b10dd6c 758 /* Prepare for the next round. */
47e8b443 759 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c 760 nowtok = now->tok;
19bc17a9 761 }
19bc17a9 762
4b10dd6c
UD
763 /* When we come here we reached the end of the file. */
764 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
19bc17a9 765}