]> git.ipfire.org Git - thirdparty/glibc.git/blob - locale/programs/ld-monetary.c
Update.
[thirdparty/glibc.git] / locale / programs / ld-monetary.c
1 /* Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If not,
17 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA. */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23
24 #include <byteswap.h>
25 #include <langinfo.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/uio.h>
30
31 #include <assert.h>
32
33 #include "linereader.h"
34 #include "localedef.h"
35 #include "localeinfo.h"
36 #include "locfile.h"
37
38
39 /* The real definition of the struct for the LC_MONETARY locale. */
40 struct locale_monetary_t
41 {
42 const char *int_curr_symbol;
43 const char *currency_symbol;
44 const char *mon_decimal_point;
45 const char *mon_thousands_sep;
46 char *mon_grouping;
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];
85 uint32_t conversion_rate_ob[2];
86 };
87
88
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[] =
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. */
102 static int curr_strcmp (const char *s1, const char **s2);
103
104
105 static void
106 monetary_startup (struct linereader *lr, struct localedef_t *locale,
107 int ignore_content)
108 {
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 }
150
151 if (lr != NULL)
152 {
153 lr->translate_strings = 1;
154 lr->return_widestr = 0;
155 }
156 }
157
158
159 void
160 monetary_finish (struct localedef_t *locale, struct charmap_t *charmap)
161 {
162 struct locale_monetary_t *monetary
163 = locale->categories[LC_MONETARY].monetary;
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 {
191 error (0, 0, _("No definition for %s category found"),
192 "LC_MONETARY");
193 monetary_startup (NULL, locale, 0);
194 monetary = locale->categories[LC_MONETARY].monetary;
195 nothing = 1;
196 }
197 }
198
199 #define TEST_ELEM(cat) \
200 if (monetary->cat == NULL && !be_quiet) \
201 { \
202 if (! nothing) \
203 error (0, 0, _("%s: field `%s' not defined"), \
204 "LC_MONETARY", #cat); \
205 monetary->cat = ""; \
206 }
207
208 TEST_ELEM (int_curr_symbol);
209 TEST_ELEM (currency_symbol);
210 TEST_ELEM (mon_decimal_point);
211 TEST_ELEM (mon_thousands_sep);
212 TEST_ELEM (positive_sign);
213 TEST_ELEM (negative_sign);
214
215 /* The international currency symbol must come from ISO 4217. */
216 if (monetary->int_curr_symbol != NULL)
217 {
218 if (strlen (monetary->int_curr_symbol) != 4)
219 {
220 if (!be_quiet)
221 error (0, 0, _("\
222 %s: value of field `int_curr_symbol' has wrong length"),
223 "LC_MONETARY");
224 }
225 else if (bsearch (monetary->int_curr_symbol, valid_int_curr,
226 NR_VALID_INT_CURR, sizeof (const char *),
227 (comparison_fn_t) curr_strcmp) == NULL
228 && !be_quiet)
229 error (0, 0, _("\
230 %s: value of field `int_curr_symbol' does \
231 not correspond to a valid name in ISO 4217"),
232 "LC_MONETARY");
233 }
234
235 /* The decimal point must not be empty. This is not said explicitly
236 in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
237 != "". */
238 if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
239 {
240 error (0, 0, _("\
241 %s: value for field `%s' must not be the empty string"),
242 "LC_MONETARY", "mon_decimal_point");
243 }
244
245 if (monetary->mon_grouping_len == 0 && ! be_quiet && ! nothing)
246 error (0, 0, _("%s: field `%s' not defined"),
247 "LC_MONETARY", "mon_grouping");
248
249 #undef TEST_ELEM
250 #define TEST_ELEM(cat, min, max) \
251 if (monetary->cat == -2 && ! be_quiet && ! nothing) \
252 error (0, 0, _("%s: field `%s' not defined"), \
253 "LC_MONETARY", #cat); \
254 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet) \
255 error (0, 0, _("\
256 %s: value for field `%s' must be in range %d...%d"), \
257 "LC_MONETARY", #cat, min, max)
258
259 #if 0
260 /* The following two test are not really necessary because all values
261 the variable could have are valid. */
262 TEST_ELEM (int_frac_digits, -128, 127); /* No range check. */
263 TEST_ELEM (frac_digits, -128, 127); /* No range check. */
264 #endif
265 TEST_ELEM (p_cs_precedes, -1, 1);
266 TEST_ELEM (p_sep_by_space, -1, 2);
267 TEST_ELEM (n_cs_precedes, -1, 1);
268 TEST_ELEM (n_sep_by_space, -1, 2);
269 TEST_ELEM (p_sign_posn, -1, 4);
270 TEST_ELEM (n_sign_posn, -1, 4);
271
272 /* The non-POSIX.2 extensions are optional. */
273 if (monetary->duo_int_curr_symbol == NULL)
274 monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
275 if (monetary->duo_currency_symbol == NULL)
276 monetary->duo_currency_symbol = monetary->currency_symbol;
277
278 if (monetary->duo_int_frac_digits == -2)
279 monetary->duo_int_frac_digits = monetary->int_frac_digits;
280 if (monetary->duo_frac_digits == -2)
281 monetary->duo_frac_digits = monetary->frac_digits;
282
283 #undef TEST_ELEM
284 #define TEST_ELEM(cat, alt, min, max) \
285 if (monetary->cat == -2) \
286 monetary->cat = monetary->alt; \
287 else if ((monetary->cat < min || monetary->cat > max) && !be_quiet \
288 && ! nothing) \
289 error (0, 0, _("\
290 %s: value for field `%s' must be in range %d...%d"), \
291 "LC_MONETARY", #cat, min, max)
292
293 TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
294 TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
295 TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
296 TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
297 TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
298 TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
299
300 TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
301 TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
302 TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
303 TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
304 TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
305 TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
306 TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
307 TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
308 TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
309 TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
310 TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
311 TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
312
313 if (monetary->uno_valid_from == 0)
314 monetary->uno_valid_from = 10101;
315 if (monetary->uno_valid_to == 0)
316 monetary->uno_valid_to = 99991231;
317 if (monetary->duo_valid_from == 0)
318 monetary->duo_valid_from = 10101;
319 if (monetary->duo_valid_to == 0)
320 monetary->duo_valid_to = 99991231;
321
322 if (monetary->conversion_rate[0] == 0)
323 {
324 monetary->conversion_rate[0] = 1;
325 monetary->conversion_rate[1] = 1;
326 }
327
328 monetary->conversion_rate_ob[0] = bswap_32 (monetary->conversion_rate[0]);
329 monetary->conversion_rate_ob[1] = bswap_32 (monetary->conversion_rate[1]);
330 }
331
332
333 void
334 monetary_output (struct localedef_t *locale, struct charmap_t *charmap,
335 const char *output_path)
336 {
337 struct locale_monetary_t *monetary
338 = locale->categories[LC_MONETARY].monetary;
339 struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
340 struct locale_file data;
341 uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
342 size_t cnt = 0;
343
344 data.magic = LIMAGIC (LC_MONETARY);
345 data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
346 iov[cnt].iov_base = (void *) &data;
347 iov[cnt].iov_len = sizeof (data);
348 ++cnt;
349
350 iov[cnt].iov_base = (void *) idx;
351 iov[cnt].iov_len = sizeof (idx);
352 ++cnt;
353
354 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
355 iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
356 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
357 ++cnt;
358
359 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
360 iov[cnt].iov_base = (void *) monetary->currency_symbol;
361 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
362 ++cnt;
363
364 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
365 iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
366 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
367 ++cnt;
368
369 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
370 iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
371 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
372 ++cnt;
373
374 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
375 iov[cnt].iov_base = monetary->mon_grouping;
376 iov[cnt].iov_len = monetary->mon_grouping_len;
377 ++cnt;
378
379 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
380 iov[cnt].iov_base = (void *) monetary->positive_sign;
381 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
382 ++cnt;
383
384 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
385 iov[cnt].iov_base = (void *) monetary->negative_sign;
386 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
387 ++cnt;
388
389 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
390 iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
391 iov[cnt].iov_len = 1;
392 ++cnt;
393
394 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
395 iov[cnt].iov_base = (void *) &monetary->frac_digits;
396 iov[cnt].iov_len = 1;
397 ++cnt;
398
399 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
400 iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
401 iov[cnt].iov_len = 1;
402 ++cnt;
403
404 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
405 iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
406 iov[cnt].iov_len = 1;
407 ++cnt;
408
409 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
410 iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
411 iov[cnt].iov_len = 1;
412 ++cnt;
413
414 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
415 iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
416 iov[cnt].iov_len = 1;
417 ++cnt;
418
419 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
420 iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
421 iov[cnt].iov_len = 1;
422 ++cnt;
423
424 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
425 iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
426 iov[cnt].iov_len = 1;
427 ++cnt;
428
429 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
430 iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
431 iov[cnt].iov_len = 1;
432 ++cnt;
433
434 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
435 iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
436 iov[cnt].iov_len = 1;
437 ++cnt;
438
439 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
440 iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
441 iov[cnt].iov_len = 1;
442 ++cnt;
443
444 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
445 iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
446 iov[cnt].iov_len = 1;
447 ++cnt;
448
449 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
450 iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
451 iov[cnt].iov_len = 1;
452 ++cnt;
453
454 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
455 iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
456 iov[cnt].iov_len = 1;
457 ++cnt;
458
459 idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
460 iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
461 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
462 ++cnt;
463
464 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
465 iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
466 iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
467 ++cnt;
468
469 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
470 iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
471 iov[cnt].iov_len = 1;
472 ++cnt;
473
474 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
475 iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
476 iov[cnt].iov_len = 1;
477 ++cnt;
478
479 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
480 iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
481 iov[cnt].iov_len = 1;
482 ++cnt;
483
484 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
485 iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
486 iov[cnt].iov_len = 1;
487 ++cnt;
488
489 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
490 iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
491 iov[cnt].iov_len = 1;
492 ++cnt;
493
494 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
495 iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
496 iov[cnt].iov_len = 1;
497 ++cnt;
498
499 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
500 iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
501 iov[cnt].iov_len = 1;
502 ++cnt;
503
504 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
505 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
506 iov[cnt].iov_len = 1;
507 ++cnt;
508
509 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
510 iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
511 iov[cnt].iov_len = 1;
512 ++cnt;
513
514 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
515 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
516 iov[cnt].iov_len = 1;
517 ++cnt;
518
519 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
520 iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
521 iov[cnt].iov_len = 1;
522 ++cnt;
523
524 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
525 iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
526 iov[cnt].iov_len = 1;
527 ++cnt;
528
529 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
530 iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
531 iov[cnt].iov_len = 1;
532 ++cnt;
533
534 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
535 iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
536 iov[cnt].iov_len = 1;
537 ++cnt;
538
539 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
540 iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
541 iov[cnt].iov_len = 4;
542 ++cnt;
543
544 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
545 iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
546 iov[cnt].iov_len = 4;
547 ++cnt;
548
549 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
550 iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
551 iov[cnt].iov_len = 4;
552 ++cnt;
553
554 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
555 iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
556 iov[cnt].iov_len = 4;
557 ++cnt;
558
559 #if BYTE_ORDER == LITTLE_ENDIAN
560 # define conversion_rate_el conversion_rate
561 # define conversion_rate_eb conversion_rate_ob
562 #else
563 # define conversion_rate_el conversion_rate_ob
564 # define conversion_rate_eb conversion_rate
565 #endif
566
567 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
568 iov[cnt].iov_base = (void *) &monetary->conversion_rate_el;
569 iov[cnt].iov_len = 8;
570 ++cnt;
571
572 idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
573 iov[cnt].iov_base = (void *) &monetary->conversion_rate_eb;
574 iov[cnt].iov_len = 8;
575 ++cnt;
576
577 assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
578
579 write_locale_data (output_path, "LC_MONETARY",
580 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
581 }
582
583
584 static int
585 curr_strcmp (const char *s1, const char **s2)
586 {
587 return strcmp (s1, *s2);
588 }
589
590
591 /* The parser for the LC_MONETARY section of the locale definition. */
592 void
593 monetary_read (struct linereader *ldfile, struct localedef_t *result,
594 struct charmap_t *charmap, const char *repertoire_name,
595 int ignore_content)
596 {
597 struct repertoire_t *repertoire = NULL;
598 struct locale_monetary_t *monetary;
599 struct token *now;
600 enum token_t nowtok;
601
602 /* Get the repertoire we have to use. */
603 if (repertoire_name != NULL)
604 repertoire = repertoire_read (repertoire_name);
605
606 /* The rest of the line containing `LC_MONETARY' must be free. */
607 lr_ignore_rest (ldfile, 1);
608
609 do
610 {
611 now = lr_token (ldfile, charmap, NULL);
612 nowtok = now->tok;
613 }
614 while (nowtok == tok_eol);
615
616 /* If we see `copy' now we are almost done. */
617 if (nowtok == tok_copy)
618 {
619 handle_copy (ldfile, charmap, repertoire, result, tok_lc_monetary,
620 LC_MONETARY, "LC_MONETARY", ignore_content);
621 return;
622 }
623
624 /* Prepare the data structures. */
625 monetary_startup (ldfile, result, ignore_content);
626 monetary = result->categories[LC_MONETARY].monetary;
627
628 while (1)
629 {
630 /* Of course we don't proceed beyond the end of file. */
631 if (nowtok == tok_eof)
632 break;
633
634 /* Ingore empty lines. */
635 if (nowtok == tok_eol)
636 {
637 now = lr_token (ldfile, charmap, NULL);
638 nowtok = now->tok;
639 continue;
640 }
641
642 switch (nowtok)
643 {
644 #define STR_ELEM(cat) \
645 case tok_##cat: \
646 /* Ignore the rest of the line if we don't need the input of \
647 this line. */ \
648 if (ignore_content) \
649 { \
650 lr_ignore_rest (ldfile, 0); \
651 break; \
652 } \
653 \
654 now = lr_token (ldfile, charmap, NULL); \
655 if (now->tok != tok_string) \
656 goto err_label; \
657 else if (monetary->cat != NULL) \
658 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
659 "LC_MONETARY", #cat); \
660 else if (!ignore_content && now->val.str.startmb == NULL) \
661 { \
662 lr_error (ldfile, _("\
663 %s: unknown character in field `%s'"), "LC_MONETARY", #cat); \
664 monetary->cat = ""; \
665 } \
666 else if (!ignore_content) \
667 monetary->cat = now->val.str.startmb; \
668 lr_ignore_rest (ldfile, 1); \
669 break
670
671 STR_ELEM (int_curr_symbol);
672 STR_ELEM (currency_symbol);
673 STR_ELEM (mon_decimal_point);
674 STR_ELEM (mon_thousands_sep);
675 STR_ELEM (positive_sign);
676 STR_ELEM (negative_sign);
677 STR_ELEM (duo_int_curr_symbol);
678 STR_ELEM (duo_currency_symbol);
679
680 #define INT_ELEM(cat) \
681 case tok_##cat: \
682 /* Ignore the rest of the line if we don't need the input of \
683 this line. */ \
684 if (ignore_content) \
685 { \
686 lr_ignore_rest (ldfile, 0); \
687 break; \
688 } \
689 \
690 now = lr_token (ldfile, charmap, NULL); \
691 if (now->tok != tok_minus1 && now->tok != tok_number) \
692 goto err_label; \
693 else if (monetary->cat != -2) \
694 lr_error (ldfile, _("%s: field `%s' declared more than once"), \
695 "LC_MONETARY", #cat); \
696 else if (!ignore_content) \
697 monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num; \
698 break
699
700 INT_ELEM (int_frac_digits);
701 INT_ELEM (frac_digits);
702 INT_ELEM (p_cs_precedes);
703 INT_ELEM (p_sep_by_space);
704 INT_ELEM (n_cs_precedes);
705 INT_ELEM (n_sep_by_space);
706 INT_ELEM (p_sign_posn);
707 INT_ELEM (n_sign_posn);
708 INT_ELEM (int_p_cs_precedes);
709 INT_ELEM (int_p_sep_by_space);
710 INT_ELEM (int_n_cs_precedes);
711 INT_ELEM (int_n_sep_by_space);
712 INT_ELEM (int_p_sign_posn);
713 INT_ELEM (int_n_sign_posn);
714 INT_ELEM (duo_int_frac_digits);
715 INT_ELEM (duo_frac_digits);
716 INT_ELEM (duo_p_cs_precedes);
717 INT_ELEM (duo_p_sep_by_space);
718 INT_ELEM (duo_n_cs_precedes);
719 INT_ELEM (duo_n_sep_by_space);
720 INT_ELEM (duo_p_sign_posn);
721 INT_ELEM (duo_n_sign_posn);
722 INT_ELEM (duo_int_p_cs_precedes);
723 INT_ELEM (duo_int_p_sep_by_space);
724 INT_ELEM (duo_int_n_cs_precedes);
725 INT_ELEM (duo_int_n_sep_by_space);
726 INT_ELEM (duo_int_p_sign_posn);
727 INT_ELEM (duo_int_n_sign_posn);
728 INT_ELEM (uno_valid_from);
729 INT_ELEM (uno_valid_to);
730 INT_ELEM (duo_valid_from);
731 INT_ELEM (duo_valid_to);
732
733 case tok_mon_grouping:
734 /* Ignore the rest of the line if we don't need the input of
735 this line. */
736 if (ignore_content)
737 {
738 lr_ignore_rest (ldfile, 0);
739 break;
740 }
741
742 now = lr_token (ldfile, charmap, NULL);
743 if (now->tok != tok_minus1 && now->tok != tok_number)
744 goto err_label;
745 else
746 {
747 size_t act = 0;
748 size_t max = 10;
749 char *grouping = ignore_content ? NULL : xmalloc (max);
750
751 do
752 {
753 if (act + 1 >= max)
754 {
755 max *= 2;
756 grouping = xrealloc (grouping, max);
757 }
758
759 if (act > 0 && grouping[act - 1] == '\177')
760 {
761 lr_error (ldfile, _("\
762 %s: `-1' must be last entry in `%s' field"),
763 "LC_MONETARY", "mon_grouping");
764 lr_ignore_rest (ldfile, 0);
765 break;
766 }
767
768 if (now->tok == tok_minus1)
769 {
770 if (!ignore_content)
771 grouping[act++] = '\177';
772 }
773 else if (now->val.num == 0)
774 {
775 /* A value of 0 disables grouping from here on but
776 we must not store a NUL character since this
777 terminates the string. Use something different
778 which must not be used otherwise. */
779 if (!ignore_content)
780 grouping[act++] = '\377';
781 }
782 else if (now->val.num > 126)
783 lr_error (ldfile, _("\
784 %s: values for field `%s' must be smaller than 127"),
785 "LC_MONETARY", "mon_grouping");
786 else if (!ignore_content)
787 grouping[act++] = now->val.num;
788
789 /* Next must be semicolon. */
790 now = lr_token (ldfile, charmap, NULL);
791 if (now->tok != tok_semicolon)
792 break;
793
794 now = lr_token (ldfile, charmap, NULL);
795 }
796 while (now->tok == tok_minus1 || now->tok == tok_number);
797
798 if (now->tok != tok_eol)
799 goto err_label;
800
801 if (!ignore_content)
802 {
803 grouping[act++] = '\0';
804
805 monetary->mon_grouping = xrealloc (grouping, act);
806 monetary->mon_grouping_len = act;
807 }
808 }
809 break;
810
811 case tok_conversion_rate:
812 /* Ignore the rest of the line if we don't need the input of
813 this line. */
814 if (ignore_content)
815 {
816 lr_ignore_rest (ldfile, 0);
817 break;
818 }
819
820 now = lr_token (ldfile, charmap, NULL);
821 if (now->tok != tok_number)
822 goto err_label;
823 if (now->val.num == 0)
824 {
825 invalid_conversion_rate:
826 lr_error (ldfile, _("conversion rate valze cannot be zero"));
827 if (!ignore_content)
828 {
829 monetary->conversion_rate[0] = 1;
830 monetary->conversion_rate[1] = 1;
831 }
832 break;
833 }
834 if (!ignore_content)
835 monetary->conversion_rate[0] = now->val.num;
836 /* Next must be a semicolon. */
837 now = lr_token (ldfile, charmap, NULL);
838 if (now->tok != tok_semicolon)
839 goto err_label;
840 /* And another number. */
841 now = lr_token (ldfile, charmap, NULL);
842 if (now->tok != tok_number)
843 goto err_label;
844 if (now->val.num == 0)
845 goto invalid_conversion_rate;
846 if (!ignore_content)
847 monetary->conversion_rate[1] = now->val.num;
848 /* The rest of the line must be empty. */
849 lr_ignore_rest (ldfile, 1);
850 break;
851
852 case tok_end:
853 /* Next we assume `LC_MONETARY'. */
854 now = lr_token (ldfile, charmap, NULL);
855 if (now->tok == tok_eof)
856 break;
857 if (now->tok == tok_eol)
858 lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
859 else if (now->tok != tok_lc_monetary)
860 lr_error (ldfile, _("\
861 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
862 lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
863 return;
864
865 default:
866 err_label:
867 SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
868 }
869
870 /* Prepare for the next round. */
871 now = lr_token (ldfile, charmap, NULL);
872 nowtok = now->tok;
873 }
874
875 /* When we come here we reached the end of the file. */
876 lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
877 }