Blame stdlib/strfmon_l.c

Packit 6c4009
/* Formatting a monetary value according to the given locale.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library 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 GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <langinfo.h>
Packit 6c4009
#include <locale.h>
Packit 6c4009
#include <monetary.h>
Packit 6c4009
#include "../libio/libioP.h"
Packit 6c4009
#include "../libio/strfile.h"
Packit 6c4009
#include <printf.h>
Packit 6c4009
#include <stdarg.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include "../locale/localeinfo.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
#define out_char(Ch)							      \
Packit 6c4009
  do {									      \
Packit 6c4009
    if (dest >= s + maxsize - 1)					      \
Packit 6c4009
      {									      \
Packit 6c4009
	__set_errno (E2BIG);						      \
Packit 6c4009
	va_end (ap);							      \
Packit 6c4009
	return -1;							      \
Packit 6c4009
      }									      \
Packit 6c4009
    *dest++ = (Ch);							      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define out_string(String)						      \
Packit 6c4009
  do {									      \
Packit 6c4009
    const char *_s = (String);						      \
Packit 6c4009
    while (*_s)								      \
Packit 6c4009
      out_char (*_s++);							      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define out_nstring(String, N)						      \
Packit 6c4009
  do {									      \
Packit 6c4009
    int _n = (N);							      \
Packit 6c4009
    const char *_s = (String);						      \
Packit 6c4009
    while (_n-- > 0)							      \
Packit 6c4009
      out_char (*_s++);							      \
Packit 6c4009
  } while (0)
Packit 6c4009
Packit 6c4009
#define to_digit(Ch) ((Ch) - '0')
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We use this code also for the extended locale handling where the
Packit 6c4009
   function gets as an additional argument the locale which has to be
Packit 6c4009
   used.  To access the values we have to redefine the _NL_CURRENT
Packit 6c4009
   macro.  */
Packit 6c4009
#undef _NL_CURRENT
Packit 6c4009
#define _NL_CURRENT(category, item) \
Packit 6c4009
  (current->values[_NL_ITEM_INDEX (item)].string)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* We have to overcome some problems with this implementation.  On the
Packit 6c4009
   one hand the strfmon() function is specified in XPG4 and of course
Packit 6c4009
   it has to follow this.  But on the other hand POSIX.2 specifies
Packit 6c4009
   some information in the LC_MONETARY category which should be used,
Packit 6c4009
   too.  Some of the information contradicts the information which can
Packit 6c4009
   be specified in format string.  */
Packit 6c4009
ssize_t
Packit 6c4009
__vstrfmon_l (char *s, size_t maxsize, locale_t loc, const char *format,
Packit 6c4009
	      va_list ap)
