Blame locale/programs/ld-monetary.c

Packit 6c4009
/* Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@gnu.org>, 1995.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
# include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <byteswap.h>
Packit 6c4009
#include <langinfo.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <sys/uio.h>
Packit 6c4009
Packit 6c4009
#include <assert.h>
Packit 6c4009
Packit 6c4009
#include "localedef.h"
Packit 6c4009
#include "linereader.h"
Packit 6c4009
#include "localeinfo.h"
Packit 6c4009
#include "locfile.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The real definition of the struct for the LC_MONETARY locale.  */
Packit 6c4009
struct locale_monetary_t
Packit 6c4009
{
Packit 6c4009
  const char *int_curr_symbol;
Packit 6c4009
  const char *currency_symbol;
Packit 6c4009
  const char *mon_decimal_point;
Packit 6c4009
  const char *mon_thousands_sep;
Packit 6c4009
  uint32_t mon_decimal_point_wc;
Packit 6c4009
  uint32_t mon_thousands_sep_wc;
Packit 6c4009
  char *mon_grouping;
Packit 6c4009
  size_t mon_grouping_len;
Packit 6c4009
  const char *positive_sign;
Packit 6c4009
  const char *negative_sign;
Packit 6c4009
  signed char int_frac_digits;
Packit 6c4009
  signed char frac_digits;
Packit 6c4009
  signed char p_cs_precedes;
Packit 6c4009
  signed char p_sep_by_space;
Packit 6c4009
  signed char n_cs_precedes;
Packit 6c4009
  signed char n_sep_by_space;
Packit 6c4009
  signed char p_sign_posn;
Packit 6c4009
  signed char n_sign_posn;
Packit 6c4009
  signed char int_p_cs_precedes;
Packit 6c4009
  signed char int_p_sep_by_space;
Packit 6c4009
  signed char int_n_cs_precedes;
Packit 6c4009
  signed char int_n_sep_by_space;
Packit 6c4009
  signed char int_p_sign_posn;
Packit 6c4009
  signed char int_n_sign_posn;
Packit 6c4009
  const char *duo_int_curr_symbol;
Packit 6c4009
  const char *duo_currency_symbol;
Packit 6c4009
  signed char duo_int_frac_digits;
Packit 6c4009
  signed char duo_frac_digits;
Packit 6c4009
  signed char duo_p_cs_precedes;
Packit 6c4009
  signed char duo_p_sep_by_space;
Packit 6c4009
  signed char duo_n_cs_precedes;
Packit 6c4009
  signed char duo_n_sep_by_space;
Packit 6c4009
  signed char duo_p_sign_posn;
Packit 6c4009
  signed char duo_n_sign_posn;
Packit 6c4009
  signed char duo_int_p_cs_precedes;
Packit 6c4009
  signed char duo_int_p_sep_by_space;
Packit 6c4009
  signed char duo_int_n_cs_precedes;
Packit 6c4009
  signed char duo_int_n_sep_by_space;
Packit 6c4009
  signed char duo_int_p_sign_posn;
Packit 6c4009
  signed char duo_int_n_sign_posn;
Packit 6c4009
  uint32_t uno_valid_from;
Packit 6c4009
  uint32_t uno_valid_to;
Packit 6c4009
  uint32_t duo_valid_from;
Packit 6c4009
  uint32_t duo_valid_to;
Packit 6c4009
  uint32_t conversion_rate[2];
Packit 6c4009
  char *crncystr;
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The content iof the field int_curr_symbol has to be taken from
Packit 6c4009
   ISO-4217.  We test for correct values.  */
Packit 6c4009
#define DEFINE_INT_CURR(str) str,
Packit 6c4009
static const char *const valid_int_curr[] =
Packit 6c4009
  {
Packit 6c4009
#   include "../iso-4217.def"
Packit 6c4009
  };
Packit 6c4009
#define NR_VALID_INT_CURR ((sizeof (valid_int_curr) \
Packit 6c4009
			    / sizeof (valid_int_curr[0])))
Packit 6c4009
#undef DEFINE_INT_CURR
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Prototypes for local functions.  */
Packit 6c4009
static int curr_strcmp (const char *s1, const char **s2);
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
monetary_startup (struct linereader *lr, struct localedef_t *locale,
Packit 6c4009
		  int ignore_content)
