Adjust for additional parameter to lr_token.
[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 Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the 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    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    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, const 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, initval) \
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 = initval;                                                \
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, initval) \
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        monetary->cat = initval;                                               \
275     }                                                                         \
276   else if ((monetary->cat < min || monetary->cat > max)                       \
277            && !be_quiet && !nothing)                                          \
278     error (0, 0, _("                                                          \
279 %s: value for field `%s' must be in range %d...%d"),                          \
280            "LC_MONETARY", #cat, min, max)
281
282   TEST_ELEM (int_frac_digits, -128, 127, -1);
283   TEST_ELEM (frac_digits, -128, 127, -1);
284   TEST_ELEM (p_cs_precedes, -1, 1, -1);
285   TEST_ELEM (p_sep_by_space, -1, 2, -1);
286   TEST_ELEM (n_cs_precedes, -1, 1, -1);
287   TEST_ELEM (n_sep_by_space, -1, 2, -1);
288   TEST_ELEM (p_sign_posn, -1, 4, -1);
289   TEST_ELEM (n_sign_posn, -1, 4, -1);
290
291   /* The non-POSIX.2 extensions are optional.  */
292   if (monetary->duo_int_curr_symbol == NULL)
293     monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
294   if (monetary->duo_currency_symbol == NULL)
295     monetary->duo_currency_symbol = monetary->currency_symbol;
296
297   if (monetary->duo_int_frac_digits == -2)
298     monetary->duo_int_frac_digits = monetary->int_frac_digits;
299   if (monetary->duo_frac_digits == -2)
300     monetary->duo_frac_digits = monetary->frac_digits;
301
302 #undef TEST_ELEM
303 #define TEST_ELEM(cat, alt, min, max) \
304   if (monetary->cat == -2)                                                    \
305     monetary->cat = monetary->alt;                                            \
306   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet          \
307            && ! nothing)                                                      \
308     error (0, 0, _("\
309 %s: value for field `%s' must be in range %d...%d"),                          \
310            "LC_MONETARY", #cat, min, max)
311
312   TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
313   TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
314   TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
315   TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
316   TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
317   TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
318
319   TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
320   TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
321   TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
322   TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
323   TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
324   TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
325   TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
326   TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
327   TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
328   TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
329   TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
330   TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
331
332   if (monetary->uno_valid_from == 0)
333     monetary->uno_valid_from = 10101;
334   if (monetary->uno_valid_to == 0)
335     monetary->uno_valid_to = 99991231;
336   if (monetary->duo_valid_from == 0)
337     monetary->duo_valid_from = 10101;
338   if (monetary->duo_valid_to == 0)
339     monetary->duo_valid_to = 99991231;
340
341   if (monetary->conversion_rate[0] == 0)
342     {
343       monetary->conversion_rate[0] = 1;
344       monetary->conversion_rate[1] = 1;
345     }
346
347   /* Create the crncystr entry.  */
348   monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
349                                          + 2);
350   monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
351   strcpy (&monetary->crncystr[1], monetary->currency_symbol);
352 }
353
354
355 void
356 monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
357                  const char *output_path)
358 {
359   struct locale_monetary_t *monetary
360     = locale->categories[LC_MONETARY].monetary;
361   struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
362   struct locale_file data;
363   uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
364   size_t cnt = 0;
365
366   data.magic = LIMAGIC (LC_MONETARY);
367   data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
368   iov[cnt].iov_base = (void *) &data;
369   iov[cnt].iov_len = sizeof (data);
370   ++cnt;
371
372   iov[cnt].iov_base = (void *) idx;
373   iov[cnt].iov_len = sizeof (idx);
374   ++cnt;
375
376   idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
377   iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
378   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
379   ++cnt;
380
381   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
382   iov[cnt].iov_base = (void *) monetary->currency_symbol;
383   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
384   ++cnt;
385
386   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
387   iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
388   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
389   ++cnt;
390
391   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
392   iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
393   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
394   ++cnt;
395
396   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
397   iov[cnt].iov_base = monetary->mon_grouping;
398   iov[cnt].iov_len = monetary->mon_grouping_len;
399   ++cnt;
400
401   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
402   iov[cnt].iov_base = (void *) monetary->positive_sign;
403   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
404   ++cnt;
405
406   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
407   iov[cnt].iov_base = (void *) monetary->negative_sign;
408   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
409   ++cnt;
410
411   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
412   iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
413   iov[cnt].iov_len = 1;
414   ++cnt;
415
416   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
417   iov[cnt].iov_base = (void *) &monetary->frac_digits;
418   iov[cnt].iov_len = 1;
419   ++cnt;
420
421   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
422   iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
423   iov[cnt].iov_len = 1;
424   ++cnt;
425
426   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
427   iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
428   iov[cnt].iov_len = 1;
429   ++cnt;
430
431   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
432   iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
433   iov[cnt].iov_len = 1;
434   ++cnt;
435
436   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
437   iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
438   iov[cnt].iov_len = 1;
439   ++cnt;
440
441   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
442   iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
443   iov[cnt].iov_len = 1;
444   ++cnt;
445
446   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
447   iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
448   iov[cnt].iov_len = 1;
449   ++cnt;
450
451   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
452   iov[cnt].iov_base = (void *) monetary->crncystr;
453   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
454   ++cnt;
455
456   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
457   iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
458   iov[cnt].iov_len = 1;
459   ++cnt;
460
461   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
462   iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
463   iov[cnt].iov_len = 1;
464   ++cnt;
465
466   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
467   iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
468   iov[cnt].iov_len = 1;
469   ++cnt;
470
471   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
472   iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
473   iov[cnt].iov_len = 1;
474   ++cnt;
475
476   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
477   iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
478   iov[cnt].iov_len = 1;
479   ++cnt;
480
481   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
482   iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
483   iov[cnt].iov_len = 1;
484   ++cnt;
485
486   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
487   iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
488   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
489   ++cnt;
490
491   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
492   iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
493   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
494   ++cnt;
495
496   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
497   iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
498   iov[cnt].iov_len = 1;
499   ++cnt;
500
501   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
502   iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
503   iov[cnt].iov_len = 1;
504   ++cnt;
505
506   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
507   iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
508   iov[cnt].iov_len = 1;
509   ++cnt;
510
511   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
512   iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
513   iov[cnt].iov_len = 1;
514   ++cnt;
515
516   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
517   iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
518   iov[cnt].iov_len = 1;
519   ++cnt;
520
521   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
522   iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
523   iov[cnt].iov_len = 1;
524   ++cnt;
525
526   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
527   iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
528   iov[cnt].iov_len = 1;
529   ++cnt;
530
531   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
532   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
533   iov[cnt].iov_len = 1;
534   ++cnt;
535
536   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
537   iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
538   iov[cnt].iov_len = 1;
539   ++cnt;
540
541   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
542   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
543   iov[cnt].iov_len = 1;
544   ++cnt;
545
546   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
547   iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
548   iov[cnt].iov_len = 1;
549   ++cnt;
550
551   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
552   iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
553   iov[cnt].iov_len = 1;
554   ++cnt;
555
556   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
557   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
558   iov[cnt].iov_len = 1;
559   ++cnt;
560
561   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
562   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
563   iov[cnt].iov_len = 1;
564   ++cnt;
565
566   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
567
568   /* Align following data */
569   iov[cnt].iov_base = (void *) "\0\0";
570   iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
571   idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
572   ++cnt;
573
574   iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
575   iov[cnt].iov_len = sizeof(uint32_t);
576   ++cnt;
577
578   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
579   iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
580   iov[cnt].iov_len = sizeof(uint32_t);
581   ++cnt;
582
583   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
584   iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
585   iov[cnt].iov_len = sizeof(uint32_t);
586   ++cnt;
587
588   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
589   iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
590   iov[cnt].iov_len = sizeof(uint32_t);
591   ++cnt;
592
593   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
594   iov[cnt].iov_base = (void *) monetary->conversion_rate;
595   iov[cnt].iov_len = 2 * sizeof(uint32_t);
596   ++cnt;
597
598   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
599   iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
600   iov[cnt].iov_len = sizeof (uint32_t);
601   ++cnt;
602
603   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
604   iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
605   iov[cnt].iov_len = sizeof (uint32_t);
606   ++cnt;
607
608   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
609   iov[cnt].iov_base = (void *) charmap->code_set_name;
610   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
611   ++cnt;
612
613   assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
614
615   write_locale_data (output_path, "LC_MONETARY",
616                      3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
617 }
618
619
620 static int
621 curr_strcmp (const char *s1, const char **s2)
622 {
623   return strcmp (s1, *s2);
624 }
625
626
627 /* The parser for the LC_MONETARY section of the locale definition.  */
628 void
629 monetary_read (struct linereader *ldfile, struct localedef_t *result,
630                const struct charmap_t *charmap, const char *repertoire_name,
631                int ignore_content)
632 {
633   struct repertoire_t *repertoire = NULL;
634   struct locale_monetary_t *monetary;
635   struct token *now;
636   enum token_t nowtok;
637
638   /* Get the repertoire we have to use.  */
639   if (repertoire_name != NULL)
640     repertoire = repertoire_read (repertoire_name);
641
642   /* The rest of the line containing `LC_MONETARY' must be free.  */
643   lr_ignore_rest (ldfile, 1);
644
645   do
646     {
647       now = lr_token (ldfile, charmap, result, NULL, verbose);
648       nowtok = now->tok;
649     }
650   while (nowtok == tok_eol);
651
652   /* If we see `copy' now we are almost done.  */
653   if (nowtok == tok_copy)
654     {
655       handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
656                    LC_MONETARY, "LC_MONETARY", ignore_content);
657       return;
658     }
659
660   /* Prepare the data structures.  */
661   monetary_startup (ldfile, result, ignore_content);
662   monetary = result->categories[LC_MONETARY].monetary;
663
664   while (1)
665     {
666       /* Of course we don't proceed beyond the end of file.  */
667       if (nowtok == tok_eof)
668         break;
669
670       /* Ignore empty lines.  */
671       if (nowtok == tok_eol)
672         {
673           now = lr_token (ldfile, charmap, result, NULL, verbose);
674           nowtok = now->tok;
675           continue;
676         }
677
678       switch (nowtok)
679         {
680 #define STR_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, result, NULL, verbose);            \
691           if (now->tok != tok_string)                                         \
692             goto err_label;                                                   \
693           else if (monetary->cat != NULL)                                     \
694             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
695                       "LC_MONETARY", #cat);                                   \
696           else if (!ignore_content && now->val.str.startmb == NULL)           \
697             {                                                                 \
698               lr_error (ldfile, _("\
699 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                  \
700               monetary->cat = "";                                             \
701             }                                                                 \
702           else if (!ignore_content)                                           \
703             monetary->cat = now->val.str.startmb;                             \
704           lr_ignore_rest (ldfile, 1);                                         \
705           break
706
707           STR_ELEM (int_curr_symbol);
708           STR_ELEM (currency_symbol);
709           STR_ELEM (positive_sign);
710           STR_ELEM (negative_sign);
711           STR_ELEM (duo_int_curr_symbol);
712           STR_ELEM (duo_currency_symbol);
713
714 #define STR_ELEM_WC(cat) \
715         case tok_##cat:                                                       \
716           /* Ignore the rest of the line if we don't need the input of        \
717              this line.  */                                                   \
718           if (ignore_content)                                                 \
719             {                                                                 \
720               lr_ignore_rest (ldfile, 0);                                     \
721               break;                                                          \
722             }                                                                 \
723                                                                               \
724           ldfile->return_widestr = 1;                                         \
725           now = lr_token (ldfile, charmap, result, repertoire, verbose);      \
726           if (now->tok != tok_string)                                         \
727             goto err_label;                                                   \
728           if (monetary->cat != NULL)                                          \
729             lr_error (ldfile, _("\
730 %s: field `%s' declared more than once"), "LC_MONETARY", #cat);               \
731           else if (!ignore_content && now->val.str.startmb == NULL)           \
732             {                                                                 \
733               lr_error (ldfile, _("\
734 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                  \
735               monetary->cat = "";                                             \
736               monetary->cat##_wc = L'\0';                                     \
737             }                                                                 \
738           else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2)    \
739             {                                                                 \
740               lr_error (ldfile, _("\
741 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat);  \
742             }                                                                 \
743           else if (!ignore_content)                                           \
744             {                                                                 \
745               monetary->cat = now->val.str.startmb;                           \
746                                                                               \
747               if (now->val.str.startwc != NULL)                               \
748                 monetary->cat##_wc = *now->val.str.startwc;                   \
749             }                                                                 \
750           ldfile->return_widestr = 0;                                         \
751           break
752
753           STR_ELEM_WC (mon_decimal_point);
754           STR_ELEM_WC (mon_thousands_sep);
755
756 #define INT_ELEM(cat) \
757         case tok_##cat:                                                       \
758           /* Ignore the rest of the line if we don't need the input of        \
759              this line.  */                                                   \
760           if (ignore_content)                                                 \
761             {                                                                 \
762               lr_ignore_rest (ldfile, 0);                                     \
763               break;                                                          \
764             }                                                                 \
765                                                                               \
766           now = lr_token (ldfile, charmap, result, NULL, verbose);            \
767           if (now->tok != tok_minus1 && now->tok != tok_number)               \
768             goto err_label;                                                   \
769           else if (monetary->cat != -2)                                       \
770             lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
771                       "LC_MONETARY", #cat);                                   \
772           else if (!ignore_content)                                           \
773             monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num;       \
774           break
775
776           INT_ELEM (int_frac_digits);
777           INT_ELEM (frac_digits);
778           INT_ELEM (p_cs_precedes);
779           INT_ELEM (p_sep_by_space);
780           INT_ELEM (n_cs_precedes);
781           INT_ELEM (n_sep_by_space);
782           INT_ELEM (p_sign_posn);
783           INT_ELEM (n_sign_posn);
784           INT_ELEM (int_p_cs_precedes);
785           INT_ELEM (int_p_sep_by_space);
786           INT_ELEM (int_n_cs_precedes);
787           INT_ELEM (int_n_sep_by_space);
788           INT_ELEM (int_p_sign_posn);
789           INT_ELEM (int_n_sign_posn);
790           INT_ELEM (duo_int_frac_digits);
791           INT_ELEM (duo_frac_digits);
792           INT_ELEM (duo_p_cs_precedes);
793           INT_ELEM (duo_p_sep_by_space);
794           INT_ELEM (duo_n_cs_precedes);
795           INT_ELEM (duo_n_sep_by_space);
796           INT_ELEM (duo_p_sign_posn);
797           INT_ELEM (duo_n_sign_posn);
798           INT_ELEM (duo_int_p_cs_precedes);
799           INT_ELEM (duo_int_p_sep_by_space);
800           INT_ELEM (duo_int_n_cs_precedes);
801           INT_ELEM (duo_int_n_sep_by_space);
802           INT_ELEM (duo_int_p_sign_posn);
803           INT_ELEM (duo_int_n_sign_posn);
804           INT_ELEM (uno_valid_from);
805           INT_ELEM (uno_valid_to);
806           INT_ELEM (duo_valid_from);
807           INT_ELEM (duo_valid_to);
808
809         case tok_mon_grouping:
810           /* Ignore the rest of the line if we don't need the input of
811              this line.  */
812           if (ignore_content)
813             {
814               lr_ignore_rest (ldfile, 0);
815               break;
816             }
817
818           now = lr_token (ldfile, charmap, result, NULL, verbose);
819           if (now->tok != tok_minus1 && now->tok != tok_number)
820             goto err_label;
821           else
822             {
823               size_t act = 0;
824               size_t max = 10;
825               char *grouping = ignore_content ? NULL : xmalloc (max);
826
827               do
828                 {
829                   if (act + 1 >= max)
830                     {
831                       max *= 2;
832                       grouping = xrealloc (grouping, max);
833                     }
834
835                   if (act > 0 && grouping[act - 1] == '\177')
836                     {
837                       lr_error (ldfile, _("\
838 %s: `-1' must be last entry in `%s' field"),
839                                 "LC_MONETARY", "mon_grouping");
840                       lr_ignore_rest (ldfile, 0);
841                       break;
842                     }
843
844                   if (now->tok == tok_minus1)
845                     {
846                       if (!ignore_content)
847                         grouping[act++] = '\177';
848                     }
849                   else if (now->val.num == 0)
850                     {
851                       /* A value of 0 disables grouping from here on but
852                          we must not store a NUL character since this
853                          terminates the string.  Use something different
854                          which must not be used otherwise.  */
855                       if (!ignore_content)
856                         grouping[act++] = '\377';
857                     }
858                   else if (now->val.num > 126)
859                     lr_error (ldfile, _("\
860 %s: values for field `%s' must be smaller than 127"),
861                               "LC_MONETARY", "mon_grouping");
862                   else if (!ignore_content)
863                     grouping[act++] = now->val.num;
864
865                   /* Next must be semicolon.  */
866                   now = lr_token (ldfile, charmap, result, NULL, verbose);
867                   if (now->tok != tok_semicolon)
868                     break;
869
870                   now = lr_token (ldfile, charmap, result, NULL, verbose);
871                 }
872               while (now->tok == tok_minus1 || now->tok == tok_number);
873
874               if (now->tok != tok_eol)
875                 goto err_label;
876
877               if (!ignore_content)
878                 {
879                   grouping[act++] = '\0';
880
881                   monetary->mon_grouping = xrealloc (grouping, act);
882                   monetary->mon_grouping_len = act;
883                 }
884             }
885           break;
886
887         case tok_conversion_rate:
888           /* Ignore the rest of the line if we don't need the input of
889              this line.  */
890           if (ignore_content)
891             {
892               lr_ignore_rest (ldfile, 0);
893               break;
894             }
895
896           now = lr_token (ldfile, charmap, result, NULL, verbose);
897           if (now->tok != tok_number)
898             goto err_label;
899           if (now->val.num == 0)
900             {
901             invalid_conversion_rate:
902               lr_error (ldfile, _("conversion rate value cannot be zero"));
903               if (!ignore_content)
904                 {
905                   monetary->conversion_rate[0] = 1;
906                   monetary->conversion_rate[1] = 1;
907                 }
908               break;
909             }
910           if (!ignore_content)
911             monetary->conversion_rate[0] = now->val.num;
912           /* Next must be a semicolon.  */
913           now = lr_token (ldfile, charmap, result, NULL, verbose);
914           if (now->tok != tok_semicolon)
915             goto err_label;
916           /* And another number.  */
917           now = lr_token (ldfile, charmap, result, NULL, verbose);
918           if (now->tok != tok_number)
919             goto err_label;
920           if (now->val.num == 0)
921             goto invalid_conversion_rate;
922           if (!ignore_content)
923             monetary->conversion_rate[1] = now->val.num;
924           /* The rest of the line must be empty.  */
925           lr_ignore_rest (ldfile, 1);
926           break;
927
928         case tok_end:
929           /* Next we assume `LC_MONETARY'.  */
930           now = lr_token (ldfile, charmap, result, NULL, verbose);
931           if (now->tok == tok_eof)
932             break;
933           if (now->tok == tok_eol)
934             lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
935           else if (now->tok != tok_lc_monetary)
936             lr_error (ldfile, _("\
937 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
938           lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
939           return;
940
941         default:
942         err_label:
943           SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
944         }
945
946       /* Prepare for the next round.  */
947       now = lr_token (ldfile, charmap, result, NULL, verbose);
948       nowtok = now->tok;
949     }
950
951   /* When we come here we reached the end of the file.  */
952   lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
953 }