]> git.ipfire.org Git - thirdparty/glibc.git/blame - locale/programs/ld-monetary.c
Update copyright notices with scripts/update-copyrights.
[thirdparty/glibc.git] / locale / programs / ld-monetary.c
CommitLineData
568035b7 1/* Copyright (C) 1995-2013 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
59ba27a6 16 along with this program; if not, see <http://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>
4b10dd6c 27#include <sys/uio.h>
19bc17a9 28
19bc17a9
RM
29#include <assert.h>
30
4b10dd6c 31#include "localedef.h"
f2b98f97 32#include "linereader.h"
19bc17a9 33#include "localeinfo.h"
4b10dd6c 34#include "locfile.h"
19bc17a9
RM
35
36
4b10dd6c 37/* The real definition of the struct for the LC_MONETARY locale. */
19bc17a9
RM
38struct locale_monetary_t
39{
40 const char *int_curr_symbol;
41 const char *currency_symbol;
42 const char *mon_decimal_point;
43 const char *mon_thousands_sep;
4295702f
UD
44 uint32_t mon_decimal_point_wc;
45 uint32_t mon_thousands_sep_wc;
19bc17a9 46 char *mon_grouping;
4b10dd6c 47 size_t mon_grouping_len;
19bc17a9
RM
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;
4b10dd6c
UD
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];
a58a4763 85 char *crncystr;
19bc17a9
RM
86};
87
88
4b10dd6c 89/* The content iof the field int_curr_symbol has to be taken from
19bc17a9
RM
90 ISO-4217. We test for correct values. */
91#define DEFINE_INT_CURR(str) str,
92static const char *const valid_int_curr[] =
93 {
94# include "../iso-4217.def"
95 };
96#define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
97 / sizeof (valid_int_curr[0])))
98#undef DEFINE_INT_CURR
99
100
101/* Prototypes for local functions. */
4b10dd6c 102static int curr_strcmp (const char *s1, const char **s2);
19bc17a9
RM
103
104
4b10dd6c 105static void
19bc17a9 106monetary_startup (struct linereader *lr, struct localedef_t *locale,
4b10dd6c 107 int ignore_content)
19bc17a9 108{
4b10dd6c
UD
109 if (!ignore_content)
110 {
111 struct locale_monetary_t *monetary;
112
113 locale->categories[LC_MONETARY].monetary = monetary =
114 (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
115
116 memset (monetary, '\0', sizeof (struct locale_monetary_t));
117
118 monetary->mon_grouping = NULL;
119 monetary->mon_grouping_len = 0;
120
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;
149 }
19bc17a9 150
b9eb05d6
UD
151 if (lr != NULL)
152 {
153 lr->translate_strings = 1;
0d54f746 154 lr->return_widestr = 0;
b9eb05d6 155 }
19bc17a9
RM
156}
157
158
159void
47e8b443 160monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
19bc17a9
RM
161{
162 struct locale_monetary_t *monetary
163 = locale->categories[LC_MONETARY].monetary;
b9eb05d6
UD
164 int nothing = 0;
165
166 /* Now resolve copying and also handle completely missing definitions. */
167 if (monetary == NULL)
168 {
169 /* First see whether we were supposed to copy. If yes, find the
170 actual definition. */
171 if (locale->copy_name[LC_MONETARY] != NULL)
172 {
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;
176
177 do
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);
182
183 monetary = locale->categories[LC_MONETARY].monetary
184 = from->categories[LC_MONETARY].monetary;
185 }
186
187 /* If there is still no definition issue an warning and create an
188 empty one. */
189 if (monetary == NULL)
190 {
f6ada7ad 191 if (! be_quiet)
f2b98f97
UD
192 WITH_CUR_LOCALE (error (0, 0, _("\
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 { \
f6ada7ad 203 if (! be_quiet && ! nothing) \
f2b98f97
UD
204 WITH_CUR_LOCALE (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 {
4b10dd6c 219 if (strlen (monetary->int_curr_symbol) != 4)
880f421f 220 {
a2236316 221 if (! be_quiet && ! nothing)
f2b98f97 222 WITH_CUR_LOCALE (error (0, 0, _("\
4b10dd6c 223%s: value of field `int_curr_symbol' has wrong length"),
f2b98f97 224 "LC_MONETARY"));
880f421f 225 }
ab18a27d
UD
226 else
227 { /* Check the first three characters against ISO 4217 */
228 char symbol[4];
229 strncpy (symbol, monetary->int_curr_symbol, 3);
230 symbol[3] = '\0';
231 if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
232 sizeof (const char *),
233 (comparison_fn_t) curr_strcmp) == NULL
c84142e8 234 && !be_quiet)
ab18a27d 235 WITH_CUR_LOCALE (error (0, 0, _("\
4b10dd6c
UD
236%s: value of field `int_curr_symbol' does \
237not correspond to a valid name in ISO 4217"),
f2b98f97 238 "LC_MONETARY"));
ab18a27d 239 }
19bc17a9
RM
240 }
241
242 /* The decimal point must not be empty. This is not said explicitly
243 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
244 != "". */
f6ada7ad
UD
245 if (monetary->mon_decimal_point == NULL)
246 {
247 if (! be_quiet && ! nothing)
f2b98f97
UD
248 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
249 "LC_MONETARY", "mon_decimal_point"));
443470c3 250 monetary->mon_decimal_point = ".";
f6ada7ad
UD
251 }
252 else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
19bc17a9 253 {
f2b98f97 254 WITH_CUR_LOCALE (error (0, 0, _("\
11bf311e 255%s: value for field `%s' must not be an empty string"),
f2b98f97 256 "LC_MONETARY", "mon_decimal_point"));
19bc17a9 257 }
4295702f
UD
258 if (monetary->mon_decimal_point_wc == L'\0')
259 monetary->mon_decimal_point_wc = L'.';
19bc17a9 260
f1d8b804
UD
261 if (monetary->mon_grouping_len == 0)
262 {
263 if (! be_quiet && ! nothing)
f2b98f97
UD
264 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
265 "LC_MONETARY", "mon_grouping"));
f1d8b804 266
575b273b 267 monetary->mon_grouping = (char *) "\177";
f1d8b804
UD
268 monetary->mon_grouping_len = 1;
269 }
19bc17a9
RM
270
271#undef TEST_ELEM
443470c3 272#define TEST_ELEM(cat, min, max, initval) \
f6ada7ad
UD
273 if (monetary->cat == -2) \
274 { \
275 if (! be_quiet && ! nothing) \
f2b98f97
UD
276 WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"), \
277 "LC_MONETARY", #cat)); \
443470c3 278 monetary->cat = initval; \
f6ada7ad 279 } \
443470c3 280 else if ((monetary->cat < min || monetary->cat > max) \
cedb4109 281 && min < max \
443470c3 282 && !be_quiet && !nothing) \
f2b98f97 283 WITH_CUR_LOCALE (error (0, 0, _("\
4b10dd6c 284%s: value for field `%s' must be in range %d...%d"), \
f2b98f97 285 "LC_MONETARY", #cat, min, max))
19bc17a9 286
cedb4109
UD
287 TEST_ELEM (int_frac_digits, 1, 0, -1);
288 TEST_ELEM (frac_digits, 1, 0, -1);
443470c3
UD
289 TEST_ELEM (p_cs_precedes, -1, 1, -1);
290 TEST_ELEM (p_sep_by_space, -1, 2, -1);
291 TEST_ELEM (n_cs_precedes, -1, 1, -1);
292 TEST_ELEM (n_sep_by_space, -1, 2, -1);
293 TEST_ELEM (p_sign_posn, -1, 4, -1);
294 TEST_ELEM (n_sign_posn, -1, 4, -1);
4b10dd6c
UD
295
296 /* The non-POSIX.2 extensions are optional. */
297 if (monetary->duo_int_curr_symbol == NULL)
298 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
299 if (monetary->duo_currency_symbol == NULL)
300 monetary->duo_currency_symbol = monetary->currency_symbol;
301
302 if (monetary->duo_int_frac_digits == -2)
303 monetary->duo_int_frac_digits = monetary->int_frac_digits;
304 if (monetary->duo_frac_digits == -2)
305 monetary->duo_frac_digits = monetary->frac_digits;
306
307#undef TEST_ELEM
308#define TEST_ELEM(cat, alt, min, max) \
b9eb05d6 309 if (monetary->cat == -2) \
4b10dd6c 310 monetary->cat = monetary->alt; \
b9eb05d6
UD
311 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
312 && ! nothing) \
f2b98f97 313 WITH_CUR_LOCALE (error (0, 0, _("\
4b10dd6c 314%s: value for field `%s' must be in range %d...%d"), \
f2b98f97 315 "LC_MONETARY", #cat, min, max))
4b10dd6c
UD
316
317 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
318 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
319 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
320 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
321 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
322 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
323
324 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
325 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
326 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
327 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
328 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
329 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
330 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
331 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
332 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
333 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
334 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
335 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
336
337 if (monetary->uno_valid_from == 0)
338 monetary->uno_valid_from = 10101;
339 if (monetary->uno_valid_to == 0)
340 monetary->uno_valid_to = 99991231;
341 if (monetary->duo_valid_from == 0)
342 monetary->duo_valid_from = 10101;
343 if (monetary->duo_valid_to == 0)
344 monetary->duo_valid_to = 99991231;
345
346 if (monetary->conversion_rate[0] == 0)
347 {
348 monetary->conversion_rate[0] = 1;
349 monetary->conversion_rate[1] = 1;
350 }
a58a4763
UD
351
352 /* Create the crncystr entry. */
353 monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
354 + 2);
355 monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
356 strcpy (&monetary->crncystr[1], monetary->currency_symbol);
19bc17a9
RM
357}
358
359
360void
47e8b443 361monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
4b10dd6c 362 const char *output_path)
19bc17a9
RM
363{
364 struct locale_monetary_t *monetary
365 = locale->categories[LC_MONETARY].monetary;
a0edd63e 366 struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
19bc17a9 367 struct locale_file data;
4b10dd6c 368 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
19bc17a9
RM
369 size_t cnt = 0;
370
19bc17a9
RM
371 data.magic = LIMAGIC (LC_MONETARY);
372 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
373 iov[cnt].iov_base = (void *) &data;
374 iov[cnt].iov_len = sizeof (data);
375 ++cnt;
376
377 iov[cnt].iov_base = (void *) idx;
378 iov[cnt].iov_len = sizeof (idx);
379 ++cnt;
380
381 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
4b10dd6c 382 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
19bc17a9
RM
383 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
384 ++cnt;
385
386 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c 387 iov[cnt].iov_base = (void *) monetary->currency_symbol;
19bc17a9
RM
388 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
389 ++cnt;
390
391 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c 392 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
19bc17a9
RM
393 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
394 ++cnt;
395
396 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c 397 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
19bc17a9
RM
398 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
399 ++cnt;
400
401 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c
UD
402 iov[cnt].iov_base = monetary->mon_grouping;
403 iov[cnt].iov_len = monetary->mon_grouping_len;
19bc17a9
RM
404 ++cnt;
405
406 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c 407 iov[cnt].iov_base = (void *) monetary->positive_sign;
19bc17a9
RM
408 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
409 ++cnt;
410
411 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c 412 iov[cnt].iov_base = (void *) monetary->negative_sign;
19bc17a9
RM
413 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
414 ++cnt;
415
416 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
417 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
418 iov[cnt].iov_len = 1;
419 ++cnt;
420
421 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
422 iov[cnt].iov_base = (void *) &monetary->frac_digits;
423 iov[cnt].iov_len = 1;
424 ++cnt;
425
426 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
427 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
428 iov[cnt].iov_len = 1;
429 ++cnt;
430
431 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
432 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
433 iov[cnt].iov_len = 1;
434 ++cnt;
435
436 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
437 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
438 iov[cnt].iov_len = 1;
439 ++cnt;
440
441 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
442 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
443 iov[cnt].iov_len = 1;
444 ++cnt;
445
446 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
447 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
448 iov[cnt].iov_len = 1;
449 ++cnt;
450
451 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
452 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
453 iov[cnt].iov_len = 1;
4b10dd6c
UD
454 ++cnt;
455
a58a4763 456 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
a0edd63e 457 iov[cnt].iov_base = (void *) monetary->crncystr;
a58a4763
UD
458 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
459 ++cnt;
460
4b10dd6c
UD
461 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
462 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
463 iov[cnt].iov_len = 1;
464 ++cnt;
465
466 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
467 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
468 iov[cnt].iov_len = 1;
469 ++cnt;
470
471 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
472 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
473 iov[cnt].iov_len = 1;
474 ++cnt;
475
476 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
477 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
478 iov[cnt].iov_len = 1;
479 ++cnt;
19bc17a9 480
4b10dd6c
UD
481 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
482 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
483 iov[cnt].iov_len = 1;
484 ++cnt;
485
486 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
487 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
488 iov[cnt].iov_len = 1;
489 ++cnt;
490
a0edd63e 491 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
4b10dd6c
UD
492 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
493 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
494 ++cnt;
495
496 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
497 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
498 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
499 ++cnt;
500
501 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
502 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
503 iov[cnt].iov_len = 1;
504 ++cnt;
505
506 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
507 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
508 iov[cnt].iov_len = 1;
509 ++cnt;
510
511 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
512 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
513 iov[cnt].iov_len = 1;
514 ++cnt;
515
516 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
517 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
518 iov[cnt].iov_len = 1;
519 ++cnt;
520
521 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
522 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
523 iov[cnt].iov_len = 1;
524 ++cnt;
525
526 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
527 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
528 iov[cnt].iov_len = 1;
529 ++cnt;
530
531 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
532 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
533 iov[cnt].iov_len = 1;
534 ++cnt;
535
536 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
537 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
538 iov[cnt].iov_len = 1;
539 ++cnt;
540
541 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
542 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
543 iov[cnt].iov_len = 1;
544 ++cnt;
545
546 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
547 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
548 iov[cnt].iov_len = 1;
549 ++cnt;
550
551 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
552 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
553 iov[cnt].iov_len = 1;
554 ++cnt;
555
556 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
557 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
558 iov[cnt].iov_len = 1;
559 ++cnt;
560
561 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
562 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
563 iov[cnt].iov_len = 1;
564 ++cnt;
565
566 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
567 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
568 iov[cnt].iov_len = 1;
569 ++cnt;
570
571 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
a0edd63e
UD
572
573 /* Align following data */
574 iov[cnt].iov_base = (void *) "\0\0";
575 iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
576 idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
577 ++cnt;
578
4b10dd6c 579 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
a0edd63e 580 iov[cnt].iov_len = sizeof(uint32_t);
4b10dd6c
UD
581 ++cnt;
582
a0edd63e 583 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
4b10dd6c 584 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
a0edd63e 585 iov[cnt].iov_len = sizeof(uint32_t);
4b10dd6c
UD
586 ++cnt;
587
a0edd63e 588 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
4b10dd6c 589 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
a0edd63e 590 iov[cnt].iov_len = sizeof(uint32_t);
4b10dd6c
UD
591 ++cnt;
592
a0edd63e 593 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
4b10dd6c 594 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
a0edd63e 595 iov[cnt].iov_len = sizeof(uint32_t);
4b10dd6c
UD
596 ++cnt;
597
a0edd63e 598 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
90952c77 599 iov[cnt].iov_base = (void *) monetary->conversion_rate;
a0edd63e 600 iov[cnt].iov_len = 2 * sizeof(uint32_t);
4b10dd6c
UD
601 ++cnt;
602
a0edd63e 603 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
4295702f
UD
604 iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
605 iov[cnt].iov_len = sizeof (uint32_t);
606 ++cnt;
607
a0edd63e 608 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
4295702f
UD
609 iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
610 iov[cnt].iov_len = sizeof (uint32_t);
611 ++cnt;
612
e7f21fa6
UD
613 idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
614 iov[cnt].iov_base = (void *) charmap->code_set_name;
615 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
616 ++cnt;
617
a0edd63e 618 assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
19bc17a9 619
a7b65cdc 620 write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
a0edd63e 621 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
19bc17a9
RM
622}
623
624
4b10dd6c
UD
625static int
626curr_strcmp (const char *s1, const char **s2)
627{
628 return strcmp (s1, *s2);
629}
630
631
632/* The parser for the LC_MONETARY section of the locale definition. */
19bc17a9 633void
4b10dd6c 634monetary_read (struct linereader *ldfile, struct localedef_t *result,
47e8b443 635 const struct charmap_t *charmap, const char *repertoire_name,
4b10dd6c 636 int ignore_content)
19bc17a9 637{
0d54f746 638 struct repertoire_t *repertoire = NULL;
4b10dd6c
UD
639 struct locale_monetary_t *monetary;
640 struct token *now;
641 enum token_t nowtok;
642
0d54f746
UD
643 /* Get the repertoire we have to use. */
644 if (repertoire_name != NULL)
645 repertoire = repertoire_read (repertoire_name);
646
4b10dd6c
UD
647 /* The rest of the line containing `LC_MONETARY' must be free. */
648 lr_ignore_rest (ldfile, 1);
649
650 do
651 {
47e8b443 652 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
653 nowtok = now->tok;
654 }
655 while (nowtok == tok_eol);
656
657 /* If we see `copy' now we are almost done. */
658 if (nowtok == tok_copy)
659 {
01ff9d0b 660 handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
b9eb05d6 661 LC_MONETARY, "LC_MONETARY", ignore_content);
4b10dd6c
UD
662 return;
663 }
664
665 /* Prepare the data structures. */
666 monetary_startup (ldfile, result, ignore_content);
667 monetary = result->categories[LC_MONETARY].monetary;
19bc17a9 668
4b10dd6c 669 while (1)
19bc17a9 670 {
4b10dd6c
UD
671 /* Of course we don't proceed beyond the end of file. */
672 if (nowtok == tok_eof)
673 break;
674
42d7c593 675 /* Ignore empty lines. */
4b10dd6c 676 if (nowtok == tok_eol)
19bc17a9 677 {
47e8b443 678 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
679 nowtok = now->tok;
680 continue;
19bc17a9 681 }
4b10dd6c
UD
682
683 switch (nowtok)
19bc17a9 684 {
4b10dd6c
UD
685#define STR_ELEM(cat) \
686 case tok_##cat: \
b9eb05d6
UD
687 /* Ignore the rest of the line if we don't need the input of \
688 this line. */ \
689 if (ignore_content) \
690 { \
691 lr_ignore_rest (ldfile, 0); \
692 break; \
693 } \
694 \
47e8b443 695 now = lr_token (ldfile, charmap, result, NULL, verbose); \
4b10dd6c
UD
696 if (now->tok != tok_string) \
697 goto err_label; \
698 else if (monetary->cat != NULL) \
699 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
700 "LC_MONETARY", #cat); \
701 else if (!ignore_content && now->val.str.startmb == NULL) \
702 { \
703 lr_error (ldfile, _("\
704%s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
705 monetary->cat = ""; \
706 } \
707 else if (!ignore_content) \
708 monetary->cat = now->val.str.startmb; \
709 lr_ignore_rest (ldfile, 1); \
710 break
711
712 STR_ELEM (int_curr_symbol);
713 STR_ELEM (currency_symbol);
4b10dd6c
UD
714 STR_ELEM (positive_sign);
715 STR_ELEM (negative_sign);
716 STR_ELEM (duo_int_curr_symbol);
717 STR_ELEM (duo_currency_symbol);
718
4295702f
UD
719#define STR_ELEM_WC(cat) \
720 case tok_##cat: \
721 /* Ignore the rest of the line if we don't need the input of \
722 this line. */ \
723 if (ignore_content) \
724 { \
725 lr_ignore_rest (ldfile, 0); \
726 break; \
727 } \
728 \
0d54f746 729 ldfile->return_widestr = 1; \
47e8b443 730 now = lr_token (ldfile, charmap, result, repertoire, verbose); \
4295702f
UD
731 if (now->tok != tok_string) \
732 goto err_label; \
733 if (monetary->cat != NULL) \
734 lr_error (ldfile, _("\
735%s: field `%s' declared more than once"), "LC_MONETARY", #cat); \
736 else if (!ignore_content && now->val.str.startmb == NULL) \
737 { \
738 lr_error (ldfile, _("\
739%s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
740 monetary->cat = ""; \
741 monetary->cat##_wc = L'\0'; \
742 } \
aec103d3 743 else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2) \
4295702f
UD
744 { \
745 lr_error (ldfile, _("\
746%s: value for field `%s' must be a single character"), "LC_MONETARY", #cat); \
747 } \
748 else if (!ignore_content) \
749 { \
750 monetary->cat = now->val.str.startmb; \
751 \
752 if (now->val.str.startwc != NULL) \
753 monetary->cat##_wc = *now->val.str.startwc; \
754 } \
0d54f746 755 ldfile->return_widestr = 0; \
4295702f
UD
756 break
757
758 STR_ELEM_WC (mon_decimal_point);
759 STR_ELEM_WC (mon_thousands_sep);
760
4b10dd6c
UD
761#define INT_ELEM(cat) \
762 case tok_##cat: \
b9eb05d6
UD
763 /* Ignore the rest of the line if we don't need the input of \
764 this line. */ \
765 if (ignore_content) \
766 { \
767 lr_ignore_rest (ldfile, 0); \
768 break; \
769 } \
770 \
47e8b443 771 now = lr_token (ldfile, charmap, result, NULL, verbose); \
4b10dd6c
UD
772 if (now->tok != tok_minus1 && now->tok != tok_number) \
773 goto err_label; \
774 else if (monetary->cat != -2) \
775 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
776 "LC_MONETARY", #cat); \
777 else if (!ignore_content) \
778 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
779 break
780
781 INT_ELEM (int_frac_digits);
782 INT_ELEM (frac_digits);
783 INT_ELEM (p_cs_precedes);
784 INT_ELEM (p_sep_by_space);
785 INT_ELEM (n_cs_precedes);
786 INT_ELEM (n_sep_by_space);
787 INT_ELEM (p_sign_posn);
788 INT_ELEM (n_sign_posn);
789 INT_ELEM (int_p_cs_precedes);
790 INT_ELEM (int_p_sep_by_space);
791 INT_ELEM (int_n_cs_precedes);
792 INT_ELEM (int_n_sep_by_space);
793 INT_ELEM (int_p_sign_posn);
794 INT_ELEM (int_n_sign_posn);
795 INT_ELEM (duo_int_frac_digits);
796 INT_ELEM (duo_frac_digits);
797 INT_ELEM (duo_p_cs_precedes);
798 INT_ELEM (duo_p_sep_by_space);
799 INT_ELEM (duo_n_cs_precedes);
800 INT_ELEM (duo_n_sep_by_space);
801 INT_ELEM (duo_p_sign_posn);
802 INT_ELEM (duo_n_sign_posn);
803 INT_ELEM (duo_int_p_cs_precedes);
804 INT_ELEM (duo_int_p_sep_by_space);
805 INT_ELEM (duo_int_n_cs_precedes);
806 INT_ELEM (duo_int_n_sep_by_space);
807 INT_ELEM (duo_int_p_sign_posn);
808 INT_ELEM (duo_int_n_sign_posn);
809 INT_ELEM (uno_valid_from);
810 INT_ELEM (uno_valid_to);
811 INT_ELEM (duo_valid_from);
812 INT_ELEM (duo_valid_to);
813
814 case tok_mon_grouping:
b9eb05d6
UD
815 /* Ignore the rest of the line if we don't need the input of
816 this line. */
817 if (ignore_content)
818 {
819 lr_ignore_rest (ldfile, 0);
820 break;
821 }
822
47e8b443 823 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
824 if (now->tok != tok_minus1 && now->tok != tok_number)
825 goto err_label;
19bc17a9 826 else
4b10dd6c
UD
827 {
828 size_t act = 0;
829 size_t max = 10;
830 char *grouping = ignore_content ? NULL : xmalloc (max);
831
832 do
833 {
834 if (act + 1 >= max)
835 {
836 max *= 2;
837 grouping = xrealloc (grouping, max);
838 }
839
840 if (act > 0 && grouping[act - 1] == '\177')
841 {
842 lr_error (ldfile, _("\
843%s: `-1' must be last entry in `%s' field"),
844 "LC_MONETARY", "mon_grouping");
845 lr_ignore_rest (ldfile, 0);
846 break;
847 }
848
849 if (now->tok == tok_minus1)
850 {
851 if (!ignore_content)
852 grouping[act++] = '\177';
853 }
854 else if (now->val.num == 0)
855 {
856 /* A value of 0 disables grouping from here on but
857 we must not store a NUL character since this
858 terminates the string. Use something different
859 which must not be used otherwise. */
860 if (!ignore_content)
861 grouping[act++] = '\377';
862 }
863 else if (now->val.num > 126)
864 lr_error (ldfile, _("\
865%s: values for field `%s' must be smaller than 127"),
866 "LC_MONETARY", "mon_grouping");
867 else if (!ignore_content)
868 grouping[act++] = now->val.num;
869
870 /* Next must be semicolon. */
47e8b443 871 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
872 if (now->tok != tok_semicolon)
873 break;
874
47e8b443 875 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
876 }
877 while (now->tok == tok_minus1 || now->tok == tok_number);
878
879 if (now->tok != tok_eol)
880 goto err_label;
881
882 if (!ignore_content)
883 {
884 grouping[act++] = '\0';
885
886 monetary->mon_grouping = xrealloc (grouping, act);
887 monetary->mon_grouping_len = act;
888 }
889 }
890 break;
891
892 case tok_conversion_rate:
b9eb05d6
UD
893 /* Ignore the rest of the line if we don't need the input of
894 this line. */
895 if (ignore_content)
896 {
897 lr_ignore_rest (ldfile, 0);
898 break;
899 }
900
47e8b443 901 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
902 if (now->tok != tok_number)
903 goto err_label;
904 if (now->val.num == 0)
905 {
906 invalid_conversion_rate:
6d77214d 907 lr_error (ldfile, _("conversion rate value cannot be zero"));
4b10dd6c
UD
908 if (!ignore_content)
909 {
910 monetary->conversion_rate[0] = 1;
911 monetary->conversion_rate[1] = 1;
912 }
913 break;
914 }
915 if (!ignore_content)
916 monetary->conversion_rate[0] = now->val.num;
917 /* Next must be a semicolon. */
47e8b443 918 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
919 if (now->tok != tok_semicolon)
920 goto err_label;
921 /* And another number. */
47e8b443 922 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
923 if (now->tok != tok_number)
924 goto err_label;
925 if (now->val.num == 0)
926 goto invalid_conversion_rate;
927 if (!ignore_content)
928 monetary->conversion_rate[1] = now->val.num;
929 /* The rest of the line must be empty. */
930 lr_ignore_rest (ldfile, 1);
931 break;
932
933 case tok_end:
934 /* Next we assume `LC_MONETARY'. */
47e8b443 935 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c
UD
936 if (now->tok == tok_eof)
937 break;
938 if (now->tok == tok_eol)
939 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
940 else if (now->tok != tok_lc_monetary)
941 lr_error (ldfile, _("\
942%1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
943 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
944 return;
945
946 default:
947 err_label:
948 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
19bc17a9 949 }
19bc17a9 950
4b10dd6c 951 /* Prepare for the next round. */
47e8b443 952 now = lr_token (ldfile, charmap, result, NULL, verbose);
4b10dd6c 953 nowtok = now->tok;
19bc17a9 954 }
19bc17a9 955
4b10dd6c
UD
956 /* When we come here we reached the end of the file. */
957 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
19bc17a9 958}