7779e87392dc4ce342084498a2ac5db5c72be3bd
[kopensolaris-gnu/glibc.git] / locale / programs / ld-monetary.c
1 /* Copyright (C) 1995-1999, 2000, 2001 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   uint32_t mon_decimal_point_wc;
47   uint32_t mon_thousands_sep_wc;
48   char *mon_grouping;
49   size_t mon_grouping_len;
50   const char *positive_sign;
51   const char *negative_sign;
52   signed char int_frac_digits;
53   signed char frac_digits;
54   signed char p_cs_precedes;
55   signed char p_sep_by_space;
56   signed char n_cs_precedes;
57   signed char n_sep_by_space;
58   signed char p_sign_posn;
59   signed char n_sign_posn;
60   signed char int_p_cs_precedes;
61   signed char int_p_sep_by_space;
62   signed char int_n_cs_precedes;
63   signed char int_n_sep_by_space;
64   signed char int_p_sign_posn;
65   signed char int_n_sign_posn;
66   const char *duo_int_curr_symbol;
67   const char *duo_currency_symbol;
68   signed char duo_int_frac_digits;
69   signed char duo_frac_digits;
70   signed char duo_p_cs_precedes;
71   signed char duo_p_sep_by_space;
72   signed char duo_n_cs_precedes;
73   signed char duo_n_sep_by_space;
74   signed char duo_p_sign_posn;
75   signed char duo_n_sign_posn;
76   signed char duo_int_p_cs_precedes;
77   signed char duo_int_p_sep_by_space;
78   signed char duo_int_n_cs_precedes;
79   signed char duo_int_n_sep_by_space;
80   signed char duo_int_p_sign_posn;
81   signed char duo_int_n_sign_posn;
82   uint32_t uno_valid_from;
83   uint32_t uno_valid_to;
84   uint32_t duo_valid_from;
85   uint32_t duo_valid_to;
86   uint32_t conversion_rate[2];
87   char *crncystr;
88 };
89
90
91 /* The content iof the field int_curr_symbol has to be taken from
92    ISO-4217.  We test for correct values.  */
93 #define DEFINE_INT_CURR(str) str,
94 static const char *const valid_int_curr[] =
95   {
96 #   include "../iso-4217.def"
97   };
98 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
99                             / sizeof (valid_int_curr[0])))
100 #undef DEFINE_INT_CURR
101
102
103 /* Prototypes for local functions.  */
104 static int curr_strcmp (const char *s1, const char **s2);
105
106
107 static void
108 monetary_startup (struct linereader *lr, struct localedef_t *locale,
109                   int ignore_content)
110 {
111   if (!ignore_content)
112     {
113       struct locale_monetary_t *monetary;
114
115       locale->categories[LC_MONETARY].monetary = monetary =
116         (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
117
118       memset (monetary, '\0', sizeof (struct locale_monetary_t));
119
120       monetary->mon_grouping = NULL;
121       monetary->mon_grouping_len = 0;
122
123       monetary->int_frac_digits = -2;
124       monetary->frac_digits = -2;
125       monetary->p_cs_precedes = -2;
126       monetary->p_sep_by_space = -2;
127       monetary->n_cs_precedes = -2;
128       monetary->n_sep_by_space = -2;
129       monetary->p_sign_posn = -2;
130       monetary->n_sign_posn = -2;
131       monetary->int_p_cs_precedes = -2;
132       monetary->int_p_sep_by_space = -2;
133       monetary->int_n_cs_precedes = -2;
134       monetary->int_n_sep_by_space = -2;
135       monetary->int_p_sign_posn = -2;
136       monetary->int_n_sign_posn = -2;
137       monetary->duo_int_frac_digits = -2;
138       monetary->duo_frac_digits = -2;
139       monetary->duo_p_cs_precedes = -2;
140       monetary->duo_p_sep_by_space = -2;
141       monetary->duo_n_cs_precedes = -2;
142       monetary->duo_n_sep_by_space = -2;
143       monetary->duo_p_sign_posn = -2;
144       monetary->duo_n_sign_posn = -2;
145       monetary->duo_int_p_cs_precedes = -2;
146       monetary->duo_int_p_sep_by_space = -2;
147       monetary->duo_int_n_cs_precedes = -2;
148       monetary->duo_int_n_sep_by_space = -2;
149       monetary->duo_int_p_sign_posn = -2;
150       monetary->duo_int_n_sign_posn = -2;
151     }
152
153   if (lr != NULL)
154     {
155       lr->translate_strings = 1;
156       lr->return_widestr = 0;
157     }
158 }
159
160
161 void
162 monetary_finish (struct localedef_t *locale, struct charmap_t *charmap)
163 {
164   struct locale_monetary_t *monetary
165     = locale->categories[LC_MONETARY].monetary;
166   int nothing = 0;
167
168   /* Now resolve copying and also handle completely missing definitions.  */
169   if (monetary == NULL)
170     {
171       /* First see whether we were supposed to copy.  If yes, find the
172          actual definition.  */
173       if (locale->copy_name[LC_MONETARY] != NULL)
174         {
175           /* Find the copying locale.  This has to happen transitively since
176              the locale we are copying from might also copying another one.  */
177           struct localedef_t *from = locale;
178
179           do
180             from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
181                                 from->repertoire_name, charmap);
182           while (from->categories[LC_MONETARY].monetary == NULL
183                  && from->copy_name[LC_MONETARY] != NULL);
184
185           monetary = locale->categories[LC_MONETARY].monetary
186             = from->categories[LC_MONETARY].monetary;
187         }
188
189       /* If there is still no definition issue an warning and create an
190          empty one.  */
191       if (monetary == NULL)
192         {
193           if (! be_quiet)
194             error (0, 0, _("No definition for %s category found"),
195                    "LC_MONETARY");
196           monetary_startup (NULL, locale, 0);
197           monetary = locale->categories[LC_MONETARY].monetary;
198           nothing = 1;
199         }
200     }
201
202 #define TEST_ELEM(cat) \
203   if (monetary->cat == NULL)                                                  \
204     {                                                                         \
205       if (! be_quiet && ! nothing)                                            \
206         error (0, 0, _("%s: field `%s' not defined"),                         \
207                "LC_MONETARY", #cat);                                          \
208       monetary->cat = "";                                                     \
209     }
210
211   TEST_ELEM (int_curr_symbol);
212   TEST_ELEM (currency_symbol);
213   TEST_ELEM (mon_decimal_point);
214   TEST_ELEM (mon_thousands_sep);
215   TEST_ELEM (positive_sign);
216   TEST_ELEM (negative_sign);
217
218   /* The international currency symbol must come from ISO 4217.  */
219   if (monetary->int_curr_symbol != NULL)
220     {
221       if (strlen (monetary->int_curr_symbol) != 4)
222         {
223           if (! be_quiet && ! nothing)
224             error (0, 0, _("\
225 %s: value of field `int_curr_symbol' has wrong length"),
226                    "LC_MONETARY");
227         }
228       else if (bsearch (monetary->int_curr_symbol, valid_int_curr,
229                         NR_VALID_INT_CURR, sizeof (const char *),
230                         (comparison_fn_t) curr_strcmp) == NULL
231                && !be_quiet)
232         error (0, 0, _("\
233 %s: value of field `int_curr_symbol' does \
234 not correspond to a valid name in ISO 4217"),
235                "LC_MONETARY");
236     }
237
238   /* The decimal point must not be empty.  This is not said explicitly
239      in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
240      != "".  */
241   if (monetary->mon_decimal_point == NULL)
242     {
243       if (! be_quiet && ! nothing)
244         error (0, 0, _("%s: field `%s' not defined"),
245                "LC_MONETARY", "mon_decimal_point");
246       monetary->mon_decimal_point = "";
247     }
248   else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
249     {
250       error (0, 0, _("\
251 %s: value for field `%s' must not be the empty string"),
252              "LC_MONETARY", "mon_decimal_point");
253     }
254   if (monetary->mon_decimal_point_wc == L'\0')
255     monetary->mon_decimal_point_wc = L'.';
256
257   if (monetary->mon_grouping_len == 0)
258     {
259       if (! be_quiet && ! nothing)
260         error (0, 0, _("%s: field `%s' not defined"),
261                "LC_MONETARY", "mon_grouping");
262
263       monetary->mon_grouping = (char *) "\177";
264       monetary->mon_grouping_len = 1;
265     }
266
267 #undef TEST_ELEM
268 #define TEST_ELEM(cat, min, max) \
269   if (monetary->cat == -2)                                                    \
270     {                                                                         \
271        if (! be_quiet && ! nothing)                                           \
272          error (0, 0, _("%s: field `%s' not defined"),                        \
273                 "LC_MONETARY", #cat);                                         \
274     }                                                                         \
275   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet          \
276            && !nothing)                                                       \
277     error (0, 0, _("                                                          \
278 %s: value for field `%s' must be in range %d...%d"),                          \
279            "LC_MONETARY", #cat, min, max)
280
281 #if 0
282 /* The following two test are not really necessary because all values
283     the variable could have are valid.  */
284   TEST_ELEM (int_frac_digits, -128, 127);       /* No range check.  */
285   TEST_ELEM (frac_digits, -128, 127);           /* No range check.  */
286 #endif
287   TEST_ELEM (p_cs_precedes, -1, 1);
288   TEST_ELEM (p_sep_by_space, -1, 2);
289   TEST_ELEM (n_cs_precedes, -1, 1);
290   TEST_ELEM (n_sep_by_space, -1, 2);
291   TEST_ELEM (p_sign_posn, -1, 4);
292   TEST_ELEM (n_sign_posn, -1, 4);
293
294   /* The non-POSIX.2 extensions are optional.  */
295   if (monetary->duo_int_curr_symbol == NULL)
296     monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
297   if (monetary->duo_currency_symbol == NULL)
298     monetary->duo_currency_symbol = monetary->currency_symbol;
299
300   if (monetary->duo_int_frac_digits == -2)
301     monetary->duo_int_frac_digits = monetary->int_frac_digits;
302   if (monetary->duo_frac_digits == -2)
303     monetary->duo_frac_digits = monetary->frac_digits;
304
305 #undef TEST_ELEM
306 #define TEST_ELEM(cat, alt, min, max) \
307   if (monetary->cat == -2)                                                    \
308     monetary->cat = monetary->alt;                                            \
309   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet          \
310            && ! nothing)                                                      \
311     error (0, 0, _("\
312 %s: value for field `%s' must be in range %d...%d"),                          \
313            "LC_MONETARY", #cat, min, max)
314
315   TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
316   TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
317   TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
318   TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
319   TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
320   TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
321
322   TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
323   TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
324   TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
325   TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
326   TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
327   TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
328   TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
329   TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
330   TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
331   TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
332   TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
333   TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
334
335   if (monetary->uno_valid_from == 0)
336     monetary->uno_valid_from = 10101;
337   if (monetary->uno_valid_to == 0)
338     monetary->uno_valid_to = 99991231;
339   if (monetary->duo_valid_from == 0)
340     monetary->duo_valid_from = 10101;
341   if (monetary->duo_valid_to == 0)
342     monetary->duo_valid_to = 99991231;
343
344   if (monetary->conversion_rate[0] == 0)
345     {
346       monetary->conversion_rate[0] = 1;
347       monetary->conversion_rate[1] = 1;
348     }
349
350   /* Create the crncystr entry.  */
351   monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
352                                          + 2);
353   monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
354   strcpy (&monetary->crncystr[1], monetary->currency_symbol);
355 }
356
357
358 void
359 monetary_output (struct localedef_t *locale, struct charmap_t *charmap,
360                  const char *output_path)
361 {
362   struct locale_monetary_t *monetary
363     = locale->categories[LC_MONETARY].monetary;
364   struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
365   struct locale_file data;
366   uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
367   size_t cnt = 0;
368
369   data.magic = LIMAGIC (LC_MONETARY);
370   data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
371   iov[cnt].iov_base = (void *) &data;
372   iov[cnt].iov_len = sizeof (data);
373   ++cnt;
374
375   iov[cnt].iov_base = (void *) idx;
376   iov[cnt].iov_len = sizeof (idx);
377   ++cnt;
378
379   idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
380   iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
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->currency_symbol;
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->mon_decimal_point;
391   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
392   ++cnt;
393
394   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
395   iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
396   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
397   ++cnt;
398
399   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
400   iov[cnt].iov_base = monetary->mon_grouping;
401   iov[cnt].iov_len = monetary->mon_grouping_len;
402   ++cnt;
403
404   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
405   iov[cnt].iov_base = (void *) monetary->positive_sign;
406   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
407   ++cnt;
408
409   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
410   iov[cnt].iov_base = (void *) monetary->negative_sign;
411   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
412   ++cnt;
413
414   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
415   iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
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->frac_digits;
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->p_cs_precedes;
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->p_sep_by_space;
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->n_cs_precedes;
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->n_sep_by_space;
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->p_sign_posn;
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->n_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->crncystr;
456   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
457   ++cnt;
458
459   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
460   iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
461   iov[cnt].iov_len = 1;
462   ++cnt;
463
464   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
465   iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
466   iov[cnt].iov_len = 1;
467   ++cnt;
468
469   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
470   iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
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->int_n_sep_by_space;
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->int_p_sign_posn;
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->int_n_sign_posn;
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_int_curr_symbol;
491   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
492   ++cnt;
493
494   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
495   iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
496   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 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_frac_digits;
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_frac_digits;
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_p_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_p_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_n_cs_precedes;
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_sep_by_space;
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_cs_precedes;
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_p_sep_by_space;
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->duo_int_n_cs_precedes;
541   iov[cnt].iov_len = 1;
542   ++cnt;
543
544   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
545   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
546   iov[cnt].iov_len = 1;
547   ++cnt;
548
549   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
550   iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
551   iov[cnt].iov_len = 1;
552   ++cnt;
553
554   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
555   iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
556   iov[cnt].iov_len = 1;
557   ++cnt;
558
559   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
560   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
561   iov[cnt].iov_len = 1;
562   ++cnt;
563
564   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
565   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
566   iov[cnt].iov_len = 1;
567   ++cnt;
568
569   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
570
571   /* Align following data */
572   iov[cnt].iov_base = (void *) "\0\0";
573   iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
574   idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
575   ++cnt;
576
577   iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
578   iov[cnt].iov_len = sizeof(uint32_t);
579   ++cnt;
580
581   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
582   iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
583   iov[cnt].iov_len = sizeof(uint32_t);
584   ++cnt;
585
586   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
587   iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
588   iov[cnt].iov_len = sizeof(uint32_t);
589   ++cnt;
590
591   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
592   iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
593   iov[cnt].iov_len = sizeof(uint32_t);
594   ++cnt;
595
596   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
597   iov[cnt].iov_base = (void *) monetary->conversion_rate;
598   iov[cnt].iov_len = 2 * sizeof(uint32_t);
599   ++cnt;
600
601   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
602   iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
603   iov[cnt].iov_len = sizeof (uint32_t);
604   ++cnt;
605
606   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
607   iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
608   iov[cnt].iov_len = sizeof (uint32_t);
609   ++cnt;
610
611   assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
612
613   write_locale_data (output_path, "LC_MONETARY",
614                      3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
615 }
616
617
618 static int
619 curr_strcmp (const char *s1, const char **s2)
620 {
621   return strcmp (s1, *s2);
622 }
623
624
625 /* The parser for the LC_MONETARY section of the locale definition.  */
626 void
627 monetary_read (struct linereader *ldfile, struct localedef_t *result,
628                struct charmap_t *charmap, const char *repertoire_name,
629                int ignore_content)
630 {
631   struct repertoire_t *repertoire = NULL;
632   struct locale_monetary_t *monetary;
633   struct token *now;
634   enum token_t nowtok;
635
636   /* Get the repertoire we have to use.  */
637   if (repertoire_name != NULL)
638     repertoire = repertoire_read (repertoire_name);
639
640   /* The rest of the line containing `LC_MONETARY' must be free.  */
641   lr_ignore_rest (ldfile, 1);
642
643   do
644     {
645       now = lr_token (ldfile, charmap, NULL, verbose);
646       nowtok = now->tok;
647     }
648   while (nowtok == tok_eol);
649
650   /* If we see `copy' now we are almost done.  */
651   if (nowtok == tok_copy)
652     {
653       handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
654                    LC_MONETARY, "LC_MONETARY", ignore_content);
655       return;
656     }
657
658   /* Prepare the data structures.  */
659   monetary_startup (ldfile, result, ignore_content);
660   monetary = result->categories[LC_MONETARY].monetary;
661
662   while (1)
663     {
664       /* Of course we don't proceed beyond the end of file.  */
665       if (nowtok == tok_eof)
666         break;
667
668       /* Ignore empty lines.  */
669       if (nowtok == tok_eol)
670         {
671           now = lr_token (ldfile, charmap, NULL, verbose);
672           nowtok = now->tok;
673           continue;
674         }
675
676       switch (nowtok)
677         {
678 #define STR_ELEM(cat) \
679         case tok_##cat:                                                       \
680           /* Ignore the rest of the line if we don't need the input of        \
681              this line.  */                                                   \
682           if (ignore_content)                                                 \
683             {                                                                 \
684               lr_ignore_rest (ldfile, 0);                                     \
685               break;                                                          \
686             }                                                                 \
687                                                                               \
688           now = lr_token (ldfile, charmap, NULL, verbose);                    \
689           if (now->tok != tok_string)                                         \
690             goto err_label;                                                   \
691           else if (monetary->cat != NULL)                                     \
692             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
693                       "LC_MONETARY", #cat);                                   \
694           else if (!ignore_content && now->val.str.startmb == NULL)           \
695             {                                                                 \
696               lr_error (ldfile, _("\
697 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                  \
698               monetary->cat = "";                                             \
699             }                                                                 \
700           else if (!ignore_content)                                           \
701             monetary->cat = now->val.str.startmb;                             \
702           lr_ignore_rest (ldfile, 1);                                         \
703           break
704
705           STR_ELEM (int_curr_symbol);
706           STR_ELEM (currency_symbol);
707           STR_ELEM (positive_sign);
708           STR_ELEM (negative_sign);
709           STR_ELEM (duo_int_curr_symbol);
710           STR_ELEM (duo_currency_symbol);
711
712 #define STR_ELEM_WC(cat) \
713         case tok_##cat:                                                       \
714           /* Ignore the rest of the line if we don't need the input of        \
715              this line.  */                                                   \
716           if (ignore_content)                                                 \
717             {                                                                 \
718               lr_ignore_rest (ldfile, 0);                                     \
719               break;                                                          \
720             }                                                                 \
721                                                                               \
722           ldfile->return_widestr = 1;                                         \
723           now = lr_token (ldfile, charmap, repertoire, verbose);              \
724           if (now->tok != tok_string)                                         \
725             goto err_label;                                                   \
726           if (monetary->cat != NULL)                                          \
727             lr_error (ldfile, _("\
728 %s: field `%s' declared more than once"), "LC_MONETARY", #cat);               \
729           else if (!ignore_content && now->val.str.startmb == NULL)           \
730             {                                                                 \
731               lr_error (ldfile, _("\
732 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                  \
733               monetary->cat = "";                                             \
734               monetary->cat##_wc = L'\0';                                     \
735             }                                                                 \
736           else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2)    \
737             {                                                                 \
738               lr_error (ldfile, _("\
739 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat);  \
740             }                                                                 \
741           else if (!ignore_content)                                           \
742             {                                                                 \
743               monetary->cat = now->val.str.startmb;                           \
744                                                                               \
745               if (now->val.str.startwc != NULL)                               \
746                 monetary->cat##_wc = *now->val.str.startwc;                   \
747             }                                                                 \
748           ldfile->return_widestr = 0;                                         \
749           break
750
751           STR_ELEM_WC (mon_decimal_point);
752           STR_ELEM_WC (mon_thousands_sep);
753
754 #define INT_ELEM(cat) \
755         case tok_##cat:                                                       \
756           /* Ignore the rest of the line if we don't need the input of        \
757              this line.  */                                                   \
758           if (ignore_content)                                                 \
759             {                                                                 \
760               lr_ignore_rest (ldfile, 0);                                     \
761               break;                                                          \
762             }                                                                 \
763                                                                               \
764           now = lr_token (ldfile, charmap, NULL, verbose);                    \
765           if (now->tok != tok_minus1 && now->tok != tok_number)               \
766             goto err_label;                                                   \
767           else if (monetary->cat != -2)                                       \
768             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
769                       "LC_MONETARY", #cat);                                   \
770           else if (!ignore_content)                                           \
771             monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num;       \
772           break
773
774           INT_ELEM (int_frac_digits);
775           INT_ELEM (frac_digits);
776           INT_ELEM (p_cs_precedes);
777           INT_ELEM (p_sep_by_space);
778           INT_ELEM (n_cs_precedes);
779           INT_ELEM (n_sep_by_space);
780           INT_ELEM (p_sign_posn);
781           INT_ELEM (n_sign_posn);
782           INT_ELEM (int_p_cs_precedes);
783           INT_ELEM (int_p_sep_by_space);
784           INT_ELEM (int_n_cs_precedes);
785           INT_ELEM (int_n_sep_by_space);
786           INT_ELEM (int_p_sign_posn);
787           INT_ELEM (int_n_sign_posn);
788           INT_ELEM (duo_int_frac_digits);
789           INT_ELEM (duo_frac_digits);
790           INT_ELEM (duo_p_cs_precedes);
791           INT_ELEM (duo_p_sep_by_space);
792           INT_ELEM (duo_n_cs_precedes);
793           INT_ELEM (duo_n_sep_by_space);
794           INT_ELEM (duo_p_sign_posn);
795           INT_ELEM (duo_n_sign_posn);
796           INT_ELEM (duo_int_p_cs_precedes);
797           INT_ELEM (duo_int_p_sep_by_space);
798           INT_ELEM (duo_int_n_cs_precedes);
799           INT_ELEM (duo_int_n_sep_by_space);
800           INT_ELEM (duo_int_p_sign_posn);
801           INT_ELEM (duo_int_n_sign_posn);
802           INT_ELEM (uno_valid_from);
803           INT_ELEM (uno_valid_to);
804           INT_ELEM (duo_valid_from);
805           INT_ELEM (duo_valid_to);
806
807         case tok_mon_grouping:
808           /* Ignore the rest of the line if we don't need the input of
809              this line.  */
810           if (ignore_content)
811             {
812               lr_ignore_rest (ldfile, 0);
813               break;
814             }
815
816           now = lr_token (ldfile, charmap, NULL, verbose);
817           if (now->tok != tok_minus1 && now->tok != tok_number)
818             goto err_label;
819           else
820             {
821               size_t act = 0;
822               size_t max = 10;
823               char *grouping = ignore_content ? NULL : xmalloc (max);
824
825               do
826                 {
827                   if (act + 1 >= max)
828                     {
829                       max *= 2;
830                       grouping = xrealloc (grouping, max);
831                     }
832
833                   if (act > 0 && grouping[act - 1] == '\177')
834                     {
835                       lr_error (ldfile, _("\
836 %s: `-1' must be last entry in `%s' field"),
837                                 "LC_MONETARY", "mon_grouping");
838                       lr_ignore_rest (ldfile, 0);
839                       break;
840                     }
841
842                   if (now->tok == tok_minus1)
843                     {
844                       if (!ignore_content)
845                         grouping[act++] = '\177';
846                     }
847                   else if (now->val.num == 0)
848                     {
849                       /* A value of 0 disables grouping from here on but
850                          we must not store a NUL character since this
851                          terminates the string.  Use something different
852                          which must not be used otherwise.  */
853                       if (!ignore_content)
854                         grouping[act++] = '\377';
855                     }
856                   else if (now->val.num > 126)
857                     lr_error (ldfile, _("\
858 %s: values for field `%s' must be smaller than 127"),
859                               "LC_MONETARY", "mon_grouping");
860                   else if (!ignore_content)
861                     grouping[act++] = now->val.num;
862
863                   /* Next must be semicolon.  */
864                   now = lr_token (ldfile, charmap, NULL, verbose);
865                   if (now->tok != tok_semicolon)
866                     break;
867
868                   now = lr_token (ldfile, charmap, NULL, verbose);
869                 }
870               while (now->tok == tok_minus1 || now->tok == tok_number);
871
872               if (now->tok != tok_eol)
873                 goto err_label;
874
875               if (!ignore_content)
876                 {
877                   grouping[act++] = '\0';
878
879                   monetary->mon_grouping = xrealloc (grouping, act);
880                   monetary->mon_grouping_len = act;
881                 }
882             }
883           break;
884
885         case tok_conversion_rate:
886           /* Ignore the rest of the line if we don't need the input of
887              this line.  */
888           if (ignore_content)
889             {
890               lr_ignore_rest (ldfile, 0);
891               break;
892             }
893
894           now = lr_token (ldfile, charmap, NULL, verbose);
895           if (now->tok != tok_number)
896             goto err_label;
897           if (now->val.num == 0)
898             {
899             invalid_conversion_rate:
900               lr_error (ldfile, _("conversion rate value cannot be zero"));
901               if (!ignore_content)
902                 {
903                   monetary->conversion_rate[0] = 1;
904                   monetary->conversion_rate[1] = 1;
905                 }
906               break;
907             }
908           if (!ignore_content)
909             monetary->conversion_rate[0] = now->val.num;
910           /* Next must be a semicolon.  */
911           now = lr_token (ldfile, charmap, NULL, verbose);
912           if (now->tok != tok_semicolon)
913             goto err_label;
914           /* And another number.  */
915           now = lr_token (ldfile, charmap, NULL, verbose);
916           if (now->tok != tok_number)
917             goto err_label;
918           if (now->val.num == 0)
919             goto invalid_conversion_rate;
920           if (!ignore_content)
921             monetary->conversion_rate[1] = now->val.num;
922           /* The rest of the line must be empty.  */
923           lr_ignore_rest (ldfile, 1);
924           break;
925
926         case tok_end:
927           /* Next we assume `LC_MONETARY'.  */
928           now = lr_token (ldfile, charmap, NULL, verbose);
929           if (now->tok == tok_eof)
930             break;
931           if (now->tok == tok_eol)
932             lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
933           else if (now->tok != tok_lc_monetary)
934             lr_error (ldfile, _("\
935 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
936           lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
937           return;
938
939         default:
940         err_label:
941           SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
942         }
943
944       /* Prepare for the next round.  */
945       now = lr_token (ldfile, charmap, NULL, verbose);
946       nowtok = now->tok;
947     }
948
949   /* When we come here we reached the end of the file.  */
950   lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
951 }