Packit 6c4009
{
Packit 6c4009
  if (!ignore_content)
Packit 6c4009
    {
Packit 6c4009
      struct locale_monetary_t *monetary;
Packit 6c4009
Packit 6c4009
      locale->categories[LC_MONETARY].monetary = monetary =
Packit 6c4009
	(struct locale_monetary_t *) xmalloc (sizeof (*monetary));
Packit 6c4009
Packit 6c4009
      memset (monetary, '\0', sizeof (struct locale_monetary_t));
Packit 6c4009
Packit 6c4009
      monetary->mon_grouping = NULL;
Packit 6c4009
      monetary->mon_grouping_len = 0;
Packit 6c4009
Packit 6c4009
      monetary->int_frac_digits = -2;
Packit 6c4009
      monetary->frac_digits = -2;
Packit 6c4009
      monetary->p_cs_precedes = -2;
Packit 6c4009
      monetary->p_sep_by_space = -2;
Packit 6c4009
      monetary->n_cs_precedes = -2;
Packit 6c4009
      monetary->n_sep_by_space = -2;
Packit 6c4009
      monetary->p_sign_posn = -2;
Packit 6c4009
      monetary->n_sign_posn = -2;
Packit 6c4009
      monetary->int_p_cs_precedes = -2;
Packit 6c4009
      monetary->int_p_sep_by_space = -2;
Packit 6c4009
      monetary->int_n_cs_precedes = -2;
Packit 6c4009
      monetary->int_n_sep_by_space = -2;
Packit 6c4009
      monetary->int_p_sign_posn = -2;
Packit 6c4009
      monetary->int_n_sign_posn = -2;
Packit 6c4009
      monetary->duo_int_frac_digits = -2;
Packit 6c4009
      monetary->duo_frac_digits = -2;
Packit 6c4009
      monetary->duo_p_cs_precedes = -2;
Packit 6c4009
      monetary->duo_p_sep_by_space = -2;
Packit 6c4009
      monetary->duo_n_cs_precedes = -2;
Packit 6c4009
      monetary->duo_n_sep_by_space = -2;
Packit 6c4009
      monetary->duo_p_sign_posn = -2;
Packit 6c4009
      monetary->duo_n_sign_posn = -2;
Packit 6c4009
      monetary->duo_int_p_cs_precedes = -2;
Packit 6c4009
      monetary->duo_int_p_sep_by_space = -2;
Packit 6c4009
      monetary->duo_int_n_cs_precedes = -2;
Packit 6c4009
      monetary->duo_int_n_sep_by_space = -2;
Packit 6c4009
      monetary->duo_int_p_sign_posn = -2;
Packit 6c4009
      monetary->duo_int_n_sign_posn = -2;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (lr != NULL)
Packit 6c4009
    {
Packit 6c4009
      lr->translate_strings = 1;
Packit 6c4009
      lr->return_widestr = 0;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
monetary_finish (struct localedef_t *locale, const struct charmap_t *charmap)
Packit 6c4009
{
Packit 6c4009
  struct locale_monetary_t *monetary
Packit 6c4009
    = locale->categories[LC_MONETARY].monetary;
Packit 6c4009
  int nothing = 0;
Packit 6c4009
Packit 6c4009
  /* Now resolve copying and also handle completely missing definitions.  */
Packit 6c4009
  if (monetary == NULL)
Packit 6c4009
    {
Packit 6c4009
      /* First see whether we were supposed to copy.  If yes, find the
Packit 6c4009
	 actual definition.  */
Packit 6c4009
      if (locale->copy_name[LC_MONETARY] != NULL)
Packit 6c4009
	{
Packit 6c4009
	  /* Find the copying locale.  This has to happen transitively since
Packit 6c4009
	     the locale we are copying from might also copying another one.  */
Packit 6c4009
	  struct localedef_t *from = locale;
Packit 6c4009
Packit 6c4009
	  do
Packit 6c4009
	    from = find_locale (LC_MONETARY, from->copy_name[LC_MONETARY],
Packit 6c4009
				from->repertoire_name, charmap);
Packit 6c4009
	  while (from->categories[LC_MONETARY].monetary == NULL
Packit 6c4009
		 && from->copy_name[LC_MONETARY] != NULL);
Packit 6c4009
Packit 6c4009
	  monetary = locale->categories[LC_MONETARY].monetary
Packit 6c4009
	    = from->categories[LC_MONETARY].monetary;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If there is still no definition issue a warning and create an
Packit 6c4009
	 empty one.  */
Packit 6c4009
      if (monetary == NULL)
Packit 6c4009
	{
Packit 6c4009
	  record_warning (_("\
Packit 6c4009
No definition for %s category found"), "LC_MONETARY");
Packit 6c4009
	  monetary_startup (NULL, locale, 0);
Packit 6c4009
	  monetary = locale->categories[LC_MONETARY].monetary;
Packit 6c4009
	  nothing = 1;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#define TEST_ELEM(cat, initval) \
Packit 6c4009
  if (monetary->cat == NULL)						      \
Packit 6c4009
    {									      \
Packit 6c4009
      if (! nothing)							      \
Packit 6c4009
	record_error (0, 0, _("%s: field `%s' not defined"),		      \
Packit 6c4009
		      "LC_MONETARY", #cat);				      \
Packit 6c4009
      monetary->cat = initval;						      \
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  TEST_ELEM (int_curr_symbol, "");
Packit 6c4009
  TEST_ELEM (currency_symbol, "");
Packit 6c4009
  TEST_ELEM (mon_decimal_point, ".");
Packit 6c4009
  TEST_ELEM (mon_thousands_sep, "");
Packit 6c4009
  TEST_ELEM (positive_sign, "");
Packit 6c4009
  TEST_ELEM (negative_sign, "");
Packit 6c4009
Packit 6c4009
  /* The international currency symbol must come from ISO 4217.  */
Packit 6c4009
  if (monetary->int_curr_symbol != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* POSIX says this should be a 3-character symbol from ISO 4217
Packit 6c4009
	 along with a 4th character that is a divider, but the POSIX
Packit 6c4009
	 locale is documented as having a special case of "", and we
Packit 6c4009
	 support that also, so allow other locales to be created with
Packit 6c4009
	 a blank int_curr_symbol.  */
Packit 6c4009
      int ics_len = strlen (monetary->int_curr_symbol);
Packit 6c4009
      if (ics_len != 4 && ics_len != 0)
Packit 6c4009
	{
Packit 6c4009
	  if (! nothing)
Packit 6c4009
	    record_error (0, 0, _("\
Packit 6c4009
%s: value of field `int_curr_symbol' has wrong length"),
Packit 6c4009
			  "LC_MONETARY");
Packit 6c4009
	}
Packit 6c4009
      else if (ics_len == 4)
Packit 6c4009
	{ /* Check the first three characters against ISO 4217 */
Packit 6c4009
	  char symbol[4];
Packit 6c4009
	  strncpy (symbol, monetary->int_curr_symbol, 3);
Packit 6c4009
	  symbol[3] = '\0';
Packit 6c4009
	  /* A user may disable this waning for testing purposes or
Packit 6c4009
	     for building a locale with a 3 letter country code that
Packit 6c4009
	     was not yet supported in our ISO 4217 list.
Packit 6c4009
	     See the use of --no-warnings=intcurrsym.  */
Packit 6c4009
	  if (bsearch (symbol, valid_int_curr, NR_VALID_INT_CURR,
Packit 6c4009
		       sizeof (const char *),
Packit 6c4009
		       (comparison_fn_t) curr_strcmp) == NULL
Packit 6c4009
	      && warn_int_curr_symbol)
Packit 6c4009
	    record_warning (_("\
Packit 6c4009
%s: value of field `int_curr_symbol' does \
Packit 6c4009
not correspond to a valid name in ISO 4217 [--no-warnings=intcurrsym]"),
Packit 6c4009
			    "LC_MONETARY");
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The decimal point must not be empty.  This is not said explicitly
Packit 6c4009
     in POSIX but ANSI C (ISO/IEC 9899) says in 4.4.2.1 it has to be
Packit 6c4009
     != "".  */
Packit 6c4009
  if (monetary->mon_decimal_point == NULL)
Packit 6c4009
    {
Packit 6c4009
      if (! nothing)
Packit 6c4009
	record_error (0, 0, _("%s: field `%s' not defined"),
Packit 6c4009
		      "LC_MONETARY", "mon_decimal_point");
Packit 6c4009
      monetary->mon_decimal_point = ".";
Packit 6c4009
    }
Packit 6c4009
  else if (monetary->mon_decimal_point[0] == '\0' && ! be_quiet && ! nothing)
Packit 6c4009
    {
Packit 6c4009
      record_error (0, 0, _("\
Packit 6c4009
%s: value for field `%s' must not be an empty string"),
Packit 6c4009
		    "LC_MONETARY", "mon_decimal_point");
Packit 6c4009
    }
Packit 6c4009
  if (monetary->mon_decimal_point_wc == L'\0')
Packit 6c4009
    monetary->mon_decimal_point_wc = L'.';
Packit 6c4009
Packit 6c4009
  if (monetary->mon_grouping_len == 0)
Packit 6c4009
    {
Packit 6c4009
      if (! nothing)
Packit 6c4009
	record_error (0, 0, _("%s: field `%s' not defined"),
Packit 6c4009
		      "LC_MONETARY", "mon_grouping");
Packit 6c4009
Packit 6c4009
      monetary->mon_grouping = (char *) "\177";
Packit 6c4009
      monetary->mon_grouping_len = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
#undef TEST_ELEM
Packit 6c4009
#define TEST_ELEM(cat, min, max, initval) \
Packit 6c4009
  if (monetary->cat == -2)						      \
Packit 6c4009
    {									      \
Packit 6c4009
       if (! nothing)							      \
Packit 6c4009
	 record_error (0, 0, _("%s: field `%s' not defined"),		      \
Packit 6c4009
		       "LC_MONETARY", #cat);				      \
Packit 6c4009
       monetary->cat = initval;						      \
Packit 6c4009
    }									      \
Packit 6c4009
  else if ((monetary->cat < min || monetary->cat > max)			      \
Packit 6c4009
	   && min < max							      \
Packit 6c4009
	   && !be_quiet && !nothing)					      \
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: value for field `%s' must be in range %d...%d"),			      \
Packit 6c4009
		  "LC_MONETARY", #cat, min, max)
Packit 6c4009
Packit 6c4009
  TEST_ELEM (int_frac_digits, 1, 0, -1);
Packit 6c4009
  TEST_ELEM (frac_digits, 1, 0, -1);
Packit 6c4009
  TEST_ELEM (p_cs_precedes, -1, 1, -1);
Packit 6c4009
  TEST_ELEM (p_sep_by_space, -1, 2, -1);
Packit 6c4009
  TEST_ELEM (n_cs_precedes, -1, 1, -1);
Packit 6c4009
  TEST_ELEM (n_sep_by_space, -1, 2, -1);
Packit 6c4009
  TEST_ELEM (p_sign_posn, -1, 4, -1);
Packit 6c4009
  TEST_ELEM (n_sign_posn, -1, 4, -1);
Packit 6c4009
Packit 6c4009
  /* The non-POSIX.2 extensions are optional.  */
Packit 6c4009
  if (monetary->duo_int_curr_symbol == NULL)
Packit 6c4009
    monetary->duo_int_curr_symbol = monetary->int_curr_symbol;
Packit 6c4009
  if (monetary->duo_currency_symbol == NULL)
Packit 6c4009
    monetary->duo_currency_symbol = monetary->currency_symbol;
Packit 6c4009
Packit 6c4009
  if (monetary->duo_int_frac_digits == -2)
Packit 6c4009
    monetary->duo_int_frac_digits = monetary->int_frac_digits;
Packit 6c4009
  if (monetary->duo_frac_digits == -2)
Packit 6c4009
    monetary->duo_frac_digits = monetary->frac_digits;
Packit 6c4009
Packit 6c4009
#undef TEST_ELEM
Packit 6c4009
#define TEST_ELEM(cat, alt, min, max) \
Packit 6c4009
  if (monetary->cat == -2)						      \
Packit 6c4009
    monetary->cat = monetary->alt;					      \
Packit 6c4009
  else if ((monetary->cat < min || monetary->cat > max)	&& ! nothing)	      \
Packit 6c4009
    record_error (0, 0, _("\
Packit 6c4009
%s: value for field `%s' must be in range %d...%d"),			      \
Packit 6c4009
		  "LC_MONETARY", #cat, min, max)
Packit 6c4009
Packit 6c4009
  TEST_ELEM (int_p_cs_precedes, p_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (int_p_sep_by_space, p_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (int_n_cs_precedes, n_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (int_n_sep_by_space, n_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (int_p_sign_posn, p_sign_posn, -1, 4);
Packit 6c4009
  TEST_ELEM (int_n_sign_posn, n_sign_posn, -1, 4);
Packit 6c4009
Packit 6c4009
  TEST_ELEM (duo_p_cs_precedes, p_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (duo_p_sep_by_space, p_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (duo_n_cs_precedes, n_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (duo_n_sep_by_space, n_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (duo_int_p_cs_precedes, int_p_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (duo_int_p_sep_by_space, int_p_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (duo_int_n_cs_precedes, int_n_cs_precedes, -1, 1);
Packit 6c4009
  TEST_ELEM (duo_int_n_sep_by_space, int_n_sep_by_space, -1, 2);
Packit 6c4009
  TEST_ELEM (duo_p_sign_posn, p_sign_posn, -1, 4);
Packit 6c4009
  TEST_ELEM (duo_n_sign_posn, n_sign_posn, -1, 4);
Packit 6c4009
  TEST_ELEM (duo_int_p_sign_posn, int_p_sign_posn, -1, 4);
Packit 6c4009
  TEST_ELEM (duo_int_n_sign_posn, int_n_sign_posn, -1, 4);
Packit 6c4009
Packit 6c4009
  if (monetary->uno_valid_from == 0)
Packit 6c4009
    monetary->uno_valid_from = 10101;
Packit 6c4009
  if (monetary->uno_valid_to == 0)
Packit 6c4009
    monetary->uno_valid_to = 99991231;
Packit 6c4009
  if (monetary->duo_valid_from == 0)
Packit 6c4009
    monetary->duo_valid_from = 10101;
Packit 6c4009
  if (monetary->duo_valid_to == 0)
Packit 6c4009
    monetary->duo_valid_to = 99991231;
Packit 6c4009
Packit 6c4009
  if (monetary->conversion_rate[0] == 0)
Packit 6c4009
    {
Packit 6c4009
      monetary->conversion_rate[0] = 1;
Packit 6c4009
      monetary->conversion_rate[1] = 1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Create the crncystr entry.  */
Packit 6c4009
  monetary->crncystr = (char *) xmalloc (strlen (monetary->currency_symbol)
Packit 6c4009
					 + 2);
Packit 6c4009
  monetary->crncystr[0] = monetary->p_cs_precedes ? '-' : '+';
Packit 6c4009
  strcpy (&monetary->crncystr[1], monetary->currency_symbol);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
monetary_output (struct localedef_t *locale, const struct charmap_t *charmap,
Packit 6c4009
		 const char *output_path)
Packit 6c4009
{
Packit 6c4009
  struct locale_monetary_t *monetary
Packit 6c4009
    = locale->categories[LC_MONETARY].monetary;
Packit 6c4009
  struct locale_file file;
Packit 6c4009
Packit 6c4009
  init_locale_data (&file, _NL_ITEM_INDEX (_NL_NUM_LC_MONETARY));
Packit 6c4009
  add_locale_string (&file, monetary->int_curr_symbol);
Packit 6c4009
  add_locale_string (&file, monetary->currency_symbol);
Packit 6c4009
  add_locale_string (&file, monetary->mon_decimal_point);
Packit 6c4009
  add_locale_string (&file, monetary->mon_thousands_sep);
Packit 6c4009
  add_locale_raw_data (&file, monetary->mon_grouping,
Packit 6c4009
		       monetary->mon_grouping_len);
Packit 6c4009
  add_locale_string (&file, monetary->positive_sign);
Packit 6c4009
  add_locale_string (&file, monetary->negative_sign);
Packit 6c4009
  add_locale_char (&file, monetary->int_frac_digits);
Packit 6c4009
  add_locale_char (&file, monetary->frac_digits);
Packit 6c4009
  add_locale_char (&file, monetary->p_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->p_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->n_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->n_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->p_sign_posn);
Packit 6c4009
  add_locale_char (&file, monetary->n_sign_posn);
Packit 6c4009
  add_locale_string (&file, monetary->crncystr);
Packit 6c4009
  add_locale_char (&file, monetary->int_p_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->int_p_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->int_n_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->int_n_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->int_p_sign_posn);
Packit 6c4009
  add_locale_char (&file, monetary->int_n_sign_posn);
Packit 6c4009
  add_locale_string (&file, monetary->duo_int_curr_symbol);
Packit 6c4009
  add_locale_string (&file, monetary->duo_currency_symbol);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_frac_digits);
Packit 6c4009
  add_locale_char (&file, monetary->duo_frac_digits);
Packit 6c4009
  add_locale_char (&file, monetary->duo_p_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->duo_p_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->duo_n_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->duo_n_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_p_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_p_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_n_cs_precedes);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_n_sep_by_space);
Packit 6c4009
  add_locale_char (&file, monetary->duo_p_sign_posn);
Packit 6c4009
  add_locale_char (&file, monetary->duo_n_sign_posn);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_p_sign_posn);
Packit 6c4009
  add_locale_char (&file, monetary->duo_int_n_sign_posn);
Packit 6c4009
  add_locale_uint32 (&file, monetary->uno_valid_from);
Packit 6c4009
  add_locale_uint32 (&file, monetary->uno_valid_to);
Packit 6c4009
  add_locale_uint32 (&file, monetary->duo_valid_from);
Packit 6c4009
  add_locale_uint32 (&file, monetary->duo_valid_to);
Packit 6c4009
  add_locale_uint32_array (&file, monetary->conversion_rate, 2);
Packit 6c4009
  add_locale_uint32 (&file, monetary->mon_decimal_point_wc);
Packit 6c4009
  add_locale_uint32 (&file, monetary->mon_thousands_sep_wc);
Packit 6c4009
  add_locale_string (&file, charmap->code_set_name);
Packit 6c4009
  write_locale_data (output_path, LC_MONETARY, "LC_MONETARY", &file;;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
curr_strcmp (const char *s1, const char **s2)
Packit 6c4009
{
Packit 6c4009
  return strcmp (s1, *s2);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* The parser for the LC_MONETARY section of the locale definition.  */
Packit 6c4009
void
Packit 6c4009
monetary_read (struct linereader *ldfile, struct localedef_t *result,
Packit 6c4009
	       const struct charmap_t *charmap, const char *repertoire_name,
Packit 6c4009
	       int ignore_content)
Packit 6c4009
{
Packit 6c4009
  struct repertoire_t *repertoire = NULL;
Packit 6c4009
  struct locale_monetary_t *monetary;
Packit 6c4009
  struct token *now;
Packit 6c4009
  enum token_t nowtok;
Packit 6c4009
Packit 6c4009
  /* Get the repertoire we have to use.  */
Packit 6c4009
  if (repertoire_name != NULL)
Packit 6c4009
    repertoire = repertoire_read (repertoire_name);
Packit 6c4009
Packit 6c4009
  /* The rest of the line containing `LC_MONETARY' must be free.  */
Packit 6c4009
  lr_ignore_rest (ldfile, 1);
Packit 6c4009
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
      nowtok = now->tok;
Packit 6c4009
    }
Packit 6c4009
  while (nowtok == tok_eol);
Packit 6c4009
Packit 6c4009
  /* If we see `copy' now we are almost done.  */
Packit 6c4009
  if (nowtok == tok_copy)
Packit 6c4009
    {
Packit 6c4009
      handle_copy (ldfile, charmap, repertoire_name, result, tok_lc_monetary,
Packit 6c4009
		   LC_MONETARY, "LC_MONETARY", ignore_content);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Prepare the data structures.  */
Packit 6c4009
  monetary_startup (ldfile, result, ignore_content);
Packit 6c4009
  monetary = result->categories[LC_MONETARY].monetary;
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* Of course we don't proceed beyond the end of file.  */
Packit 6c4009
      if (nowtok == tok_eof)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      /* Ignore empty lines.  */
Packit 6c4009
      if (nowtok == tok_eol)
Packit 6c4009
	{
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  nowtok = now->tok;
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      switch (nowtok)
Packit 6c4009
	{
Packit 6c4009
#define STR_ELEM(cat) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);	      \
Packit 6c4009
	  if (now->tok != tok_string)					      \
Packit 6c4009
	    goto err_label;						      \
Packit 6c4009
	  else if (monetary->cat != NULL)				      \
Packit 6c4009
	    lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
Packit 6c4009
		      "LC_MONETARY", #cat);				      \
Packit 6c4009
	  else if (!ignore_content && now->val.str.startmb == NULL)	      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_error (ldfile, _("\
Packit 6c4009
%s: unknown character in field `%s'"), "LC_MONETARY", #cat);		      \
Packit 6c4009
	      monetary->cat = "";					      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (!ignore_content)					      \
Packit 6c4009
	    monetary->cat = now->val.str.startmb;			      \
Packit 6c4009
	  lr_ignore_rest (ldfile, 1);					      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  STR_ELEM (int_curr_symbol);
Packit 6c4009
	  STR_ELEM (currency_symbol);
Packit 6c4009
	  STR_ELEM (positive_sign);
Packit 6c4009
	  STR_ELEM (negative_sign);
Packit 6c4009
	  STR_ELEM (duo_int_curr_symbol);
Packit 6c4009
	  STR_ELEM (duo_currency_symbol);
Packit 6c4009
Packit 6c4009
#define STR_ELEM_WC(cat) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  ldfile->return_widestr = 1;					      \
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, repertoire, verbose);      \
Packit 6c4009
	  if (now->tok != tok_string)					      \
Packit 6c4009
	    goto err_label;						      \
Packit 6c4009
	  if (monetary->cat != NULL)					      \
Packit 6c4009
	    lr_error (ldfile, _("\
Packit 6c4009
%s: field `%s' declared more than once"), "LC_MONETARY", #cat);		      \
Packit 6c4009
	  else if (!ignore_content && now->val.str.startmb == NULL)	      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_error (ldfile, _("\
Packit 6c4009
%s: unknown character in field `%s'"), "LC_MONETARY", #cat);		      \
Packit 6c4009
	      monetary->cat = "";					      \
Packit 6c4009
	      monetary->cat##_wc = L'\0';				      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (now->val.str.startwc != NULL && now->val.str.lenwc > 2)    \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_error (ldfile, _("\
Packit 6c4009
%s: value for field `%s' must be a single character"), "LC_MONETARY", #cat);  \
Packit 6c4009
	    }								      \
Packit 6c4009
	  else if (!ignore_content)					      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      monetary->cat = now->val.str.startmb;			      \
Packit 6c4009
									      \
Packit 6c4009
	      if (now->val.str.startwc != NULL)				      \
Packit 6c4009
		monetary->cat##_wc = *now->val.str.startwc;		      \
Packit 6c4009
	    }								      \
Packit 6c4009
	  ldfile->return_widestr = 0;					      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  STR_ELEM_WC (mon_decimal_point);
Packit 6c4009
	  STR_ELEM_WC (mon_thousands_sep);
Packit 6c4009
Packit 6c4009
#define INT_ELEM(cat) \
Packit 6c4009
	case tok_##cat:							      \
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of	      \
Packit 6c4009
	     this line.  */						      \
Packit 6c4009
	  if (ignore_content)						      \
Packit 6c4009
	    {								      \
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);				      \
Packit 6c4009
	      break;							      \
Packit 6c4009
	    }								      \
Packit 6c4009
									      \
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);	      \
Packit 6c4009
	  if (now->tok != tok_minus1 && now->tok != tok_number)		      \
Packit 6c4009
	    goto err_label;						      \
Packit 6c4009
	  else if (monetary->cat != -2)					      \
Packit 6c4009
	    lr_error (ldfile, _("%s: field `%s' declared more than once"),    \
Packit 6c4009
		      "LC_MONETARY", #cat);				      \
Packit 6c4009
	  else if (!ignore_content)					      \
Packit 6c4009
	    monetary->cat = now->tok == tok_minus1 ? -1 : now->val.num;	      \
Packit 6c4009
	  break
Packit 6c4009
Packit 6c4009
	  INT_ELEM (int_frac_digits);
Packit 6c4009
	  INT_ELEM (frac_digits);
Packit 6c4009
	  INT_ELEM (p_cs_precedes);
Packit 6c4009
	  INT_ELEM (p_sep_by_space);
Packit 6c4009
	  INT_ELEM (n_cs_precedes);
Packit 6c4009
	  INT_ELEM (n_sep_by_space);
Packit 6c4009
	  INT_ELEM (p_sign_posn);
Packit 6c4009
	  INT_ELEM (n_sign_posn);
Packit 6c4009
	  INT_ELEM (int_p_cs_precedes);
Packit 6c4009
	  INT_ELEM (int_p_sep_by_space);
Packit 6c4009
	  INT_ELEM (int_n_cs_precedes);
Packit 6c4009
	  INT_ELEM (int_n_sep_by_space);
Packit 6c4009
	  INT_ELEM (int_p_sign_posn);
Packit 6c4009
	  INT_ELEM (int_n_sign_posn);
Packit 6c4009
	  INT_ELEM (duo_int_frac_digits);
Packit 6c4009
	  INT_ELEM (duo_frac_digits);
Packit 6c4009
	  INT_ELEM (duo_p_cs_precedes);
Packit 6c4009
	  INT_ELEM (duo_p_sep_by_space);
Packit 6c4009
	  INT_ELEM (duo_n_cs_precedes);
Packit 6c4009
	  INT_ELEM (duo_n_sep_by_space);
Packit 6c4009
	  INT_ELEM (duo_p_sign_posn);
Packit 6c4009
	  INT_ELEM (duo_n_sign_posn);
Packit 6c4009
	  INT_ELEM (duo_int_p_cs_precedes);
Packit 6c4009
	  INT_ELEM (duo_int_p_sep_by_space);
Packit 6c4009
	  INT_ELEM (duo_int_n_cs_precedes);
Packit 6c4009
	  INT_ELEM (duo_int_n_sep_by_space);
Packit 6c4009
	  INT_ELEM (duo_int_p_sign_posn);
Packit 6c4009
	  INT_ELEM (duo_int_n_sign_posn);
Packit 6c4009
	  INT_ELEM (uno_valid_from);
Packit 6c4009
	  INT_ELEM (uno_valid_to);
Packit 6c4009
	  INT_ELEM (duo_valid_from);
Packit 6c4009
	  INT_ELEM (duo_valid_to);
Packit 6c4009
Packit 6c4009
	case tok_mon_grouping:
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of
Packit 6c4009
	     this line.  */
Packit 6c4009
	  if (ignore_content)
Packit 6c4009
	    {
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  if (now->tok != tok_minus1 && now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      size_t act = 0;
Packit 6c4009
	      size_t max = 10;
Packit 6c4009
	      char *grouping = ignore_content ? NULL : xmalloc (max);
Packit 6c4009
Packit 6c4009
	      do
Packit 6c4009
		{
Packit 6c4009
		  if (act + 1 >= max)
Packit 6c4009
		    {
Packit 6c4009
		      max *= 2;
Packit 6c4009
		      grouping = xrealloc (grouping, max);
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  if (act > 0 && grouping[act - 1] == '\177')
Packit 6c4009
		    {
Packit 6c4009
		      lr_error (ldfile, _("\
Packit 6c4009
%s: `-1' must be last entry in `%s' field"),
Packit 6c4009
				"LC_MONETARY", "mon_grouping");
Packit 6c4009
		      lr_ignore_rest (ldfile, 0);
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  if (now->tok == tok_minus1)
Packit 6c4009
		    {
Packit 6c4009
		      if (!ignore_content)
Packit 6c4009
			grouping[act++] = '\177';
Packit 6c4009
		    }
Packit 6c4009
		  else if (now->val.num == 0)
Packit 6c4009
		    {
Packit 6c4009
		      /* A value of 0 disables grouping from here on but
Packit 6c4009
			 we must not store a NUL character since this
Packit 6c4009
			 terminates the string.  Use something different
Packit 6c4009
			 which must not be used otherwise.  */
Packit 6c4009
		      if (!ignore_content)
Packit 6c4009
			grouping[act++] = '\377';
Packit 6c4009
		    }
Packit 6c4009
		  else if (now->val.num > 126)
Packit 6c4009
		    lr_error (ldfile, _("\
Packit 6c4009
%s: values for field `%s' must be smaller than 127"),
Packit 6c4009
			      "LC_MONETARY", "mon_grouping");
Packit 6c4009
		  else if (!ignore_content)
Packit 6c4009
		    grouping[act++] = now->val.num;
Packit 6c4009
Packit 6c4009
		  /* Next must be semicolon.  */
Packit 6c4009
		  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
		  if (now->tok != tok_semicolon)
Packit 6c4009
		    break;
Packit 6c4009
Packit 6c4009
		  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
		}
Packit 6c4009
	      while (now->tok == tok_minus1 || now->tok == tok_number);
Packit 6c4009
Packit 6c4009
	      if (now->tok != tok_eol)
Packit 6c4009
		goto err_label;
Packit 6c4009
Packit 6c4009
	      if (!ignore_content)
Packit 6c4009
		{
Packit 6c4009
		  /* A single -1 means no grouping.  */
Packit 6c4009
		  if (act == 1 && grouping[0] == '\177')
Packit 6c4009
		    act--;
Packit 6c4009
		  grouping[act++] = '\0';
Packit 6c4009
Packit 6c4009
		  monetary->mon_grouping = xrealloc (grouping, act);
Packit 6c4009
		  monetary->mon_grouping_len = act;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case tok_conversion_rate:
Packit 6c4009
	  /* Ignore the rest of the line if we don't need the input of
Packit 6c4009
	     this line.  */
Packit 6c4009
	  if (ignore_content)
Packit 6c4009
	    {
Packit 6c4009
	      lr_ignore_rest (ldfile, 0);
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  if (now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  if (now->val.num == 0)
Packit 6c4009
	    {
Packit 6c4009
	    invalid_conversion_rate:
Packit 6c4009
	      lr_error (ldfile, _("conversion rate value cannot be zero"));
Packit 6c4009
	      if (!ignore_content)
Packit 6c4009
		{
Packit 6c4009
		  monetary->conversion_rate[0] = 1;
Packit 6c4009
		  monetary->conversion_rate[1] = 1;
Packit 6c4009
		}
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  if (!ignore_content)
Packit 6c4009
	    monetary->conversion_rate[0] = now->val.num;
Packit 6c4009
	  /* Next must be a semicolon.  */
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  if (now->tok != tok_semicolon)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  /* And another number.  */
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  if (now->tok != tok_number)
Packit 6c4009
	    goto err_label;
Packit 6c4009
	  if (now->val.num == 0)
Packit 6c4009
	    goto invalid_conversion_rate;
Packit 6c4009
	  if (!ignore_content)
Packit 6c4009
	    monetary->conversion_rate[1] = now->val.num;
Packit 6c4009
	  /* The rest of the line must be empty.  */
Packit 6c4009
	  lr_ignore_rest (ldfile, 1);
Packit 6c4009
	  break;
Packit 6c4009
Packit 6c4009
	case tok_end:
Packit 6c4009
	  /* Next we assume `LC_MONETARY'.  */
Packit 6c4009
	  now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
	  if (now->tok == tok_eof)
Packit 6c4009
	    break;
Packit 6c4009
	  if (now->tok == tok_eol)
Packit 6c4009
	    lr_error (ldfile, _("%s: incomplete `END' line"), "LC_MONETARY");
Packit 6c4009
	  else if (now->tok != tok_lc_monetary)
Packit 6c4009
	    lr_error (ldfile, _("\
Packit 6c4009
%1$s: definition does not end with `END %1$s'"), "LC_MONETARY");
Packit 6c4009
	  lr_ignore_rest (ldfile, now->tok == tok_lc_monetary);
Packit 6c4009
	  return;
Packit 6c4009
Packit 6c4009
	default:
Packit 6c4009
	err_label:
Packit 6c4009
	  SYNTAX_ERROR (_("%s: syntax error"), "LC_MONETARY");
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Prepare for the next round.  */
Packit 6c4009
      now = lr_token (ldfile, charmap, result, NULL, verbose);
Packit 6c4009
      nowtok = now->tok;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* When we come here we reached the end of the file.  */
Packit 6c4009
  lr_error (ldfile, _("%s: premature end of file"), "LC_MONETARY");
Packit 6c4009
}