Packit 6c4009
{
Packit 6c4009
  struct __locale_data *current = loc->__locales[LC_MONETARY];
Packit 6c4009
  _IO_strfile f;
Packit 6c4009
  struct printf_info info;
Packit 6c4009
  char *dest;			/* Pointer so copy the output.  */
Packit 6c4009
  const char *fmt;		/* Pointer that walks through format.  */
Packit 6c4009
Packit 6c4009
  dest = s;
Packit 6c4009
  fmt = format;
Packit 6c4009
Packit 6c4009
  /* Loop through the format-string.  */
Packit 6c4009
  while (*fmt != '\0')
Packit 6c4009
    {
Packit 6c4009
      /* The floating-point value to output.  */
Packit 6c4009
      union
Packit 6c4009
      {
Packit 6c4009
	double dbl;
Packit 6c4009
	long double ldbl;
Packit 6c4009
      }
Packit 6c4009
      fpnum;
Packit 6c4009
      int int_format;
Packit 6c4009
      int print_curr_symbol;
Packit 6c4009
      int left_prec;
Packit 6c4009
      int left_pad;
Packit 6c4009
      int right_prec;
Packit 6c4009
      int group;
Packit 6c4009
      char pad;
Packit 6c4009
      int is_long_double;
Packit 6c4009
      int p_sign_posn;
Packit 6c4009
      int n_sign_posn;
Packit 6c4009
      int sign_posn;
Packit 6c4009
      int other_sign_posn;
Packit 6c4009
      int left;
Packit 6c4009
      int is_negative;
Packit 6c4009
      int sep_by_space;
Packit 6c4009
      int other_sep_by_space;
Packit 6c4009
      int cs_precedes;
Packit 6c4009
      int other_cs_precedes;
Packit 6c4009
      const char *sign_string;
Packit 6c4009
      const char *other_sign_string;
Packit 6c4009
      int done;
Packit 6c4009
      const char *currency_symbol;
Packit 6c4009
      size_t currency_symbol_len;
Packit 6c4009
      long int width;
Packit 6c4009
      char *startp;
Packit 6c4009
      const void *ptr;
Packit 6c4009
      char space_char;
Packit 6c4009
Packit 6c4009
      /* Process all character which do not introduce a format
Packit 6c4009
	 specification.  */
Packit 6c4009
      if (*fmt != '%')
Packit 6c4009
	{
Packit 6c4009
	  out_char (*fmt++);
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* "%%" means a single '%' character.  */
Packit 6c4009
      if (fmt[1] == '%')
Packit 6c4009
	{
Packit 6c4009
	  out_char (*++fmt);
Packit 6c4009
	  ++fmt;
Packit 6c4009
	  continue;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Defaults for formatting.  */
Packit 6c4009
      int_format = 0;			/* Use international curr. symbol */
Packit 6c4009
      print_curr_symbol = 1;		/* Print the currency symbol.  */
Packit 6c4009
      left_prec = -1;			/* No left precision specified.  */
Packit 6c4009
      right_prec = -1;			/* No right precision specified.  */
Packit 6c4009
      group = 1;			/* Print digits grouped.  */
Packit 6c4009
      pad = ' ';			/* Fill character is <SP>.  */
Packit 6c4009
      is_long_double = 0;		/* Double argument by default.  */
Packit 6c4009
      p_sign_posn = -2;			/* This indicates whether the */
Packit 6c4009
      n_sign_posn = -2;			/* '(' flag is given.  */
Packit 6c4009
      width = -1;			/* No width specified so far.  */
Packit 6c4009
      left = 0;				/* Right justified by default.  */
Packit 6c4009
Packit 6c4009
      /* Parse group characters.  */
Packit 6c4009
      while (1)
Packit 6c4009
	{
Packit 6c4009
	  switch (*++fmt)
Packit 6c4009
	    {
Packit 6c4009
	    case '=':			/* Set fill character.  */
Packit 6c4009
	      pad = *++fmt;
Packit 6c4009
	      if (pad == '\0')
Packit 6c4009
		{
Packit 6c4009
		  /* Premature EOS.  */
Packit 6c4009
		  __set_errno (EINVAL);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
	      continue;
Packit 6c4009
	    case '^':			/* Don't group digits.  */
Packit 6c4009
	      group = 0;
Packit 6c4009
	      continue;
Packit 6c4009
	    case '+':			/* Use +/- for sign of number.  */
Packit 6c4009
	      if (n_sign_posn != -2)
Packit 6c4009
		{
Packit 6c4009
		  __set_errno (EINVAL);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
	      p_sign_posn = *_NL_CURRENT (LC_MONETARY, P_SIGN_POSN);
Packit 6c4009
	      n_sign_posn = *_NL_CURRENT (LC_MONETARY, N_SIGN_POSN);
Packit 6c4009
	      continue;
Packit 6c4009
	    case '(':			/* Use ( ) for negative sign.  */
Packit 6c4009
	      if (n_sign_posn != -2)
Packit 6c4009
		{
Packit 6c4009
		  __set_errno (EINVAL);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
	      p_sign_posn = 0;
Packit 6c4009
	      n_sign_posn = 0;
Packit 6c4009
	      continue;
Packit 6c4009
	    case '!':			/* Don't print the currency symbol.  */
Packit 6c4009
	      print_curr_symbol = 0;
Packit 6c4009
	      continue;
Packit 6c4009
	    case '-':			/* Print left justified.  */
Packit 6c4009
	      left = 1;
Packit 6c4009
	      continue;
Packit 6c4009
	    default:
Packit 6c4009
	      /* Will stop the loop.  */;
Packit 6c4009
	    }
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (isdigit (*fmt))
Packit 6c4009
	{
Packit 6c4009
	  /* Parse field width.  */
Packit 6c4009
	  width = to_digit (*fmt);
Packit 6c4009
Packit 6c4009
	  while (isdigit (*++fmt))
Packit 6c4009
	    {
Packit 6c4009
	      int val = to_digit (*fmt);
Packit 6c4009
Packit 6c4009
	      if (width > LONG_MAX / 10
Packit 6c4009
		  || (width == LONG_MAX && val > LONG_MAX % 10))
Packit 6c4009
		{
Packit 6c4009
		  __set_errno (E2BIG);
Packit 6c4009
		  return -1;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      width = width * 10 + val;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* If we don't have enough room for the demanded width we
Packit 6c4009
	     can stop now and return an error.  */
Packit 6c4009
	  if (width >= maxsize - (dest - s))
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (E2BIG);
Packit 6c4009
	      return -1;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Recognize left precision.  */
Packit 6c4009
      if (*fmt == '#')
Packit 6c4009
	{
Packit 6c4009
	  if (!isdigit (*++fmt))
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (EINVAL);
Packit 6c4009
	      return -1;
Packit 6c4009
	    }
Packit 6c4009
	  left_prec = to_digit (*fmt);
Packit 6c4009
Packit 6c4009
	  while (isdigit (*++fmt))
Packit 6c4009
	    {
Packit 6c4009
	      left_prec *= 10;
Packit 6c4009
	      left_prec += to_digit (*fmt);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Recognize right precision.  */
Packit 6c4009
      if (*fmt == '.')
Packit 6c4009
	{
Packit 6c4009
	  if (!isdigit (*++fmt))
Packit 6c4009
	    {
Packit 6c4009
	      __set_errno (EINVAL);
Packit 6c4009
	      return -1;
Packit 6c4009
	    }
Packit 6c4009
	  right_prec = to_digit (*fmt);
Packit 6c4009
Packit 6c4009
	  while (isdigit (*++fmt))
Packit 6c4009
	    {
Packit 6c4009
	      right_prec *= 10;
Packit 6c4009
	      right_prec += to_digit (*fmt);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Handle modifier.  This is an extension.  */
Packit 6c4009
      if (*fmt == 'L')
Packit 6c4009
	{
Packit 6c4009
	  ++fmt;
Packit 6c4009
	  if (!__ldbl_is_dbl)
Packit 6c4009
	    is_long_double = 1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Handle format specifier.  */
Packit 6c4009
      char int_symbol[4];
Packit 6c4009
      switch (*fmt++)
Packit 6c4009
	{
Packit 6c4009
	case 'i': {		/* Use international currency symbol.  */
Packit 6c4009
	  const char *int_curr_symbol;
Packit 6c4009
Packit 6c4009
	  int_curr_symbol = _NL_CURRENT (LC_MONETARY, INT_CURR_SYMBOL);
Packit 6c4009
	  strncpy(int_symbol, int_curr_symbol, 3);
Packit 6c4009
	  int_symbol[3] = '\0';
Packit 6c4009
Packit 6c4009
	  currency_symbol_len = 3;
Packit 6c4009
	  currency_symbol = &int_symbol[0];
Packit 6c4009
	  space_char = int_curr_symbol[3];
Packit 6c4009
	  int_format = 1;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
	case 'n':		/* Use national currency symbol.  */
Packit 6c4009
	  currency_symbol = _NL_CURRENT (LC_MONETARY, CURRENCY_SYMBOL);
Packit 6c4009
	  currency_symbol_len = strlen (currency_symbol);
Packit 6c4009
	  space_char = ' ';
Packit 6c4009
	  int_format = 0;
Packit 6c4009
	  break;
Packit 6c4009
	default:		/* Any unrecognized format is an error.  */
Packit 6c4009
	  __set_errno (EINVAL);
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If not specified by the format string now find the values for
Packit 6c4009
	 the format specification.  */
Packit 6c4009
      if (p_sign_posn == -2)
Packit 6c4009
	p_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SIGN_POSN : P_SIGN_POSN);
Packit 6c4009
      if (n_sign_posn == -2)
Packit 6c4009
	n_sign_posn = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SIGN_POSN : N_SIGN_POSN);
Packit 6c4009
Packit 6c4009
      if (right_prec == -1)
Packit 6c4009
	{
Packit 6c4009
	  right_prec = *_NL_CURRENT (LC_MONETARY, int_format ? INT_FRAC_DIGITS : FRAC_DIGITS);
Packit 6c4009
Packit 6c4009
	  if (right_prec == '\377')
Packit 6c4009
	    right_prec = 2;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* If we have to print the digits grouped determine how many
Packit 6c4009
	 extra characters this means.  */
Packit 6c4009
      if (group && left_prec != -1)
Packit 6c4009
	left_prec += __guess_grouping (left_prec,
Packit 6c4009
				       _NL_CURRENT (LC_MONETARY, MON_GROUPING));
Packit 6c4009
Packit 6c4009
      /* Now it's time to get the value.  */
Packit 6c4009
      if (is_long_double == 1)
Packit 6c4009
	{
Packit 6c4009
	  fpnum.ldbl = va_arg (ap, long double);
Packit 6c4009
	  is_negative = fpnum.ldbl < 0;
Packit 6c4009
	  if (is_negative)
Packit 6c4009
	    fpnum.ldbl = -fpnum.ldbl;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  fpnum.dbl = va_arg (ap, double);
Packit 6c4009
	  is_negative = fpnum.dbl < 0;
Packit 6c4009
	  if (is_negative)
Packit 6c4009
	    fpnum.dbl = -fpnum.dbl;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* We now know the sign of the value and can determine the format.  */
Packit 6c4009
      if (is_negative)
Packit 6c4009
	{
Packit 6c4009
	  sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
Packit 6c4009
	  /* If the locale does not specify a character for the
Packit 6c4009
	     negative sign we use a '-'.  */
Packit 6c4009
	  if (*sign_string == '\0')
Packit 6c4009
	    sign_string = (const char *) "-";
Packit 6c4009
	  cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
Packit 6c4009
	  sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
Packit 6c4009
	  sign_posn = n_sign_posn;
Packit 6c4009
Packit 6c4009
	  other_sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
Packit 6c4009
	  other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
Packit 6c4009
	  other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
Packit 6c4009
	  other_sign_posn = p_sign_posn;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  sign_string = _NL_CURRENT (LC_MONETARY, POSITIVE_SIGN);
Packit 6c4009
	  cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_CS_PRECEDES : P_CS_PRECEDES);
Packit 6c4009
	  sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_P_SEP_BY_SPACE : P_SEP_BY_SPACE);
Packit 6c4009
	  sign_posn = p_sign_posn;
Packit 6c4009
Packit 6c4009
	  other_sign_string = _NL_CURRENT (LC_MONETARY, NEGATIVE_SIGN);
Packit 6c4009
	  if (*other_sign_string == '\0')
Packit 6c4009
	    other_sign_string = (const char *) "-";
Packit 6c4009
	  other_cs_precedes = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_CS_PRECEDES : N_CS_PRECEDES);
Packit 6c4009
	  other_sep_by_space = *_NL_CURRENT (LC_MONETARY, int_format ? INT_N_SEP_BY_SPACE : N_SEP_BY_SPACE);
Packit 6c4009
	  other_sign_posn = n_sign_posn;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Set default values for unspecified information.  */
Packit 6c4009
      if (cs_precedes != 0)
Packit 6c4009
	cs_precedes = 1;
Packit 6c4009
      if (other_cs_precedes != 0)
Packit 6c4009
	other_cs_precedes = 1;
Packit 6c4009
      if (sep_by_space == '\377')
Packit 6c4009
	sep_by_space = 0;
Packit 6c4009
      if (other_sep_by_space == '\377')
Packit 6c4009
	other_sep_by_space = 0;
Packit 6c4009
      if (sign_posn == '\377')
Packit 6c4009
	sign_posn = 1;
Packit 6c4009
      if (other_sign_posn == '\377')
Packit 6c4009
	other_sign_posn = 1;
Packit 6c4009
Packit 6c4009
      /* Check for degenerate cases */
Packit 6c4009
      if (sep_by_space == 2)
Packit 6c4009
	{
Packit 6c4009
	  if (sign_posn == 0 ||
Packit 6c4009
	      (sign_posn == 1 && !cs_precedes) ||
Packit 6c4009
	      (sign_posn == 2 && cs_precedes))
Packit 6c4009
	    /* sign and symbol are not adjacent, so no separator */
Packit 6c4009
	    sep_by_space = 0;
Packit 6c4009
	}
Packit 6c4009
      if (other_sep_by_space == 2)
Packit 6c4009
	{
Packit 6c4009
	  if (other_sign_posn == 0 ||
Packit 6c4009
	      (other_sign_posn == 1 && !other_cs_precedes) ||
Packit 6c4009
	      (other_sign_posn == 2 && other_cs_precedes))
Packit 6c4009
	    /* sign and symbol are not adjacent, so no separator */
Packit 6c4009
	    other_sep_by_space = 0;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Set the left precision and padding needed for alignment */
Packit 6c4009
      if (left_prec == -1)
Packit 6c4009
	{
Packit 6c4009
	  left_prec = 0;
Packit 6c4009
	  left_pad = 0;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* Set left_pad to number of spaces needed to align positive
Packit 6c4009
	     and negative formats */
Packit 6c4009
Packit 6c4009
	  int left_bytes = 0;
Packit 6c4009
	  int other_left_bytes = 0;
Packit 6c4009
Packit 6c4009
	  /* Work out number of bytes for currency string and separator
Packit 6c4009
	     preceding the value */
Packit 6c4009
	  if (cs_precedes)
Packit 6c4009
	    {
Packit 6c4009
	      left_bytes += currency_symbol_len;
Packit 6c4009
	      if (sep_by_space != 0)
Packit 6c4009
		++left_bytes;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (other_cs_precedes)
Packit 6c4009
	    {
Packit 6c4009
	      other_left_bytes += currency_symbol_len;
Packit 6c4009
	      if (other_sep_by_space != 0)
Packit 6c4009
		++other_left_bytes;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Work out number of bytes for the sign (or left parenthesis)
Packit 6c4009
	     preceding the value */
Packit 6c4009
	  if (sign_posn == 0 && is_negative)
Packit 6c4009
	    ++left_bytes;
Packit 6c4009
	  else if (sign_posn == 1)
Packit 6c4009
	    left_bytes += strlen (sign_string);
Packit 6c4009
	  else if (cs_precedes && (sign_posn == 3 || sign_posn == 4))
Packit 6c4009
	    left_bytes += strlen (sign_string);
Packit 6c4009
Packit 6c4009
	  if (other_sign_posn == 0 && !is_negative)
Packit 6c4009
	    ++other_left_bytes;
Packit 6c4009
	  else if (other_sign_posn == 1)
Packit 6c4009
	    other_left_bytes += strlen (other_sign_string);
Packit 6c4009
	  else if (other_cs_precedes &&
Packit 6c4009
		   (other_sign_posn == 3 || other_sign_posn == 4))
Packit 6c4009
	    other_left_bytes += strlen (other_sign_string);
Packit 6c4009
Packit 6c4009
	  /* Compare the number of bytes preceding the value for
Packit 6c4009
	     each format, and set the padding accordingly */
Packit 6c4009
	  if (other_left_bytes > left_bytes)
Packit 6c4009
	    left_pad = other_left_bytes - left_bytes;
Packit 6c4009
	  else
Packit 6c4009
	    left_pad = 0;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      /* Perhaps we'll someday make these things configurable so
Packit 6c4009
	 better start using symbolic names now.  */
Packit 6c4009
#define left_paren '('
Packit 6c4009
#define right_paren ')'
Packit 6c4009
Packit 6c4009
      startp = dest;		/* Remember start so we can compute length.  */
Packit 6c4009
Packit 6c4009
      while (left_pad-- > 0)
Packit 6c4009
	out_char (' ');
Packit 6c4009
Packit 6c4009
      if (sign_posn == 0 && is_negative)
Packit 6c4009
	out_char (left_paren);
Packit 6c4009
Packit 6c4009
      if (cs_precedes)
Packit 6c4009
	{
Packit 6c4009
	  if (sign_posn != 0 && sign_posn != 2 && sign_posn != 4
Packit 6c4009
	      && sign_posn != 5)
Packit 6c4009
	    {
Packit 6c4009
	      out_string (sign_string);
Packit 6c4009
	      if (sep_by_space == 2)
Packit 6c4009
		out_char (' ');
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (print_curr_symbol)
Packit 6c4009
	    out_string (currency_symbol);
Packit 6c4009
Packit 6c4009
	  if (sign_posn == 4)
Packit 6c4009
	    {
Packit 6c4009
	      if (print_curr_symbol && sep_by_space == 2)
Packit 6c4009
		out_char (space_char);
Packit 6c4009
	      out_string (sign_string);
Packit 6c4009
	      if (sep_by_space == 1)
Packit 6c4009
		/* POSIX.2 and SUS are not clear on this case, but C99
Packit 6c4009
		   says a space follows the adjacent-symbol-and-sign */
Packit 6c4009
		out_char (' ');
Packit 6c4009
	    }
Packit 6c4009
	  else
Packit 6c4009
	    if (print_curr_symbol && sep_by_space == 1)
Packit 6c4009
	      out_char (space_char);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	if (sign_posn != 0 && sign_posn != 2 && sign_posn != 3
Packit 6c4009
	    && sign_posn != 4 && sign_posn != 5)
Packit 6c4009
	  out_string (sign_string);
Packit 6c4009
Packit 6c4009
      /* Print the number.  */
Packit 6c4009
#ifdef _IO_MTSAFE_IO
Packit 6c4009
      f._sbf._f._lock = NULL;
Packit 6c4009
#endif
Packit 6c4009
      _IO_init_internal (&f._sbf._f, 0);
Packit 6c4009
      _IO_JUMPS (&f._sbf) = &_IO_str_jumps;
Packit 6c4009
      _IO_str_init_static_internal (&f, dest, (s + maxsize) - dest, dest);
Packit 6c4009
      /* We clear the last available byte so we can find out whether
Packit 6c4009
	 the numeric representation is too long.  */
Packit 6c4009
      s[maxsize - 1] = '\0';
Packit 6c4009
Packit 6c4009
      memset (&info, '\0', sizeof (info));
Packit 6c4009
      info.prec = right_prec;
Packit 6c4009
      info.width = left_prec + (right_prec ? (right_prec + 1) : 0);
Packit 6c4009
      info.spec = 'f';
Packit 6c4009
      info.is_long_double = is_long_double;
Packit 6c4009
      info.group = group;
Packit 6c4009
      info.pad = pad;
Packit 6c4009
      info.extra = 1;		/* This means use values from LC_MONETARY.  */
Packit 6c4009
Packit 6c4009
      ptr = &fpnum;
Packit 6c4009
      done = __printf_fp_l (&f._sbf._f, loc, &info, &ptr);
Packit 6c4009
      if (done < 0)
Packit 6c4009
	return -1;
Packit 6c4009
Packit 6c4009
      if (s[maxsize - 1] != '\0')
Packit 6c4009
	{
Packit 6c4009
	  __set_errno (E2BIG);
Packit 6c4009
	  return -1;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      dest += done;
Packit 6c4009
Packit 6c4009
      if (!cs_precedes)
Packit 6c4009
	{
Packit 6c4009
	  if (sign_posn == 3)
Packit 6c4009
	    {
Packit 6c4009
	      if (sep_by_space == 1)
Packit 6c4009
		out_char (' ');
Packit 6c4009
	      out_string (sign_string);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (print_curr_symbol)
Packit 6c4009
	    {
Packit 6c4009
	      if ((sign_posn == 3 && sep_by_space == 2)
Packit 6c4009
		  || (sign_posn == 4 && sep_by_space == 1)
Packit 6c4009
		  || (sign_posn == 2 && sep_by_space == 1)
Packit 6c4009
		  || (sign_posn == 1 && sep_by_space == 1)
Packit 6c4009
		  || (sign_posn == 0 && sep_by_space == 1))
Packit 6c4009
		out_char (space_char);
Packit 6c4009
	      out_nstring (currency_symbol, currency_symbol_len);
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (sign_posn == 4)
Packit 6c4009
	    {
Packit 6c4009
	      if (sep_by_space == 2)
Packit 6c4009
		out_char (' ');
Packit 6c4009
	      out_string (sign_string);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (sign_posn == 2)
Packit 6c4009
	{
Packit 6c4009
	  if (sep_by_space == 2)
Packit 6c4009
	    out_char (' ');
Packit 6c4009
	  out_string (sign_string);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (sign_posn == 0 && is_negative)
Packit 6c4009
	out_char (right_paren);
Packit 6c4009
Packit 6c4009
      /* Now test whether the output width is filled.  */
Packit 6c4009
      if (dest - startp < width)
Packit 6c4009
	{
Packit 6c4009
	  if (left)
Packit 6c4009
	    /* We simply have to fill using spaces.  */
Packit 6c4009
	    do
Packit 6c4009
	      out_char (' ');
Packit 6c4009
	    while (dest - startp < width);
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      long int dist = width - (dest - startp);
Packit 6c4009
	      for (char *cp = dest - 1; cp >= startp; --cp)
Packit 6c4009
		cp[dist] = cp[0];
Packit 6c4009
Packit 6c4009
	      dest += dist;
Packit 6c4009
Packit 6c4009
	      do
Packit 6c4009
		startp[--dist] = ' ';
Packit 6c4009
	      while (dist > 0);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Terminate the string.  */
Packit 6c4009
  *dest = '\0';
Packit 6c4009
Packit 6c4009
  return dest - s;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
ssize_t
Packit 6c4009
___strfmon_l (char *s, size_t maxsize, locale_t loc, const char *format, ...)
Packit 6c4009
{
Packit 6c4009
  va_list ap;
Packit 6c4009
Packit 6c4009
  va_start (ap, format);
Packit 6c4009
Packit 6c4009
  ssize_t res = __vstrfmon_l (s, maxsize, loc, format, ap);
Packit 6c4009
Packit 6c4009
  va_end (ap);
Packit 6c4009
Packit 6c4009
  return res;
Packit 6c4009
}
Packit 6c4009
ldbl_strong_alias (___strfmon_l, __strfmon_l)
Packit 6c4009
ldbl_weak_alias (___strfmon_l, strfmon_l)