61f9f8dc6cc4f80bb23c4f416c5414d3cd2a94f1
[kopensolaris-gnu/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   lr->translate_strings = 1;
152   lr->return_widestr = 0;
153 }
154
155
156 void
157 monetary_finish (struct localedef_t *locale, struct charmap_t *charmap)
158 {
159   struct locale_monetary_t *monetary
160     = locale->categories[LC_MONETARY].monetary;
161
162 #define TEST_ELEM(cat) \
163   if (monetary->cat == NULL && !be_quiet)                                     \
164     {                                                                         \
165       error (0, 0, _("%s: field `%s' not defined"),                           \
166              "LC_MONETARY", #cat);                                            \
167       monetary->cat = "";                                                     \
168     }
169
170   TEST_ELEM (int_curr_symbol);
171   TEST_ELEM (currency_symbol);
172   TEST_ELEM (mon_decimal_point);
173   TEST_ELEM (mon_thousands_sep);
174   TEST_ELEM (positive_sign);
175   TEST_ELEM (negative_sign);
176
177   /* The international currency symbol must come from ISO 4217.  */
178   if (monetary->int_curr_symbol != NULL)
179     {
180       if (strlen (monetary->int_curr_symbol) != 4)
181         {
182           if (!be_quiet)
183             error (0, 0, _("\
184 %s: value of field `int_curr_symbol' has wrong length"),
185                    "LC_MONETARY");
186         }
187       else if (bsearch (monetary->int_curr_symbol, valid_int_curr,
188                         NR_VALID_INT_CURR, sizeof (const char *),
189                         (comparison_fn_t) curr_strcmp) == NULL
190                && !be_quiet)
191         error (0, 0, _("\
192 %s: value of field `int_curr_symbol' does \
193 not correspond to a valid name in ISO 4217"),
194                "LC_MONETARY");
195     }
196
197   /* The decimal point must not be empty.  This is not said explicitly
198      in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
199      != "".  */
200   if (monetary->mon_decimal_point[0] == '\0' && !be_quiet)
201     {
202       error (0, 0, _("\
203 %s: value for field `%s' must not be the empty string"),
204              "LC_MONETARY", "mon_decimal_point");
205     }
206
207   if (monetary->mon_grouping_len == 0 && !be_quiet)
208     error (0, 0, _("%s: field `%s' not defined"),
209            "LC_MONETARY", "mon_grouping");
210
211 #undef TEST_ELEM
212 #define TEST_ELEM(cat, min, max) \
213   if (monetary->cat == -2 && !be_quiet)                                       \
214     error (0, 0, _("%s: field `%s' not defined"),                             \
215            "LC_MONETARY", #cat);                                              \
216   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet)         \
217     error (0, 0, _("\
218 %s: value for field `%s' must be in range %d...%d"),                          \
219            "LC_MONETARY", #cat, min, max)
220
221 #if 0
222 /* The following two test are not really necessary because all values
223     the variable could have are valid.  */
224   TEST_ELEM (int_frac_digits, -128, 127);       /* No range check.  */
225   TEST_ELEM (frac_digits, -128, 127);           /* No range check.  */
226 #endif
227   TEST_ELEM (p_cs_precedes, -1, 1);
228   TEST_ELEM (p_sep_by_space, -1, 2);
229   TEST_ELEM (n_cs_precedes, -1, 1);
230   TEST_ELEM (n_sep_by_space, -1, 2);
231   TEST_ELEM (p_sign_posn, -1, 4);
232   TEST_ELEM (n_sign_posn, -1, 4);
233
234   /* The non-POSIX.2 extensions are optional.  */
235   if (monetary->duo_int_curr_symbol == NULL)
236     monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
237   if (monetary->duo_currency_symbol == NULL)
238     monetary->duo_currency_symbol = monetary->currency_symbol;
239
240   if (monetary->duo_int_frac_digits == -2)
241     monetary->duo_int_frac_digits = monetary->int_frac_digits;
242   if (monetary->duo_frac_digits == -2)
243     monetary->duo_frac_digits = monetary->frac_digits;
244
245 #undef TEST_ELEM
246 #define TEST_ELEM(cat, alt, min, max) \
247   if (monetary->cat == -2 && !be_quiet)                                       \
248     monetary->cat = monetary->alt;                                            \
249   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet)         \
250     error (0, 0, _("\
251 %s: value for field `%s' must be in range %d...%d"),                          \
252            "LC_MONETARY", #cat, min, max)
253
254   TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
255   TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
256   TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
257   TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
258   TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
259   TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
260
261   TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
262   TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
263   TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
264   TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
265   TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
266   TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
267   TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
268   TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
269   TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
270   TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
271   TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
272   TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
273
274   if (monetary->uno_valid_from == 0)
275     monetary->uno_valid_from = 10101;
276   if (monetary->uno_valid_to == 0)
277     monetary->uno_valid_to = 99991231;
278   if (monetary->duo_valid_from == 0)
279     monetary->duo_valid_from = 10101;
280   if (monetary->duo_valid_to == 0)
281     monetary->duo_valid_to = 99991231;
282
283   if (monetary->conversion_rate[0] == 0)
284     {
285       monetary->conversion_rate[0] = 1;
286       monetary->conversion_rate[1] = 1;
287     }
288
289   monetary->conversion_rate_ob[0] = bswap_32 (monetary->conversion_rate[0]);
290   monetary->conversion_rate_ob[1] = bswap_32 (monetary->conversion_rate[1]);
291 }
292
293
294 void
295 monetary_output (struct localedef_t *locale, struct charmap_t *charmap,
296                  const char *output_path)
297 {
298   struct locale_monetary_t *monetary
299     = locale->categories[LC_MONETARY].monetary;
300   struct iovec iov[2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
301   struct locale_file data;
302   uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
303   size_t cnt = 0;
304
305   data.magic = LIMAGIC (LC_MONETARY);
306   data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
307   iov[cnt].iov_base = (void *) &data;
308   iov[cnt].iov_len = sizeof (data);
309   ++cnt;
310
311   iov[cnt].iov_base = (void *) idx;
312   iov[cnt].iov_len = sizeof (idx);
313   ++cnt;
314
315   idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
316   iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
317   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
318   ++cnt;
319
320   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
321   iov[cnt].iov_base = (void *) monetary->currency_symbol;
322   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
323   ++cnt;
324
325   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
326   iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
327   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
328   ++cnt;
329
330   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
331   iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
332   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
333   ++cnt;
334
335   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
336   iov[cnt].iov_base = monetary->mon_grouping;
337   iov[cnt].iov_len = monetary->mon_grouping_len;
338   ++cnt;
339
340   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
341   iov[cnt].iov_base = (void *) monetary->positive_sign;
342   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
343   ++cnt;
344
345   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
346   iov[cnt].iov_base = (void *) monetary->negative_sign;
347   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
348   ++cnt;
349
350   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
351   iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
352   iov[cnt].iov_len = 1;
353   ++cnt;
354
355   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
356   iov[cnt].iov_base = (void *) &monetary->frac_digits;
357   iov[cnt].iov_len = 1;
358   ++cnt;
359
360   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
361   iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
362   iov[cnt].iov_len = 1;
363   ++cnt;
364
365   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
366   iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
367   iov[cnt].iov_len = 1;
368   ++cnt;
369
370   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
371   iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
372   iov[cnt].iov_len = 1;
373   ++cnt;
374
375   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
376   iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
377   iov[cnt].iov_len = 1;
378   ++cnt;
379
380   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
381   iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
382   iov[cnt].iov_len = 1;
383   ++cnt;
384
385   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
386   iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
387   iov[cnt].iov_len = 1;
388   ++cnt;
389
390   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
391   iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
392   iov[cnt].iov_len = 1;
393   ++cnt;
394
395   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
396   iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
397   iov[cnt].iov_len = 1;
398   ++cnt;
399
400   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
401   iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
402   iov[cnt].iov_len = 1;
403   ++cnt;
404
405   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
406   iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
407   iov[cnt].iov_len = 1;
408   ++cnt;
409
410   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
411   iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
412   iov[cnt].iov_len = 1;
413   ++cnt;
414
415   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
416   iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
417   iov[cnt].iov_len = 1;
418   ++cnt;
419
420   idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
421   iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
422   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
423   ++cnt;
424
425   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
426   iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
427   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
428   ++cnt;
429
430   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
431   iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
432   iov[cnt].iov_len = 1;
433   ++cnt;
434
435   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
436   iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
437   iov[cnt].iov_len = 1;
438   ++cnt;
439
440   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
441   iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
442   iov[cnt].iov_len = 1;
443   ++cnt;
444
445   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
446   iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
447   iov[cnt].iov_len = 1;
448   ++cnt;
449
450   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
451   iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
452   iov[cnt].iov_len = 1;
453   ++cnt;
454
455   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
456   iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
457   iov[cnt].iov_len = 1;
458   ++cnt;
459
460   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
461   iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
462   iov[cnt].iov_len = 1;
463   ++cnt;
464
465   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
466   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
467   iov[cnt].iov_len = 1;
468   ++cnt;
469
470   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
471   iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
472   iov[cnt].iov_len = 1;
473   ++cnt;
474
475   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
476   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
477   iov[cnt].iov_len = 1;
478   ++cnt;
479
480   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
481   iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
482   iov[cnt].iov_len = 1;
483   ++cnt;
484
485   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
486   iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
487   iov[cnt].iov_len = 1;
488   ++cnt;
489
490   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
491   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
492   iov[cnt].iov_len = 1;
493   ++cnt;
494
495   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
496   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
497   iov[cnt].iov_len = 1;
498   ++cnt;
499
500   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
501   iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
502   iov[cnt].iov_len = 4;
503   ++cnt;
504
505   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
506   iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
507   iov[cnt].iov_len = 4;
508   ++cnt;
509
510   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
511   iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
512   iov[cnt].iov_len = 4;
513   ++cnt;
514
515   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
516   iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
517   iov[cnt].iov_len = 4;
518   ++cnt;
519
520 #if BYTE_ORDER == LITTLE_ENDIAN
521 # define conversion_rate_el conversion_rate
522 # define conversion_rate_eb conversion_rate_ob
523 #else
524 # define conversion_rate_el conversion_rate_ob
525 # define conversion_rate_eb conversion_rate
526 #endif
527
528   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
529   iov[cnt].iov_base = (void *) &monetary->conversion_rate_el;
530   iov[cnt].iov_len = 8;
531   ++cnt;
532
533   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
534   iov[cnt].iov_base = (void *) &monetary->conversion_rate_eb;
535   iov[cnt].iov_len = 8;
536   ++cnt;
537
538   assert (cnt == 2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
539
540   write_locale_data (output_path, "LC_MONETARY",
541                      2 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
542 }
543
544
545 static int
546 curr_strcmp (const char *s1, const char **s2)
547 {
548   return strcmp (s1, *s2);
549 }
550
551
552 /* The parser for the LC_MONETARY section of the locale definition.  */
553 void
554 monetary_read (struct linereader *ldfile, struct localedef_t *result,
555                struct charmap_t *charmap, const char *repertoire_name,
556                int ignore_content)
557 {
558   struct repertoire_t *repertoire = NULL;
559   struct locale_monetary_t *monetary;
560   struct token *now;
561   enum token_t nowtok;
562
563   /* Get the repertoire we have to use.  */
564   if (repertoire_name != NULL)
565     repertoire = repertoire_read (repertoire_name);
566
567   /* The rest of the line containing `LC_MONETARY' must be free.  */
568   lr_ignore_rest (ldfile, 1);
569
570   do
571     {
572       now = lr_token (ldfile, charmap, NULL);
573       nowtok = now->tok;
574     }
575   while (nowtok == tok_eol);
576
577   /* If we see `copy' now we are almost done.  */
578   if (nowtok == tok_copy)
579     {
580       handle_copy (ldfile, charmap, repertoire, tok_lc_monetary, LC_MONETARY,
581                    "LC_MONETARY", ignore_content);
582       return;
583     }
584
585   /* Prepare the data structures.  */
586   monetary_startup (ldfile, result, ignore_content);
587   monetary = result->categories[LC_MONETARY].monetary;
588
589   while (1)
590     {
591       /* Of course we don't proceed beyond the end of file.  */
592       if (nowtok == tok_eof)
593         break;
594
595       /* Ingore empty lines.  */
596       if (nowtok == tok_eol)
597         {
598           now = lr_token (ldfile, charmap, NULL);
599           nowtok = now->tok;
600           continue;
601         }
602
603       switch (nowtok)
604         {
605 #define STR_ELEM(cat) \
606         case tok_##cat:                                                       \
607           now = lr_token (ldfile, charmap, NULL);                             \
608           if (now->tok != tok_string)                                         \
609             goto err_label;                                                   \
610           else if (monetary->cat != NULL)                                     \
611             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
612                       "LC_MONETARY", #cat);                                   \
613           else if (!ignore_content && now->val.str.startmb == NULL)           \
614             {                                                                 \
615               lr_error (ldfile, _("\
616 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                  \
617               monetary->cat = "";                                             \
618             }                                                                 \
619           else if (!ignore_content)                                           \
620             monetary->cat = now->val.str.startmb;                             \
621           lr_ignore_rest (ldfile, 1);                                         \
622           break
623
624           STR_ELEM (int_curr_symbol);
625           STR_ELEM (currency_symbol);
626           STR_ELEM (mon_decimal_point);
627           STR_ELEM (mon_thousands_sep);
628           STR_ELEM (positive_sign);
629           STR_ELEM (negative_sign);
630           STR_ELEM (duo_int_curr_symbol);
631           STR_ELEM (duo_currency_symbol);
632
633 #define INT_ELEM(cat) \
634         case tok_##cat:                                                       \
635           now = lr_token (ldfile, charmap, NULL);                             \
636           if (now->tok != tok_minus1 && now->tok != tok_number)               \
637             goto err_label;                                                   \
638           else if (monetary->cat != -2)                                       \
639             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
640                       "LC_MONETARY", #cat);                                   \
641           else if (!ignore_content)                                           \
642             monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num;       \
643           break
644
645           INT_ELEM (int_frac_digits);
646           INT_ELEM (frac_digits);
647           INT_ELEM (p_cs_precedes);
648           INT_ELEM (p_sep_by_space);
649           INT_ELEM (n_cs_precedes);
650           INT_ELEM (n_sep_by_space);
651           INT_ELEM (p_sign_posn);
652           INT_ELEM (n_sign_posn);
653           INT_ELEM (int_p_cs_precedes);
654           INT_ELEM (int_p_sep_by_space);
655           INT_ELEM (int_n_cs_precedes);
656           INT_ELEM (int_n_sep_by_space);
657           INT_ELEM (int_p_sign_posn);
658           INT_ELEM (int_n_sign_posn);
659           INT_ELEM (duo_int_frac_digits);
660           INT_ELEM (duo_frac_digits);
661           INT_ELEM (duo_p_cs_precedes);
662           INT_ELEM (duo_p_sep_by_space);
663           INT_ELEM (duo_n_cs_precedes);
664           INT_ELEM (duo_n_sep_by_space);
665           INT_ELEM (duo_p_sign_posn);
666           INT_ELEM (duo_n_sign_posn);
667           INT_ELEM (duo_int_p_cs_precedes);
668           INT_ELEM (duo_int_p_sep_by_space);
669           INT_ELEM (duo_int_n_cs_precedes);
670           INT_ELEM (duo_int_n_sep_by_space);
671           INT_ELEM (duo_int_p_sign_posn);
672           INT_ELEM (duo_int_n_sign_posn);
673           INT_ELEM (uno_valid_from);
674           INT_ELEM (uno_valid_to);
675           INT_ELEM (duo_valid_from);
676           INT_ELEM (duo_valid_to);
677
678         case tok_mon_grouping:
679           now = lr_token (ldfile, charmap, NULL);
680           if (now->tok != tok_minus1 && now->tok != tok_number)
681             goto err_label;
682           else
683             {
684               size_t act = 0;
685               size_t max = 10;
686               char *grouping = ignore_content ? NULL : xmalloc (max);
687
688               do
689                 {
690                   if (act + 1 >= max)
691                     {
692                       max *= 2;
693                       grouping = xrealloc (grouping, max);
694                     }
695
696                   if (act > 0 && grouping[act - 1] == '\177')
697                     {
698                       lr_error (ldfile, _("\
699 %s: `-1' must be last entry in `%s' field"),
700                                 "LC_MONETARY", "mon_grouping");
701                       lr_ignore_rest (ldfile, 0);
702                       break;
703                     }
704
705                   if (now->tok == tok_minus1)
706                     {
707                       if (!ignore_content)
708                         grouping[act++] = '\177';
709                     }
710                   else if (now->val.num == 0)
711                     {
712                       /* A value of 0 disables grouping from here on but
713                          we must not store a NUL character since this
714                          terminates the string.  Use something different
715                          which must not be used otherwise.  */
716                       if (!ignore_content)
717                         grouping[act++] = '\377';
718                     }
719                   else if (now->val.num > 126)
720                     lr_error (ldfile, _("\
721 %s: values for field `%s' must be smaller than 127"),
722                               "LC_MONETARY", "mon_grouping");
723                   else if (!ignore_content)
724                     grouping[act++] = now->val.num;
725
726                   /* Next must be semicolon.  */
727                   now = lr_token (ldfile, charmap, NULL);
728                   if (now->tok != tok_semicolon)
729                     break;
730
731                   now = lr_token (ldfile, charmap, NULL);
732                 }
733               while (now->tok == tok_minus1 || now->tok == tok_number);
734
735               if (now->tok != tok_eol)
736                 goto err_label;
737
738               if (!ignore_content)
739                 {
740                   grouping[act++] = '\0';
741
742                   monetary->mon_grouping = xrealloc (grouping, act);
743                   monetary->mon_grouping_len = act;
744                 }
745             }
746           break;
747
748         case tok_conversion_rate:
749           now = lr_token (ldfile, charmap, NULL);
750           if (now->tok != tok_number)
751             goto err_label;
752           if (now->val.num == 0)
753             {
754             invalid_conversion_rate:
755               lr_error (ldfile, _("conversion rate valze cannot be zero"));
756               if (!ignore_content)
757                 {
758                   monetary->conversion_rate[0] = 1;
759                   monetary->conversion_rate[1] = 1;
760                 }
761               break;
762             }
763           if (!ignore_content)
764             monetary->conversion_rate[0] = now->val.num;
765           /* Next must be a semicolon.  */
766           now = lr_token (ldfile, charmap, NULL);
767           if (now->tok != tok_semicolon)
768             goto err_label;
769           /* And another number.  */
770           now = lr_token (ldfile, charmap, NULL);
771           if (now->tok != tok_number)
772             goto err_label;
773           if (now->val.num == 0)
774             goto invalid_conversion_rate;
775           if (!ignore_content)
776             monetary->conversion_rate[1] = now->val.num;
777           /* The rest of the line must be empty.  */
778           lr_ignore_rest (ldfile, 1);
779           break;
780
781         case tok_end:
782           /* Next we assume `LC_MONETARY'.  */
783           now = lr_token (ldfile, charmap, NULL);
784           if (now->tok == tok_eof)
785             break;
786           if (now->tok == tok_eol)
787             lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
788           else if (now->tok != tok_lc_monetary)
789             lr_error (ldfile, _("\
790 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
791           lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
792           return;
793
794         default:
795         err_label:
796           SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
797         }
798
799       /* Prepare for the next round.  */
800       now = lr_token (ldfile, charmap, NULL);
801       nowtok = now->tok;
802     }
803
804   /* When we come here we reached the end of the file.  */
805   lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
806 }