Back to index

glibc  2.9
ld-monetary.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995-1999,2000,2001,2002,2005,2007
00002    Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published
00008    by the Free Software Foundation; version 2 of the License, or
00009    (at your option) any later version.
00010 
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015 
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software Foundation,
00018    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
00019 
00020 #ifdef HAVE_CONFIG_H
00021 # include <config.h>
00022 #endif
00023 
00024 #include <byteswap.h>
00025 #include <langinfo.h>
00026 #include <limits.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <sys/uio.h>
00030 
00031 #include <assert.h>
00032 
00033 #include "localedef.h"
00034 #include "linereader.h"
00035 #include "localeinfo.h"
00036 #include "locfile.h"
00037 
00038 
00039 /* The real definition of the struct for the LC_MONETARY locale.  */
00040 struct locale_monetary_t
00041 {
00042   const char *int_curr_symbol;
00043   const char *currency_symbol;
00044   const char *mon_decimal_point;
00045   const char *mon_thousands_sep;
00046   uint32_t mon_decimal_point_wc;
00047   uint32_t mon_thousands_sep_wc;
00048   char *mon_grouping;
00049   size_t mon_grouping_len;
00050   const char *positive_sign;
00051   const char *negative_sign;
00052   signed char int_frac_digits;
00053   signed char frac_digits;
00054   signed char p_cs_precedes;
00055   signed char p_sep_by_space;
00056   signed char n_cs_precedes;
00057   signed char n_sep_by_space;
00058   signed char p_sign_posn;
00059   signed char n_sign_posn;
00060   signed char int_p_cs_precedes;
00061   signed char int_p_sep_by_space;
00062   signed char int_n_cs_precedes;
00063   signed char int_n_sep_by_space;
00064   signed char int_p_sign_posn;
00065   signed char int_n_sign_posn;
00066   const char *duo_int_curr_symbol;
00067   const char *duo_currency_symbol;
00068   signed char duo_int_frac_digits;
00069   signed char duo_frac_digits;
00070   signed char duo_p_cs_precedes;
00071   signed char duo_p_sep_by_space;
00072   signed char duo_n_cs_precedes;
00073   signed char duo_n_sep_by_space;
00074   signed char duo_p_sign_posn;
00075   signed char duo_n_sign_posn;
00076   signed char duo_int_p_cs_precedes;
00077   signed char duo_int_p_sep_by_space;
00078   signed char duo_int_n_cs_precedes;
00079   signed char duo_int_n_sep_by_space;
00080   signed char duo_int_p_sign_posn;
00081   signed char duo_int_n_sign_posn;
00082   uint32_t uno_valid_from;
00083   uint32_t uno_valid_to;
00084   uint32_t duo_valid_from;
00085   uint32_t duo_valid_to;
00086   uint32_t conversion_rate[2];
00087   char *crncystr;
00088 };
00089 
00090 
00091 /* The content iof the field int_curr_symbol has to be taken from
00092    ISO-4217.  We test for correct values.  */
00093 #define DEFINE_INT_CURR(str) str,
00094 static const char *const valid_int_curr[] =
00095   {
00096 #   include "../iso-4217.def"
00097   };
00098 #define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
00099                          / sizeof (valid_int_curr[0])))
00100 #undef DEFINE_INT_CURR
00101 
00102 
00103 /* Prototypes for local functions.  */
00104 static int curr_strcmp (const char *s1, const char **s2);
00105 
00106 
00107 static void
00108 monetary_startup (struct linereader *lr, struct localedef_t *locale,
00109                 int ignore_content)
00110 {
00111   if (!ignore_content)
00112     {
00113       struct locale_monetary_t *monetary;
00114 
00115       locale->categories[LC_MONETARY].monetary = monetary =
00116        (struct locale_monetary_t *) xmalloc (sizeof (*monetary));
00117 
00118       memset (monetary, '\0', sizeof (struct locale_monetary_t));
00119 
00120       monetary->mon_grouping = NULL;
00121       monetary->mon_grouping_len = 0;
00122 
00123       monetary->int_frac_digits = -2;
00124       monetary->frac_digits = -2;
00125       monetary->p_cs_precedes = -2;
00126       monetary->p_sep_by_space = -2;
00127       monetary->n_cs_precedes = -2;
00128       monetary->n_sep_by_space = -2;
00129       monetary->p_sign_posn = -2;
00130       monetary->n_sign_posn = -2;
00131       monetary->int_p_cs_precedes = -2;
00132       monetary->int_p_sep_by_space = -2;
00133       monetary->int_n_cs_precedes = -2;
00134       monetary->int_n_sep_by_space = -2;
00135       monetary->int_p_sign_posn = -2;
00136       monetary->int_n_sign_posn = -2;
00137       monetary->duo_int_frac_digits = -2;
00138       monetary->duo_frac_digits = -2;
00139       monetary->duo_p_cs_precedes = -2;
00140       monetary->duo_p_sep_by_space = -2;
00141       monetary->duo_n_cs_precedes = -2;
00142       monetary->duo_n_sep_by_space = -2;
00143       monetary->duo_p_sign_posn = -2;
00144       monetary->duo_n_sign_posn = -2;
00145       monetary->duo_int_p_cs_precedes = -2;
00146       monetary->duo_int_p_sep_by_space = -2;
00147       monetary->duo_int_n_cs_precedes = -2;
00148       monetary->duo_int_n_sep_by_space = -2;
00149       monetary->duo_int_p_sign_posn = -2;
00150       monetary->duo_int_n_sign_posn = -2;
00151     }
00152 
00153   if (lr != NULL)
00154     {
00155       lr->translate_strings = 1;
00156       lr->return_widestr = 0;
00157     }
00158 }
00159 
00160 
00161 void
00162 monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
00163 {
00164   struct locale_monetary_t *monetary
00165     = locale->categories[LC_MONETARY].monetary;
00166   int nothing = 0;
00167 
00168   /* Now resolve copying and also handle completely missing definitions.  */
00169   if (monetary == NULL)
00170     {
00171       /* First see whether we were supposed to copy.  If yes, find the
00172         actual definition.  */
00173       if (locale->copy_name[LC_MONETARY] != NULL)
00174        {
00175          /* Find the copying locale.  This has to happen transitively since
00176             the locale we are copying from might also copying another one.  */
00177          struct localedef_t *from = locale;
00178 
00179          do
00180            from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
00181                             from->repertoire_name, charmap);
00182          while (from->categories[LC_MONETARY].monetary == NULL
00183                && from->copy_name[LC_MONETARY] != NULL);
00184 
00185          monetary = locale->categories[LC_MONETARY].monetary
00186            = from->categories[LC_MONETARY].monetary;
00187        }
00188 
00189       /* If there is still no definition issue an warning and create an
00190         empty one.  */
00191       if (monetary == NULL)
00192        {
00193          if (! be_quiet)
00194            WITH_CUR_LOCALE (error (0, 0, _("\
00195 No definition for %s category found"), "LC_MONETARY"));
00196          monetary_startup (NULL, locale, 0);
00197          monetary = locale->categories[LC_MONETARY].monetary;
00198          nothing = 1;
00199        }
00200     }
00201 
00202 #define TEST_ELEM(cat, initval) \
00203   if (monetary->cat == NULL)                                                \
00204     {                                                                \
00205       if (! be_quiet && ! nothing)                                   \
00206        WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),       \
00207                             "LC_MONETARY", #cat));                          \
00208       monetary->cat = initval;                                              \
00209     }
00210 
00211   TEST_ELEM (int_curr_symbol, "");
00212   TEST_ELEM (currency_symbol, "");
00213   TEST_ELEM (mon_decimal_point, ".");
00214   TEST_ELEM (mon_thousands_sep, "");
00215   TEST_ELEM (positive_sign, "");
00216   TEST_ELEM (negative_sign, "");
00217 
00218   /* The international currency symbol must come from ISO 4217.  */
00219   if (monetary->int_curr_symbol != NULL)
00220     {
00221       if (strlen (monetary->int_curr_symbol) != 4)
00222        {
00223          if (! be_quiet && ! nothing)
00224            WITH_CUR_LOCALE (error (0, 0, _("\
00225 %s: value of field `int_curr_symbol' has wrong length"),
00226                                 "LC_MONETARY"));
00227        }
00228       else
00229        { /* Check the first three characters against ISO 4217 */
00230          char symbol[4];
00231          strncpy (symbol, monetary->int_curr_symbol, 3);
00232          symbol[3] = '\0';
00233          if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
00234                      sizeof (const char *),
00235                      (comparison_fn_t) curr_strcmp) == NULL
00236               && !be_quiet)
00237            WITH_CUR_LOCALE (error (0, 0, _("\
00238 %s: value of field `int_curr_symbol' does \
00239 not correspond to a valid name in ISO 4217"),
00240                             "LC_MONETARY"));
00241        }
00242     }
00243 
00244   /* The decimal point must not be empty.  This is not said explicitly
00245      in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
00246      != "".  */
00247   if (monetary->mon_decimal_point == NULL)
00248     {
00249       if (! be_quiet && ! nothing)
00250        WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
00251                             "LC_MONETARY", "mon_decimal_point"));
00252       monetary->mon_decimal_point = ".";
00253     }
00254   else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
00255     {
00256       WITH_CUR_LOCALE (error (0, 0, _("\
00257 %s: value for field `%s' must not be an empty string"),
00258                            "LC_MONETARY", "mon_decimal_point"));
00259     }
00260   if (monetary->mon_decimal_point_wc == L'\0')
00261     monetary->mon_decimal_point_wc = L'.';
00262 
00263   if (monetary->mon_grouping_len == 0)
00264     {
00265       if (! be_quiet && ! nothing)
00266        WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),
00267                             "LC_MONETARY", "mon_grouping"));
00268 
00269       monetary->mon_grouping = (char *) "\177";
00270       monetary->mon_grouping_len = 1;
00271     }
00272 
00273 #undef TEST_ELEM
00274 #define TEST_ELEM(cat, min, max, initval) \
00275   if (monetary->cat == -2)                                           \
00276     {                                                                \
00277        if (! be_quiet && ! nothing)                                         \
00278         WITH_CUR_LOCALE (error (0, 0, _("%s: field `%s' not defined"),             \
00279                              "LC_MONETARY", #cat));                         \
00280        monetary->cat = initval;                                             \
00281     }                                                                \
00282   else if ((monetary->cat < min || monetary->cat > max)                     \
00283           && min < max                                                      \
00284           && !be_quiet && !nothing)                                         \
00285     WITH_CUR_LOCALE (error (0, 0, _("\
00286 %s: value for field `%s' must be in range %d...%d"),                        \
00287                          "LC_MONETARY", #cat, min, max))
00288 
00289   TEST_ELEM (int_frac_digits, 1, 0, -1);
00290   TEST_ELEM (frac_digits, 1, 0, -1);
00291   TEST_ELEM (p_cs_precedes, -1, 1, -1);
00292   TEST_ELEM (p_sep_by_space, -1, 2, -1);
00293   TEST_ELEM (n_cs_precedes, -1, 1, -1);
00294   TEST_ELEM (n_sep_by_space, -1, 2, -1);
00295   TEST_ELEM (p_sign_posn, -1, 4, -1);
00296   TEST_ELEM (n_sign_posn, -1, 4, -1);
00297 
00298   /* The non-POSIX.2 extensions are optional.  */
00299   if (monetary->duo_int_curr_symbol == NULL)
00300     monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
00301   if (monetary->duo_currency_symbol == NULL)
00302     monetary->duo_currency_symbol = monetary->currency_symbol;
00303 
00304   if (monetary->duo_int_frac_digits == -2)
00305     monetary->duo_int_frac_digits = monetary->int_frac_digits;
00306   if (monetary->duo_frac_digits == -2)
00307     monetary->duo_frac_digits = monetary->frac_digits;
00308 
00309 #undef TEST_ELEM
00310 #define TEST_ELEM(cat, alt, min, max) \
00311   if (monetary->cat == -2)                                           \
00312     monetary->cat = monetary->alt;                                   \
00313   else if ((monetary->cat < min || monetary->cat > max) && !be_quiet        \
00314           && ! nothing)                                              \
00315     WITH_CUR_LOCALE (error (0, 0, _("\
00316 %s: value for field `%s' must be in range %d...%d"),                        \
00317                          "LC_MONETARY", #cat, min, max))
00318 
00319   TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
00320   TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
00321   TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
00322   TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
00323   TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
00324   TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
00325 
00326   TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
00327   TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
00328   TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
00329   TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
00330   TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
00331   TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
00332   TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
00333   TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
00334   TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
00335   TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
00336   TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
00337   TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
00338 
00339   if (monetary->uno_valid_from == 0)
00340     monetary->uno_valid_from = 10101;
00341   if (monetary->uno_valid_to == 0)
00342     monetary->uno_valid_to = 99991231;
00343   if (monetary->duo_valid_from == 0)
00344     monetary->duo_valid_from = 10101;
00345   if (monetary->duo_valid_to == 0)
00346     monetary->duo_valid_to = 99991231;
00347 
00348   if (monetary->conversion_rate[0] == 0)
00349     {
00350       monetary->conversion_rate[0] = 1;
00351       monetary->conversion_rate[1] = 1;
00352     }
00353 
00354   /* Create the crncystr entry.  */
00355   monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
00356                                     + 2);
00357   monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
00358   strcpy (&monetary->crncystr[1], monetary->currency_symbol);
00359 }
00360 
00361 
00362 void
00363 monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
00364                const char *output_path)
00365 {
00366   struct locale_monetary_t *monetary
00367     = locale->categories[LC_MONETARY].monetary;
00368   struct iovec iov[3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
00369   struct locale_file data;
00370   uint32_t idx[_NL_ITEM_INDEX (_NL_NUM_LC_MONETARY)];
00371   size_t cnt = 0;
00372 
00373   data.magic = LIMAGIC (LC_MONETARY);
00374   data.n = _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY);
00375   iov[cnt].iov_base = (void *) &data;
00376   iov[cnt].iov_len = sizeof (data);
00377   ++cnt;
00378 
00379   iov[cnt].iov_base = (void *) idx;
00380   iov[cnt].iov_len = sizeof (idx);
00381   ++cnt;
00382 
00383   idx[cnt - 2] = iov[0].iov_len + iov[1].iov_len;
00384   iov[cnt].iov_base = (void *) monetary->int_curr_symbol;
00385   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00386   ++cnt;
00387 
00388   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00389   iov[cnt].iov_base = (void *) monetary->currency_symbol;
00390   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00391   ++cnt;
00392 
00393   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00394   iov[cnt].iov_base = (void *) monetary->mon_decimal_point;
00395   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00396   ++cnt;
00397 
00398   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00399   iov[cnt].iov_base = (void *) monetary->mon_thousands_sep;
00400   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00401   ++cnt;
00402 
00403   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00404   iov[cnt].iov_base = monetary->mon_grouping;
00405   iov[cnt].iov_len = monetary->mon_grouping_len;
00406   ++cnt;
00407 
00408   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00409   iov[cnt].iov_base = (void *) monetary->positive_sign;
00410   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00411   ++cnt;
00412 
00413   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00414   iov[cnt].iov_base = (void *) monetary->negative_sign;
00415   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00416   ++cnt;
00417 
00418   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00419   iov[cnt].iov_base = (void *) &monetary->int_frac_digits;
00420   iov[cnt].iov_len = 1;
00421   ++cnt;
00422 
00423   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00424   iov[cnt].iov_base = (void *) &monetary->frac_digits;
00425   iov[cnt].iov_len = 1;
00426   ++cnt;
00427 
00428   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00429   iov[cnt].iov_base = (void *) &monetary->p_cs_precedes;
00430   iov[cnt].iov_len = 1;
00431   ++cnt;
00432 
00433   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00434   iov[cnt].iov_base = (void *) &monetary->p_sep_by_space;
00435   iov[cnt].iov_len = 1;
00436   ++cnt;
00437 
00438   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00439   iov[cnt].iov_base = (void *) &monetary->n_cs_precedes;
00440   iov[cnt].iov_len = 1;
00441   ++cnt;
00442 
00443   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00444   iov[cnt].iov_base = (void *) &monetary->n_sep_by_space;
00445   iov[cnt].iov_len = 1;
00446   ++cnt;
00447 
00448   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00449   iov[cnt].iov_base = (void *) &monetary->p_sign_posn;
00450   iov[cnt].iov_len = 1;
00451   ++cnt;
00452 
00453   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00454   iov[cnt].iov_base = (void *) &monetary->n_sign_posn;
00455   iov[cnt].iov_len = 1;
00456   ++cnt;
00457 
00458   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00459   iov[cnt].iov_base = (void *) monetary->crncystr;
00460   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00461   ++cnt;
00462 
00463   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00464   iov[cnt].iov_base = (void *) &monetary->int_p_cs_precedes;
00465   iov[cnt].iov_len = 1;
00466   ++cnt;
00467 
00468   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00469   iov[cnt].iov_base = (void *) &monetary->int_p_sep_by_space;
00470   iov[cnt].iov_len = 1;
00471   ++cnt;
00472 
00473   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00474   iov[cnt].iov_base = (void *) &monetary->int_n_cs_precedes;
00475   iov[cnt].iov_len = 1;
00476   ++cnt;
00477 
00478   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00479   iov[cnt].iov_base = (void *) &monetary->int_n_sep_by_space;
00480   iov[cnt].iov_len = 1;
00481   ++cnt;
00482 
00483   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00484   iov[cnt].iov_base = (void *) &monetary->int_p_sign_posn;
00485   iov[cnt].iov_len = 1;
00486   ++cnt;
00487 
00488   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00489   iov[cnt].iov_base = (void *) &monetary->int_n_sign_posn;
00490   iov[cnt].iov_len = 1;
00491   ++cnt;
00492 
00493   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00494   iov[cnt].iov_base = (void *) monetary->duo_int_curr_symbol;
00495   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00496   ++cnt;
00497 
00498   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00499   iov[cnt].iov_base = (void *) monetary->duo_currency_symbol;
00500   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00501   ++cnt;
00502 
00503   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00504   iov[cnt].iov_base = (void *) &monetary->duo_int_frac_digits;
00505   iov[cnt].iov_len = 1;
00506   ++cnt;
00507 
00508   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00509   iov[cnt].iov_base = (void *) &monetary->duo_frac_digits;
00510   iov[cnt].iov_len = 1;
00511   ++cnt;
00512 
00513   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00514   iov[cnt].iov_base = (void *) &monetary->duo_p_cs_precedes;
00515   iov[cnt].iov_len = 1;
00516   ++cnt;
00517 
00518   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00519   iov[cnt].iov_base = (void *) &monetary->duo_p_sep_by_space;
00520   iov[cnt].iov_len = 1;
00521   ++cnt;
00522 
00523   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00524   iov[cnt].iov_base = (void *) &monetary->duo_n_cs_precedes;
00525   iov[cnt].iov_len = 1;
00526   ++cnt;
00527 
00528   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00529   iov[cnt].iov_base = (void *) &monetary->duo_n_sep_by_space;
00530   iov[cnt].iov_len = 1;
00531   ++cnt;
00532 
00533   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00534   iov[cnt].iov_base = (void *) &monetary->duo_int_p_cs_precedes;
00535   iov[cnt].iov_len = 1;
00536   ++cnt;
00537 
00538   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00539   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sep_by_space;
00540   iov[cnt].iov_len = 1;
00541   ++cnt;
00542 
00543   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00544   iov[cnt].iov_base = (void *) &monetary->duo_int_n_cs_precedes;
00545   iov[cnt].iov_len = 1;
00546   ++cnt;
00547 
00548   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00549   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sep_by_space;
00550   iov[cnt].iov_len = 1;
00551   ++cnt;
00552 
00553   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00554   iov[cnt].iov_base = (void *) &monetary->duo_p_sign_posn;
00555   iov[cnt].iov_len = 1;
00556   ++cnt;
00557 
00558   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00559   iov[cnt].iov_base = (void *) &monetary->duo_n_sign_posn;
00560   iov[cnt].iov_len = 1;
00561   ++cnt;
00562 
00563   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00564   iov[cnt].iov_base = (void *) &monetary->duo_int_p_sign_posn;
00565   iov[cnt].iov_len = 1;
00566   ++cnt;
00567 
00568   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00569   iov[cnt].iov_base = (void *) &monetary->duo_int_n_sign_posn;
00570   iov[cnt].iov_len = 1;
00571   ++cnt;
00572 
00573   idx[cnt - 2] = idx[cnt - 3] + iov[cnt - 1].iov_len;
00574 
00575   /* Align following data */
00576   iov[cnt].iov_base = (void *) "\0\0";
00577   iov[cnt].iov_len = ((idx[cnt - 2] + 3) & ~3) - idx[cnt - 2];
00578   idx[cnt - 2] = (idx[cnt - 2] + 3) & ~3;
00579   ++cnt;
00580 
00581   iov[cnt].iov_base = (void *) &monetary->uno_valid_from;
00582   iov[cnt].iov_len = sizeof(uint32_t);
00583   ++cnt;
00584 
00585   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00586   iov[cnt].iov_base = (void *) &monetary->uno_valid_to;
00587   iov[cnt].iov_len = sizeof(uint32_t);
00588   ++cnt;
00589 
00590   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00591   iov[cnt].iov_base = (void *) &monetary->duo_valid_from;
00592   iov[cnt].iov_len = sizeof(uint32_t);
00593   ++cnt;
00594 
00595   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00596   iov[cnt].iov_base = (void *) &monetary->duo_valid_to;
00597   iov[cnt].iov_len = sizeof(uint32_t);
00598   ++cnt;
00599 
00600   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00601   iov[cnt].iov_base = (void *) monetary->conversion_rate;
00602   iov[cnt].iov_len = 2 * sizeof(uint32_t);
00603   ++cnt;
00604 
00605   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00606   iov[cnt].iov_base = (void *) &monetary->mon_decimal_point_wc;
00607   iov[cnt].iov_len = sizeof (uint32_t);
00608   ++cnt;
00609 
00610   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00611   iov[cnt].iov_base = (void *) &monetary->mon_thousands_sep_wc;
00612   iov[cnt].iov_len = sizeof (uint32_t);
00613   ++cnt;
00614 
00615   idx[cnt - 3] = idx[cnt - 4] + iov[cnt - 1].iov_len;
00616   iov[cnt].iov_base = (void *) charmap->code_set_name;
00617   iov[cnt].iov_len = strlen (iov[cnt].iov_base) + 1;
00618   ++cnt;
00619 
00620   assert (cnt == 3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
00621 
00622   write_locale_data (output_path, LC_MONETARY, "LC_MONETARY",
00623                    3 + _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY), iov);
00624 }
00625 
00626 
00627 static int
00628 curr_strcmp (const char *s1, const char **s2)
00629 {
00630   return strcmp (s1, *s2);
00631 }
00632 
00633 
00634 /* The parser for the LC_MONETARY section of the locale definition.  */
00635 void
00636 monetary_read (struct linereader *ldfile, struct localedef_t *result,
00637               const struct charmap_t *charmap, const char *repertoire_name,
00638               int ignore_content)
00639 {
00640   struct repertoire_t *repertoire = NULL;
00641   struct locale_monetary_t *monetary;
00642   struct token *now;
00643   enum token_t nowtok;
00644 
00645   /* Get the repertoire we have to use.  */
00646   if (repertoire_name != NULL)
00647     repertoire = repertoire_read (repertoire_name);
00648 
00649   /* The rest of the line containing `LC_MONETARY' must be free.  */
00650   lr_ignore_rest (ldfile, 1);
00651 
00652   do
00653     {
00654       now = lr_token (ldfile, charmap, result, NULL, verbose);
00655       nowtok = now->tok;
00656     }
00657   while (nowtok == tok_eol);
00658 
00659   /* If we see `copy' now we are almost done.  */
00660   if (nowtok == tok_copy)
00661     {
00662       handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
00663                  LC_MONETARY, "LC_MONETARY", ignore_content);
00664       return;
00665     }
00666 
00667   /* Prepare the data structures.  */
00668   monetary_startup (ldfile, result, ignore_content);
00669   monetary = result->categories[LC_MONETARY].monetary;
00670 
00671   while (1)
00672     {
00673       /* Of course we don't proceed beyond the end of file.  */
00674       if (nowtok == tok_eof)
00675        break;
00676 
00677       /* Ignore empty lines.  */
00678       if (nowtok == tok_eol)
00679        {
00680          now = lr_token (ldfile, charmap, result, NULL, verbose);
00681          nowtok = now->tok;
00682          continue;
00683        }
00684 
00685       switch (nowtok)
00686        {
00687 #define STR_ELEM(cat) \
00688        case tok_##cat:                                                      \
00689          /* Ignore the rest of the line if we don't need the input of       \
00690             this line.  */                                           \
00691          if (ignore_content)                                                \
00692            {                                                         \
00693              lr_ignore_rest (ldfile, 0);                             \
00694              break;                                                  \
00695            }                                                         \
00696                                                                      \
00697          now = lr_token (ldfile, charmap, result, NULL, verbose);           \
00698          if (now->tok != tok_string)                                        \
00699            goto err_label;                                           \
00700          else if (monetary->cat != NULL)                             \
00701            lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
00702                     "LC_MONETARY", #cat);                            \
00703          else if (!ignore_content && now->val.str.startmb == NULL)          \
00704            {                                                         \
00705              lr_error (ldfile, _("\
00706 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                \
00707              monetary->cat = "";                                     \
00708            }                                                         \
00709          else if (!ignore_content)                                   \
00710            monetary->cat = now->val.str.startmb;                     \
00711          lr_ignore_rest (ldfile, 1);                                        \
00712          break
00713 
00714          STR_ELEM (int_curr_symbol);
00715          STR_ELEM (currency_symbol);
00716          STR_ELEM (positive_sign);
00717          STR_ELEM (negative_sign);
00718          STR_ELEM (duo_int_curr_symbol);
00719          STR_ELEM (duo_currency_symbol);
00720 
00721 #define STR_ELEM_WC(cat) \
00722        case tok_##cat:                                                      \
00723          /* Ignore the rest of the line if we don't need the input of       \
00724             this line.  */                                           \
00725          if (ignore_content)                                                \
00726            {                                                         \
00727              lr_ignore_rest (ldfile, 0);                             \
00728              break;                                                  \
00729            }                                                         \
00730                                                                      \
00731          ldfile->return_widestr = 1;                                        \
00732          now = lr_token (ldfile, charmap, result, repertoire, verbose);      \
00733          if (now->tok != tok_string)                                        \
00734            goto err_label;                                           \
00735          if (monetary->cat != NULL)                                         \
00736            lr_error (ldfile, _("\
00737 %s: field `%s' declared more than once"), "LC_MONETARY", #cat);                    \
00738          else if (!ignore_content && now->val.str.startmb == NULL)          \
00739            {                                                         \
00740              lr_error (ldfile, _("\
00741 %s: unknown character in field `%s'"), "LC_MONETARY", #cat);                \
00742              monetary->cat = "";                                     \
00743              monetary->cat##_wc = L'\0';                             \
00744            }                                                         \
00745          else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2)    \
00746            {                                                         \
00747              lr_error (ldfile, _("\
00748 %s: value for field `%s' must be a single character"), "LC_MONETARY", #cat);  \
00749            }                                                         \
00750          else if (!ignore_content)                                   \
00751            {                                                         \
00752              monetary->cat = now->val.str.startmb;                          \
00753                                                                      \
00754              if (now->val.str.startwc != NULL)                              \
00755               monetary->cat##_wc = *now->val.str.startwc;                   \
00756            }                                                         \
00757          ldfile->return_widestr = 0;                                        \
00758          break
00759 
00760          STR_ELEM_WC (mon_decimal_point);
00761          STR_ELEM_WC (mon_thousands_sep);
00762 
00763 #define INT_ELEM(cat) \
00764        case tok_##cat:                                                      \
00765          /* Ignore the rest of the line if we don't need the input of       \
00766             this line.  */                                           \
00767          if (ignore_content)                                                \
00768            {                                                         \
00769              lr_ignore_rest (ldfile, 0);                             \
00770              break;                                                  \
00771            }                                                         \
00772                                                                      \
00773          now = lr_token (ldfile, charmap, result, NULL, verbose);           \
00774          if (now->tok != tok_minus1 && now->tok != tok_number)              \
00775            goto err_label;                                           \
00776          else if (monetary->cat != -2)                                      \
00777            lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
00778                     "LC_MONETARY", #cat);                            \
00779          else if (!ignore_content)                                   \
00780            monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num;             \
00781          break
00782 
00783          INT_ELEM (int_frac_digits);
00784          INT_ELEM (frac_digits);
00785          INT_ELEM (p_cs_precedes);
00786          INT_ELEM (p_sep_by_space);
00787          INT_ELEM (n_cs_precedes);
00788          INT_ELEM (n_sep_by_space);
00789          INT_ELEM (p_sign_posn);
00790          INT_ELEM (n_sign_posn);
00791          INT_ELEM (int_p_cs_precedes);
00792          INT_ELEM (int_p_sep_by_space);
00793          INT_ELEM (int_n_cs_precedes);
00794          INT_ELEM (int_n_sep_by_space);
00795          INT_ELEM (int_p_sign_posn);
00796          INT_ELEM (int_n_sign_posn);
00797          INT_ELEM (duo_int_frac_digits);
00798          INT_ELEM (duo_frac_digits);
00799          INT_ELEM (duo_p_cs_precedes);
00800          INT_ELEM (duo_p_sep_by_space);
00801          INT_ELEM (duo_n_cs_precedes);
00802          INT_ELEM (duo_n_sep_by_space);
00803          INT_ELEM (duo_p_sign_posn);
00804          INT_ELEM (duo_n_sign_posn);
00805          INT_ELEM (duo_int_p_cs_precedes);
00806          INT_ELEM (duo_int_p_sep_by_space);
00807          INT_ELEM (duo_int_n_cs_precedes);
00808          INT_ELEM (duo_int_n_sep_by_space);
00809          INT_ELEM (duo_int_p_sign_posn);
00810          INT_ELEM (duo_int_n_sign_posn);
00811          INT_ELEM (uno_valid_from);
00812          INT_ELEM (uno_valid_to);
00813          INT_ELEM (duo_valid_from);
00814          INT_ELEM (duo_valid_to);
00815 
00816        case tok_mon_grouping:
00817          /* Ignore the rest of the line if we don't need the input of
00818             this line.  */
00819          if (ignore_content)
00820            {
00821              lr_ignore_rest (ldfile, 0);
00822              break;
00823            }
00824 
00825          now = lr_token (ldfile, charmap, result, NULL, verbose);
00826          if (now->tok != tok_minus1 && now->tok != tok_number)
00827            goto err_label;
00828          else
00829            {
00830              size_t act = 0;
00831              size_t max = 10;
00832              char *grouping = ignore_content ? NULL : xmalloc (max);
00833 
00834              do
00835               {
00836                 if (act + 1 >= max)
00837                   {
00838                     max *= 2;
00839                     grouping = xrealloc (grouping, max);
00840                   }
00841 
00842                 if (act > 0 && grouping[act - 1] == '\177')
00843                   {
00844                     lr_error (ldfile, _("\
00845 %s: `-1' must be last entry in `%s' field"),
00846                             "LC_MONETARY", "mon_grouping");
00847                     lr_ignore_rest (ldfile, 0);
00848                     break;
00849                   }
00850 
00851                 if (now->tok == tok_minus1)
00852                   {
00853                     if (!ignore_content)
00854                      grouping[act++] = '\177';
00855                   }
00856                 else if (now->val.num == 0)
00857                   {
00858                     /* A value of 0 disables grouping from here on but
00859                       we must not store a NUL character since this
00860                       terminates the string.  Use something different
00861                       which must not be used otherwise.  */
00862                     if (!ignore_content)
00863                      grouping[act++] = '\377';
00864                   }
00865                 else if (now->val.num > 126)
00866                   lr_error (ldfile, _("\
00867 %s: values for field `%s' must be smaller than 127"),
00868                            "LC_MONETARY", "mon_grouping");
00869                 else if (!ignore_content)
00870                   grouping[act++] = now->val.num;
00871 
00872                 /* Next must be semicolon.  */
00873                 now = lr_token (ldfile, charmap, result, NULL, verbose);
00874                 if (now->tok != tok_semicolon)
00875                   break;
00876 
00877                 now = lr_token (ldfile, charmap, result, NULL, verbose);
00878               }
00879              while (now->tok == tok_minus1 || now->tok == tok_number);
00880 
00881              if (now->tok != tok_eol)
00882               goto err_label;
00883 
00884              if (!ignore_content)
00885               {
00886                 grouping[act++] = '\0';
00887 
00888                 monetary->mon_grouping = xrealloc (grouping, act);
00889                 monetary->mon_grouping_len = act;
00890               }
00891            }
00892          break;
00893 
00894        case tok_conversion_rate:
00895          /* Ignore the rest of the line if we don't need the input of
00896             this line.  */
00897          if (ignore_content)
00898            {
00899              lr_ignore_rest (ldfile, 0);
00900              break;
00901            }
00902 
00903          now = lr_token (ldfile, charmap, result, NULL, verbose);
00904          if (now->tok != tok_number)
00905            goto err_label;
00906          if (now->val.num == 0)
00907            {
00908            invalid_conversion_rate:
00909              lr_error (ldfile, _("conversion rate value cannot be zero"));
00910              if (!ignore_content)
00911               {
00912                 monetary->conversion_rate[0] = 1;
00913                 monetary->conversion_rate[1] = 1;
00914               }
00915              break;
00916            }
00917          if (!ignore_content)
00918            monetary->conversion_rate[0] = now->val.num;
00919          /* Next must be a semicolon.  */
00920          now = lr_token (ldfile, charmap, result, NULL, verbose);
00921          if (now->tok != tok_semicolon)
00922            goto err_label;
00923          /* And another number.  */
00924          now = lr_token (ldfile, charmap, result, NULL, verbose);
00925          if (now->tok != tok_number)
00926            goto err_label;
00927          if (now->val.num == 0)
00928            goto invalid_conversion_rate;
00929          if (!ignore_content)
00930            monetary->conversion_rate[1] = now->val.num;
00931          /* The rest of the line must be empty.  */
00932          lr_ignore_rest (ldfile, 1);
00933          break;
00934 
00935        case tok_end:
00936          /* Next we assume `LC_MONETARY'.  */
00937          now = lr_token (ldfile, charmap, result, NULL, verbose);
00938          if (now->tok == tok_eof)
00939            break;
00940          if (now->tok == tok_eol)
00941            lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
00942          else if (now->tok != tok_lc_monetary)
00943            lr_error (ldfile, _("\
00944 %1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
00945          lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
00946          return;
00947 
00948        default:
00949        err_label:
00950          SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
00951        }
00952 
00953       /* Prepare for the next round.  */
00954       now = lr_token (ldfile, charmap, result, NULL, verbose);
00955       nowtok = now->tok;
00956     }
00957 
00958   /* When we come here we reached the end of the file.  */
00959   lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
00960 }