diff options
Diffstat (limited to 'pcp/intl/vasnprintf.c')
| -rw-r--r-- | pcp/intl/vasnprintf.c | 5606 | 
1 files changed, 5606 insertions, 0 deletions
| diff --git a/pcp/intl/vasnprintf.c b/pcp/intl/vasnprintf.c new file mode 100644 index 0000000..93ee955 --- /dev/null +++ b/pcp/intl/vasnprintf.c @@ -0,0 +1,5606 @@ +/* vsprintf with automatic memory allocation. +   Copyright (C) 1999, 2002-2012 Free Software Foundation, Inc. + +   This program is free software: you can redistribute it and/or modify +   it under the terms of the GNU Lesser General Public License as published by +   the Free Software Foundation; either version 2.1 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU Lesser General Public License for more details. + +   You should have received a copy of the GNU Lesser General Public License +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */ + +/* This file can be parametrized with the following macros: +     VASNPRINTF         The name of the function being defined. +     FCHAR_T            The element type of the format string. +     DCHAR_T            The element type of the destination (result) string. +     FCHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters +                        in the format string are ASCII. MUST be set if +                        FCHAR_T and DCHAR_T are not the same type. +     DIRECTIVE          Structure denoting a format directive. +                        Depends on FCHAR_T. +     DIRECTIVES         Structure denoting the set of format directives of a +                        format string.  Depends on FCHAR_T. +     PRINTF_PARSE       Function that parses a format string. +                        Depends on FCHAR_T. +     DCHAR_CPY          memcpy like function for DCHAR_T[] arrays. +     DCHAR_SET          memset like function for DCHAR_T[] arrays. +     DCHAR_MBSNLEN      mbsnlen like function for DCHAR_T[] arrays. +     SNPRINTF           The system's snprintf (or similar) function. +                        This may be either snprintf or swprintf. +     TCHAR_T            The element type of the argument and result string +                        of the said SNPRINTF function.  This may be either +                        char or wchar_t.  The code exploits that +                        sizeof (TCHAR_T) | sizeof (DCHAR_T) and +                        alignof (TCHAR_T) <= alignof (DCHAR_T). +     DCHAR_IS_TCHAR     Set to 1 if DCHAR_T and TCHAR_T are the same type. +     DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[]. +     DCHAR_IS_UINT8_T   Set to 1 if DCHAR_T is uint8_t. +     DCHAR_IS_UINT16_T  Set to 1 if DCHAR_T is uint16_t. +     DCHAR_IS_UINT32_T  Set to 1 if DCHAR_T is uint32_t.  */ + +/* Tell glibc's <stdio.h> to provide a prototype for snprintf(). +   This must come before <config.h> because <config.h> may include +   <features.h>, and once <features.h> has been included, it's too late.  */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE    1 +#endif + +#ifndef VASNPRINTF +# include <config.h> +#endif +#ifndef IN_LIBINTL +# include <alloca.h> +#endif + +/* Specification.  */ +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +#  include "vasnwprintf.h" +# else +#  include "vasnprintf.h" +# endif +#endif + +#include <locale.h>     /* localeconv() */ +#include <stdio.h>      /* snprintf(), sprintf() */ +#include <stdlib.h>     /* abort(), malloc(), realloc(), free() */ +#include <string.h>     /* memcpy(), strlen() */ +#include <errno.h>      /* errno */ +#include <limits.h>     /* CHAR_BIT */ +#include <float.h>      /* DBL_MAX_EXP, LDBL_MAX_EXP */ +#if HAVE_NL_LANGINFO +# include <langinfo.h> +#endif +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +#  include "wprintf-parse.h" +# else +#  include "printf-parse.h" +# endif +#endif + +/* Checked size_t computations.  */ +#include "xsize.h" + +#include "verify.h" + +#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +# include <math.h> +# include "float+.h" +#endif + +#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL +# include <math.h> +# include "isnand-nolibm.h" +#endif + +#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL +# include <math.h> +# include "isnanl-nolibm.h" +# include "fpucw.h" +#endif + +#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL +# include <math.h> +# include "isnand-nolibm.h" +# include "printf-frexp.h" +#endif + +#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +# include <math.h> +# include "isnanl-nolibm.h" +# include "printf-frexpl.h" +# include "fpucw.h" +#endif + +/* Default parameters.  */ +#ifndef VASNPRINTF +# if WIDE_CHAR_VERSION +#  define VASNPRINTF vasnwprintf +#  define FCHAR_T wchar_t +#  define DCHAR_T wchar_t +#  define TCHAR_T wchar_t +#  define DCHAR_IS_TCHAR 1 +#  define DIRECTIVE wchar_t_directive +#  define DIRECTIVES wchar_t_directives +#  define PRINTF_PARSE wprintf_parse +#  define DCHAR_CPY wmemcpy +#  define DCHAR_SET wmemset +# else +#  define VASNPRINTF vasnprintf +#  define FCHAR_T char +#  define DCHAR_T char +#  define TCHAR_T char +#  define DCHAR_IS_TCHAR 1 +#  define DIRECTIVE char_directive +#  define DIRECTIVES char_directives +#  define PRINTF_PARSE printf_parse +#  define DCHAR_CPY memcpy +#  define DCHAR_SET memset +# endif +#endif +#if WIDE_CHAR_VERSION +  /* TCHAR_T is wchar_t.  */ +# define USE_SNPRINTF 1 +# if HAVE_DECL__SNWPRINTF +   /* On Windows, the function swprintf() has a different signature than +      on Unix; we use the function _snwprintf() or - on mingw - snwprintf() +      instead.  The mingw function snwprintf() has fewer bugs than the +      MSVCRT function _snwprintf(), so prefer that.  */ +#  if defined __MINGW32__ +#   define SNPRINTF snwprintf +#  else +#   define SNPRINTF _snwprintf +#  endif +# else +   /* Unix.  */ +#  define SNPRINTF swprintf +# endif +#else +  /* TCHAR_T is char.  */ +  /* Use snprintf if it exists under the name 'snprintf' or '_snprintf'. +     But don't use it on BeOS, since BeOS snprintf produces no output if the +     size argument is >= 0x3000000. +     Also don't use it on Linux libc5, since there snprintf with size = 1 +     writes any output without bounds, like sprintf.  */ +# if (HAVE_DECL__SNPRINTF || HAVE_SNPRINTF) && !defined __BEOS__ && !(__GNU_LIBRARY__ == 1) +#  define USE_SNPRINTF 1 +# else +#  define USE_SNPRINTF 0 +# endif +# if HAVE_DECL__SNPRINTF +   /* Windows.  The mingw function snprintf() has fewer bugs than the MSVCRT +      function _snprintf(), so prefer that.  */ +#  if defined __MINGW32__ +#   define SNPRINTF snprintf +    /* Here we need to call the native snprintf, not rpl_snprintf.  */ +#   undef snprintf +#  else +#   define SNPRINTF _snprintf +#  endif +# else +   /* Unix.  */ +#  define SNPRINTF snprintf +   /* Here we need to call the native snprintf, not rpl_snprintf.  */ +#  undef snprintf +# endif +#endif +/* Here we need to call the native sprintf, not rpl_sprintf.  */ +#undef sprintf + +/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" +   warnings in this file.  Use -Dlint to suppress them.  */ +#ifdef lint +# define IF_LINT(Code) Code +#else +# define IF_LINT(Code) /* empty */ +#endif + +/* Avoid some warnings from "gcc -Wshadow". +   This file doesn't use the exp() and remainder() functions.  */ +#undef exp +#define exp expo +#undef remainder +#define remainder rem + +#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION +# if (HAVE_STRNLEN && !defined _AIX) +#  define local_strnlen strnlen +# else +#  ifndef local_strnlen_defined +#   define local_strnlen_defined 1 +static size_t +local_strnlen (const char *string, size_t maxlen) +{ +  const char *end = memchr (string, '\0', maxlen); +  return end ? (size_t) (end - string) : maxlen; +} +#  endif +# endif +#endif + +#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T +# if HAVE_WCSLEN +#  define local_wcslen wcslen +# else +   /* Solaris 2.5.1 has wcslen() in a separate library libw.so. To avoid +      a dependency towards this library, here is a local substitute. +      Define this substitute only once, even if this file is included +      twice in the same compilation unit.  */ +#  ifndef local_wcslen_defined +#   define local_wcslen_defined 1 +static size_t +local_wcslen (const wchar_t *s) +{ +  const wchar_t *ptr; + +  for (ptr = s; *ptr != (wchar_t) 0; ptr++) +    ; +  return ptr - s; +} +#  endif +# endif +#endif + +#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION +# if HAVE_WCSNLEN +#  define local_wcsnlen wcsnlen +# else +#  ifndef local_wcsnlen_defined +#   define local_wcsnlen_defined 1 +static size_t +local_wcsnlen (const wchar_t *s, size_t maxlen) +{ +  const wchar_t *ptr; + +  for (ptr = s; maxlen > 0 && *ptr != (wchar_t) 0; ptr++, maxlen--) +    ; +  return ptr - s; +} +#  endif +# endif +#endif + +#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL +/* Determine the decimal-point character according to the current locale.  */ +# ifndef decimal_point_char_defined +#  define decimal_point_char_defined 1 +static char +decimal_point_char (void) +{ +  const char *point; +  /* Determine it in a multithread-safe way.  We know nl_langinfo is +     multithread-safe on glibc systems and Mac OS X systems, but is not required +     to be multithread-safe by POSIX.  sprintf(), however, is multithread-safe. +     localeconv() is rarely multithread-safe.  */ +#  if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__)) +  point = nl_langinfo (RADIXCHAR); +#  elif 1 +  char pointbuf[5]; +  sprintf (pointbuf, "%#.0f", 1.0); +  point = &pointbuf[1]; +#  else +  point = localeconv () -> decimal_point; +#  endif +  /* The decimal point is always a single byte: either '.' or ','.  */ +  return (point[0] != '\0' ? point[0] : '.'); +} +# endif +#endif + +#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL + +/* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */ +static int +is_infinite_or_zero (double x) +{ +  return isnand (x) || x + x == x; +} + +#endif + +#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL + +/* Equivalent to !isfinite(x) || x == 0, but does not require libm.  */ +static int +is_infinite_or_zerol (long double x) +{ +  return isnanl (x) || x + x == x; +} + +#endif + +#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL + +/* Converting 'long double' to decimal without rare rounding bugs requires +   real bignums.  We use the naming conventions of GNU gmp, but vastly simpler +   (and slower) algorithms.  */ + +typedef unsigned int mp_limb_t; +# define GMP_LIMB_BITS 32 +verify (sizeof (mp_limb_t) * CHAR_BIT == GMP_LIMB_BITS); + +typedef unsigned long long mp_twolimb_t; +# define GMP_TWOLIMB_BITS 64 +verify (sizeof (mp_twolimb_t) * CHAR_BIT == GMP_TWOLIMB_BITS); + +/* Representation of a bignum >= 0.  */ +typedef struct +{ +  size_t nlimbs; +  mp_limb_t *limbs; /* Bits in little-endian order, allocated with malloc().  */ +} mpn_t; + +/* Compute the product of two bignums >= 0. +   Return the allocated memory in case of success, NULL in case of memory +   allocation failure.  */ +static void * +multiply (mpn_t src1, mpn_t src2, mpn_t *dest) +{ +  const mp_limb_t *p1; +  const mp_limb_t *p2; +  size_t len1; +  size_t len2; + +  if (src1.nlimbs <= src2.nlimbs) +    { +      len1 = src1.nlimbs; +      p1 = src1.limbs; +      len2 = src2.nlimbs; +      p2 = src2.limbs; +    } +  else +    { +      len1 = src2.nlimbs; +      p1 = src2.limbs; +      len2 = src1.nlimbs; +      p2 = src1.limbs; +    } +  /* Now 0 <= len1 <= len2.  */ +  if (len1 == 0) +    { +      /* src1 or src2 is zero.  */ +      dest->nlimbs = 0; +      dest->limbs = (mp_limb_t *) malloc (1); +    } +  else +    { +      /* Here 1 <= len1 <= len2.  */ +      size_t dlen; +      mp_limb_t *dp; +      size_t k, i, j; + +      dlen = len1 + len2; +      dp = (mp_limb_t *) malloc (dlen * sizeof (mp_limb_t)); +      if (dp == NULL) +        return NULL; +      for (k = len2; k > 0; ) +        dp[--k] = 0; +      for (i = 0; i < len1; i++) +        { +          mp_limb_t digit1 = p1[i]; +          mp_twolimb_t carry = 0; +          for (j = 0; j < len2; j++) +            { +              mp_limb_t digit2 = p2[j]; +              carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2; +              carry += dp[i + j]; +              dp[i + j] = (mp_limb_t) carry; +              carry = carry >> GMP_LIMB_BITS; +            } +          dp[i + len2] = (mp_limb_t) carry; +        } +      /* Normalise.  */ +      while (dlen > 0 && dp[dlen - 1] == 0) +        dlen--; +      dest->nlimbs = dlen; +      dest->limbs = dp; +    } +  return dest->limbs; +} + +/* Compute the quotient of a bignum a >= 0 and a bignum b > 0. +   a is written as  a = q * b + r  with 0 <= r < b.  q is the quotient, r +   the remainder. +   Finally, round-to-even is performed: If r > b/2 or if r = b/2 and q is odd, +   q is incremented. +   Return the allocated memory in case of success, NULL in case of memory +   allocation failure.  */ +static void * +divide (mpn_t a, mpn_t b, mpn_t *q) +{ +  /* Algorithm: +     First normalise a and b: a=[a[m-1],...,a[0]], b=[b[n-1],...,b[0]] +     with m>=0 and n>0 (in base beta = 2^GMP_LIMB_BITS). +     If m<n, then q:=0 and r:=a. +     If m>=n=1, perform a single-precision division: +       r:=0, j:=m, +       while j>0 do +         {Here (q[m-1]*beta^(m-1)+...+q[j]*beta^j) * b[0] + r*beta^j = +               = a[m-1]*beta^(m-1)+...+a[j]*beta^j und 0<=r<b[0]<beta} +         j:=j-1, r:=r*beta+a[j], q[j]:=floor(r/b[0]), r:=r-b[0]*q[j]. +       Normalise [q[m-1],...,q[0]], yields q. +     If m>=n>1, perform a multiple-precision division: +       We have a/b < beta^(m-n+1). +       s:=intDsize-1-(highest bit in b[n-1]), 0<=s<intDsize. +       Shift a and b left by s bits, copying them. r:=a. +       r=[r[m],...,r[0]], b=[b[n-1],...,b[0]] with b[n-1]>=beta/2. +       For j=m-n,...,0: {Here 0 <= r < b*beta^(j+1).} +         Compute q* : +           q* := floor((r[j+n]*beta+r[j+n-1])/b[n-1]). +           In case of overflow (q* >= beta) set q* := beta-1. +           Compute c2 := ((r[j+n]*beta+r[j+n-1]) - q* * b[n-1])*beta + r[j+n-2] +           and c3 := b[n-2] * q*. +           {We have 0 <= c2 < 2*beta^2, even 0 <= c2 < beta^2 if no overflow +            occurred.  Furthermore 0 <= c3 < beta^2. +            If there was overflow and +            r[j+n]*beta+r[j+n-1] - q* * b[n-1] >= beta, i.e. c2 >= beta^2, +            the next test can be skipped.} +           While c3 > c2, {Here 0 <= c2 < c3 < beta^2} +             Put q* := q* - 1, c2 := c2 + b[n-1]*beta, c3 := c3 - b[n-2]. +           If q* > 0: +             Put r := r - b * q* * beta^j. In detail: +               [r[n+j],...,r[j]] := [r[n+j],...,r[j]] - q* * [b[n-1],...,b[0]]. +               hence: u:=0, for i:=0 to n-1 do +                              u := u + q* * b[i], +                              r[j+i]:=r[j+i]-(u mod beta) (+ beta, if carry), +                              u:=u div beta (+ 1, if carry in subtraction) +                      r[n+j]:=r[n+j]-u. +               {Since always u = (q* * [b[i-1],...,b[0]] div beta^i) + 1 +                               < q* + 1 <= beta, +                the carry u does not overflow.} +             If a negative carry occurs, put q* := q* - 1 +               and [r[n+j],...,r[j]] := [r[n+j],...,r[j]] + [0,b[n-1],...,b[0]]. +         Set q[j] := q*. +       Normalise [q[m-n],..,q[0]]; this yields the quotient q. +       Shift [r[n-1],...,r[0]] right by s bits and normalise; this yields the +       rest r. +       The room for q[j] can be allocated at the memory location of r[n+j]. +     Finally, round-to-even: +       Shift r left by 1 bit. +       If r > b or if r = b and q[0] is odd, q := q+1. +   */ +  const mp_limb_t *a_ptr = a.limbs; +  size_t a_len = a.nlimbs; +  const mp_limb_t *b_ptr = b.limbs; +  size_t b_len = b.nlimbs; +  mp_limb_t *roomptr; +  mp_limb_t *tmp_roomptr = NULL; +  mp_limb_t *q_ptr; +  size_t q_len; +  mp_limb_t *r_ptr; +  size_t r_len; + +  /* Allocate room for a_len+2 digits. +     (Need a_len+1 digits for the real division and 1 more digit for the +     final rounding of q.)  */ +  roomptr = (mp_limb_t *) malloc ((a_len + 2) * sizeof (mp_limb_t)); +  if (roomptr == NULL) +    return NULL; + +  /* Normalise a.  */ +  while (a_len > 0 && a_ptr[a_len - 1] == 0) +    a_len--; + +  /* Normalise b.  */ +  for (;;) +    { +      if (b_len == 0) +        /* Division by zero.  */ +        abort (); +      if (b_ptr[b_len - 1] == 0) +        b_len--; +      else +        break; +    } + +  /* Here m = a_len >= 0 and n = b_len > 0.  */ + +  if (a_len < b_len) +    { +      /* m<n: trivial case.  q=0, r := copy of a.  */ +      r_ptr = roomptr; +      r_len = a_len; +      memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t)); +      q_ptr = roomptr + a_len; +      q_len = 0; +    } +  else if (b_len == 1) +    { +      /* n=1: single precision division. +         beta^(m-1) <= a < beta^m  ==>  beta^(m-2) <= a/b < beta^m  */ +      r_ptr = roomptr; +      q_ptr = roomptr + 1; +      { +        mp_limb_t den = b_ptr[0]; +        mp_limb_t remainder = 0; +        const mp_limb_t *sourceptr = a_ptr + a_len; +        mp_limb_t *destptr = q_ptr + a_len; +        size_t count; +        for (count = a_len; count > 0; count--) +          { +            mp_twolimb_t num = +              ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--sourceptr; +            *--destptr = num / den; +            remainder = num % den; +          } +        /* Normalise and store r.  */ +        if (remainder > 0) +          { +            r_ptr[0] = remainder; +            r_len = 1; +          } +        else +          r_len = 0; +        /* Normalise q.  */ +        q_len = a_len; +        if (q_ptr[q_len - 1] == 0) +          q_len--; +      } +    } +  else +    { +      /* n>1: multiple precision division. +         beta^(m-1) <= a < beta^m, beta^(n-1) <= b < beta^n  ==> +         beta^(m-n-1) <= a/b < beta^(m-n+1).  */ +      /* Determine s.  */ +      size_t s; +      { +        mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */ +        /* Determine s = GMP_LIMB_BITS - integer_length (msd). +           Code copied from gnulib's integer_length.c.  */ +# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +        s = __builtin_clz (msd); +# else +#  if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT +        if (GMP_LIMB_BITS <= DBL_MANT_BIT) +          { +            /* Use 'double' operations. +               Assumes an IEEE 754 'double' implementation.  */ +#   define DBL_EXP_MASK ((DBL_MAX_EXP - DBL_MIN_EXP) | 7) +#   define DBL_EXP_BIAS (DBL_EXP_MASK / 2 - 1) +#   define NWORDS \ +     ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) +            union { double value; unsigned int word[NWORDS]; } m; + +            /* Use a single integer to floating-point conversion.  */ +            m.value = msd; + +            s = GMP_LIMB_BITS +                - (((m.word[DBL_EXPBIT0_WORD] >> DBL_EXPBIT0_BIT) & DBL_EXP_MASK) +                   - DBL_EXP_BIAS); +          } +        else +#   undef NWORDS +#  endif +          { +            s = 31; +            if (msd >= 0x10000) +              { +                msd = msd >> 16; +                s -= 16; +              } +            if (msd >= 0x100) +              { +                msd = msd >> 8; +                s -= 8; +              } +            if (msd >= 0x10) +              { +                msd = msd >> 4; +                s -= 4; +              } +            if (msd >= 0x4) +              { +                msd = msd >> 2; +                s -= 2; +              } +            if (msd >= 0x2) +              { +                msd = msd >> 1; +                s -= 1; +              } +          } +# endif +      } +      /* 0 <= s < GMP_LIMB_BITS. +         Copy b, shifting it left by s bits.  */ +      if (s > 0) +        { +          tmp_roomptr = (mp_limb_t *) malloc (b_len * sizeof (mp_limb_t)); +          if (tmp_roomptr == NULL) +            { +              free (roomptr); +              return NULL; +            } +          { +            const mp_limb_t *sourceptr = b_ptr; +            mp_limb_t *destptr = tmp_roomptr; +            mp_twolimb_t accu = 0; +            size_t count; +            for (count = b_len; count > 0; count--) +              { +                accu += (mp_twolimb_t) *sourceptr++ << s; +                *destptr++ = (mp_limb_t) accu; +                accu = accu >> GMP_LIMB_BITS; +              } +            /* accu must be zero, since that was how s was determined.  */ +            if (accu != 0) +              abort (); +          } +          b_ptr = tmp_roomptr; +        } +      /* Copy a, shifting it left by s bits, yields r. +         Memory layout: +         At the beginning: r = roomptr[0..a_len], +         at the end: r = roomptr[0..b_len-1], q = roomptr[b_len..a_len]  */ +      r_ptr = roomptr; +      if (s == 0) +        { +          memcpy (r_ptr, a_ptr, a_len * sizeof (mp_limb_t)); +          r_ptr[a_len] = 0; +        } +      else +        { +          const mp_limb_t *sourceptr = a_ptr; +          mp_limb_t *destptr = r_ptr; +          mp_twolimb_t accu = 0; +          size_t count; +          for (count = a_len; count > 0; count--) +            { +              accu += (mp_twolimb_t) *sourceptr++ << s; +              *destptr++ = (mp_limb_t) accu; +              accu = accu >> GMP_LIMB_BITS; +            } +          *destptr++ = (mp_limb_t) accu; +        } +      q_ptr = roomptr + b_len; +      q_len = a_len - b_len + 1; /* q will have m-n+1 limbs */ +      { +        size_t j = a_len - b_len; /* m-n */ +        mp_limb_t b_msd = b_ptr[b_len - 1]; /* b[n-1] */ +        mp_limb_t b_2msd = b_ptr[b_len - 2]; /* b[n-2] */ +        mp_twolimb_t b_msdd = /* b[n-1]*beta+b[n-2] */ +          ((mp_twolimb_t) b_msd << GMP_LIMB_BITS) | b_2msd; +        /* Division loop, traversed m-n+1 times. +           j counts down, b is unchanged, beta/2 <= b[n-1] < beta.  */ +        for (;;) +          { +            mp_limb_t q_star; +            mp_limb_t c1; +            if (r_ptr[j + b_len] < b_msd) /* r[j+n] < b[n-1] ? */ +              { +                /* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow.  */ +                mp_twolimb_t num = +                  ((mp_twolimb_t) r_ptr[j + b_len] << GMP_LIMB_BITS) +                  | r_ptr[j + b_len - 1]; +                q_star = num / b_msd; +                c1 = num % b_msd; +              } +            else +              { +                /* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-1].  */ +                q_star = (mp_limb_t)~(mp_limb_t)0; /* q* = beta-1 */ +                /* Test whether r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] >= beta +                   <==> r[j+n]*beta+r[j+n-1] + b[n-1] >= beta*b[n-1]+beta +                   <==> b[n-1] < floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) +                        {<= beta !}. +                   If yes, jump directly to the subtraction loop. +                   (Otherwise, r[j+n]*beta+r[j+n-1] - (beta-1)*b[n-1] < beta +                    <==> floor((r[j+n]*beta+r[j+n-1]+b[n-1])/beta) = b[n-1] ) */ +                if (r_ptr[j + b_len] > b_msd +                    || (c1 = r_ptr[j + b_len - 1] + b_msd) < b_msd) +                  /* r[j+n] >= b[n-1]+1 or +                     r[j+n] = b[n-1] and the addition r[j+n-1]+b[n-1] gives a +                     carry.  */ +                  goto subtract; +              } +            /* q_star = q*, +               c1 = (r[j+n]*beta+r[j+n-1]) - q* * b[n-1] (>=0, <beta).  */ +            { +              mp_twolimb_t c2 = /* c1*beta+r[j+n-2] */ +                ((mp_twolimb_t) c1 << GMP_LIMB_BITS) | r_ptr[j + b_len - 2]; +              mp_twolimb_t c3 = /* b[n-2] * q* */ +                (mp_twolimb_t) b_2msd * (mp_twolimb_t) q_star; +              /* While c2 < c3, increase c2 and decrease c3. +                 Consider c3-c2.  While it is > 0, decrease it by +                 b[n-1]*beta+b[n-2].  Because of b[n-1]*beta+b[n-2] >= beta^2/2 +                 this can happen only twice.  */ +              if (c3 > c2) +                { +                  q_star = q_star - 1; /* q* := q* - 1 */ +                  if (c3 - c2 > b_msdd) +                    q_star = q_star - 1; /* q* := q* - 1 */ +                } +            } +            if (q_star > 0) +              subtract: +              { +                /* Subtract r := r - b * q* * beta^j.  */ +                mp_limb_t cr; +                { +                  const mp_limb_t *sourceptr = b_ptr; +                  mp_limb_t *destptr = r_ptr + j; +                  mp_twolimb_t carry = 0; +                  size_t count; +                  for (count = b_len; count > 0; count--) +                    { +                      /* Here 0 <= carry <= q*.  */ +                      carry = +                        carry +                        + (mp_twolimb_t) q_star * (mp_twolimb_t) *sourceptr++ +                        + (mp_limb_t) ~(*destptr); +                      /* Here 0 <= carry <= beta*q* + beta-1.  */ +                      *destptr++ = ~(mp_limb_t) carry; +                      carry = carry >> GMP_LIMB_BITS; /* <= q* */ +                    } +                  cr = (mp_limb_t) carry; +                } +                /* Subtract cr from r_ptr[j + b_len], then forget about +                   r_ptr[j + b_len].  */ +                if (cr > r_ptr[j + b_len]) +                  { +                    /* Subtraction gave a carry.  */ +                    q_star = q_star - 1; /* q* := q* - 1 */ +                    /* Add b back.  */ +                    { +                      const mp_limb_t *sourceptr = b_ptr; +                      mp_limb_t *destptr = r_ptr + j; +                      mp_limb_t carry = 0; +                      size_t count; +                      for (count = b_len; count > 0; count--) +                        { +                          mp_limb_t source1 = *sourceptr++; +                          mp_limb_t source2 = *destptr; +                          *destptr++ = source1 + source2 + carry; +                          carry = +                            (carry +                             ? source1 >= (mp_limb_t) ~source2 +                             : source1 > (mp_limb_t) ~source2); +                        } +                    } +                    /* Forget about the carry and about r[j+n].  */ +                  } +              } +            /* q* is determined.  Store it as q[j].  */ +            q_ptr[j] = q_star; +            if (j == 0) +              break; +            j--; +          } +      } +      r_len = b_len; +      /* Normalise q.  */ +      if (q_ptr[q_len - 1] == 0) +        q_len--; +# if 0 /* Not needed here, since we need r only to compare it with b/2, and +          b is shifted left by s bits.  */ +      /* Shift r right by s bits.  */ +      if (s > 0) +        { +          mp_limb_t ptr = r_ptr + r_len; +          mp_twolimb_t accu = 0; +          size_t count; +          for (count = r_len; count > 0; count--) +            { +              accu = (mp_twolimb_t) (mp_limb_t) accu << GMP_LIMB_BITS; +              accu += (mp_twolimb_t) *--ptr << (GMP_LIMB_BITS - s); +              *ptr = (mp_limb_t) (accu >> GMP_LIMB_BITS); +            } +        } +# endif +      /* Normalise r.  */ +      while (r_len > 0 && r_ptr[r_len - 1] == 0) +        r_len--; +    } +  /* Compare r << 1 with b.  */ +  if (r_len > b_len) +    goto increment_q; +  { +    size_t i; +    for (i = b_len;;) +      { +        mp_limb_t r_i = +          (i <= r_len && i > 0 ? r_ptr[i - 1] >> (GMP_LIMB_BITS - 1) : 0) +          | (i < r_len ? r_ptr[i] << 1 : 0); +        mp_limb_t b_i = (i < b_len ? b_ptr[i] : 0); +        if (r_i > b_i) +          goto increment_q; +        if (r_i < b_i) +          goto keep_q; +        if (i == 0) +          break; +        i--; +      } +  } +  if (q_len > 0 && ((q_ptr[0] & 1) != 0)) +    /* q is odd.  */ +    increment_q: +    { +      size_t i; +      for (i = 0; i < q_len; i++) +        if (++(q_ptr[i]) != 0) +          goto keep_q; +      q_ptr[q_len++] = 1; +    } +  keep_q: +  if (tmp_roomptr != NULL) +    free (tmp_roomptr); +  q->limbs = q_ptr; +  q->nlimbs = q_len; +  return roomptr; +} + +/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal +   representation. +   Destroys the contents of a. +   Return the allocated memory - containing the decimal digits in low-to-high +   order, terminated with a NUL character - in case of success, NULL in case +   of memory allocation failure.  */ +static char * +convert_to_decimal (mpn_t a, size_t extra_zeroes) +{ +  mp_limb_t *a_ptr = a.limbs; +  size_t a_len = a.nlimbs; +  /* 0.03345 is slightly larger than log(2)/(9*log(10)).  */ +  size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1); +  char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes)); +  if (c_ptr != NULL) +    { +      char *d_ptr = c_ptr; +      for (; extra_zeroes > 0; extra_zeroes--) +        *d_ptr++ = '0'; +      while (a_len > 0) +        { +          /* Divide a by 10^9, in-place.  */ +          mp_limb_t remainder = 0; +          mp_limb_t *ptr = a_ptr + a_len; +          size_t count; +          for (count = a_len; count > 0; count--) +            { +              mp_twolimb_t num = +                ((mp_twolimb_t) remainder << GMP_LIMB_BITS) | *--ptr; +              *ptr = num / 1000000000; +              remainder = num % 1000000000; +            } +          /* Store the remainder as 9 decimal digits.  */ +          for (count = 9; count > 0; count--) +            { +              *d_ptr++ = '0' + (remainder % 10); +              remainder = remainder / 10; +            } +          /* Normalize a.  */ +          if (a_ptr[a_len - 1] == 0) +            a_len--; +        } +      /* Remove leading zeroes.  */ +      while (d_ptr > c_ptr && d_ptr[-1] == '0') +        d_ptr--; +      /* But keep at least one zero.  */ +      if (d_ptr == c_ptr) +        *d_ptr++ = '0'; +      /* Terminate the string.  */ +      *d_ptr = '\0'; +    } +  return c_ptr; +} + +# if NEED_PRINTF_LONG_DOUBLE + +/* Assuming x is finite and >= 0: +   write x as x = 2^e * m, where m is a bignum. +   Return the allocated memory in case of success, NULL in case of memory +   allocation failure.  */ +static void * +decode_long_double (long double x, int *ep, mpn_t *mp) +{ +  mpn_t m; +  int exp; +  long double y; +  size_t i; + +  /* Allocate memory for result.  */ +  m.nlimbs = (LDBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; +  m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t)); +  if (m.limbs == NULL) +    return NULL; +  /* Split into exponential part and mantissa.  */ +  y = frexpl (x, &exp); +  if (!(y >= 0.0L && y < 1.0L)) +    abort (); +  /* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * 2^LDBL_MANT_BIT), and the +     latter is an integer.  */ +  /* Convert the mantissa (y * 2^LDBL_MANT_BIT) to a sequence of limbs. +     I'm not sure whether it's safe to cast a 'long double' value between +     2^31 and 2^32 to 'unsigned int', therefore play safe and cast only +     'long double' values between 0 and 2^16 (to 'unsigned int' or 'int', +     doesn't matter).  */ +#  if (LDBL_MANT_BIT % GMP_LIMB_BITS) != 0 +#   if (LDBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2 +    { +      mp_limb_t hi, lo; +      y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % (GMP_LIMB_BITS / 2)); +      hi = (int) y; +      y -= hi; +      if (!(y >= 0.0L && y < 1.0L)) +        abort (); +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      lo = (int) y; +      y -= lo; +      if (!(y >= 0.0L && y < 1.0L)) +        abort (); +      m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo; +    } +#   else +    { +      mp_limb_t d; +      y *= (mp_limb_t) 1 << (LDBL_MANT_BIT % GMP_LIMB_BITS); +      d = (int) y; +      y -= d; +      if (!(y >= 0.0L && y < 1.0L)) +        abort (); +      m.limbs[LDBL_MANT_BIT / GMP_LIMB_BITS] = d; +    } +#   endif +#  endif +  for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; ) +    { +      mp_limb_t hi, lo; +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      hi = (int) y; +      y -= hi; +      if (!(y >= 0.0L && y < 1.0L)) +        abort (); +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      lo = (int) y; +      y -= lo; +      if (!(y >= 0.0L && y < 1.0L)) +        abort (); +      m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo; +    } +#  if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess +           precision.  */ +  if (!(y == 0.0L)) +    abort (); +#  endif +  /* Normalise.  */ +  while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0) +    m.nlimbs--; +  *mp = m; +  *ep = exp - LDBL_MANT_BIT; +  return m.limbs; +} + +# endif + +# if NEED_PRINTF_DOUBLE + +/* Assuming x is finite and >= 0: +   write x as x = 2^e * m, where m is a bignum. +   Return the allocated memory in case of success, NULL in case of memory +   allocation failure.  */ +static void * +decode_double (double x, int *ep, mpn_t *mp) +{ +  mpn_t m; +  int exp; +  double y; +  size_t i; + +  /* Allocate memory for result.  */ +  m.nlimbs = (DBL_MANT_BIT + GMP_LIMB_BITS - 1) / GMP_LIMB_BITS; +  m.limbs = (mp_limb_t *) malloc (m.nlimbs * sizeof (mp_limb_t)); +  if (m.limbs == NULL) +    return NULL; +  /* Split into exponential part and mantissa.  */ +  y = frexp (x, &exp); +  if (!(y >= 0.0 && y < 1.0)) +    abort (); +  /* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * 2^DBL_MANT_BIT), and the +     latter is an integer.  */ +  /* Convert the mantissa (y * 2^DBL_MANT_BIT) to a sequence of limbs. +     I'm not sure whether it's safe to cast a 'double' value between +     2^31 and 2^32 to 'unsigned int', therefore play safe and cast only +     'double' values between 0 and 2^16 (to 'unsigned int' or 'int', +     doesn't matter).  */ +#  if (DBL_MANT_BIT % GMP_LIMB_BITS) != 0 +#   if (DBL_MANT_BIT % GMP_LIMB_BITS) > GMP_LIMB_BITS / 2 +    { +      mp_limb_t hi, lo; +      y *= (mp_limb_t) 1 << (DBL_MANT_BIT % (GMP_LIMB_BITS / 2)); +      hi = (int) y; +      y -= hi; +      if (!(y >= 0.0 && y < 1.0)) +        abort (); +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      lo = (int) y; +      y -= lo; +      if (!(y >= 0.0 && y < 1.0)) +        abort (); +      m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = (hi << (GMP_LIMB_BITS / 2)) | lo; +    } +#   else +    { +      mp_limb_t d; +      y *= (mp_limb_t) 1 << (DBL_MANT_BIT % GMP_LIMB_BITS); +      d = (int) y; +      y -= d; +      if (!(y >= 0.0 && y < 1.0)) +        abort (); +      m.limbs[DBL_MANT_BIT / GMP_LIMB_BITS] = d; +    } +#   endif +#  endif +  for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; ) +    { +      mp_limb_t hi, lo; +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      hi = (int) y; +      y -= hi; +      if (!(y >= 0.0 && y < 1.0)) +        abort (); +      y *= (mp_limb_t) 1 << (GMP_LIMB_BITS / 2); +      lo = (int) y; +      y -= lo; +      if (!(y >= 0.0 && y < 1.0)) +        abort (); +      m.limbs[--i] = (hi << (GMP_LIMB_BITS / 2)) | lo; +    } +  if (!(y == 0.0)) +    abort (); +  /* Normalise.  */ +  while (m.nlimbs > 0 && m.limbs[m.nlimbs - 1] == 0) +    m.nlimbs--; +  *mp = m; +  *ep = exp - DBL_MANT_BIT; +  return m.limbs; +} + +# endif + +/* Assuming x = 2^e * m is finite and >= 0, and n is an integer: +   Returns the decimal representation of round (x * 10^n). +   Return the allocated memory - containing the decimal digits in low-to-high +   order, terminated with a NUL character - in case of success, NULL in case +   of memory allocation failure.  */ +static char * +scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n) +{ +  int s; +  size_t extra_zeroes; +  unsigned int abs_n; +  unsigned int abs_s; +  mp_limb_t *pow5_ptr; +  size_t pow5_len; +  unsigned int s_limbs; +  unsigned int s_bits; +  mpn_t pow5; +  mpn_t z; +  void *z_memory; +  char *digits; + +  if (memory == NULL) +    return NULL; +  /* x = 2^e * m, hence +     y = round (2^e * 10^n * m) = round (2^(e+n) * 5^n * m) +       = round (2^s * 5^n * m).  */ +  s = e + n; +  extra_zeroes = 0; +  /* Factor out a common power of 10 if possible.  */ +  if (s > 0 && n > 0) +    { +      extra_zeroes = (s < n ? s : n); +      s -= extra_zeroes; +      n -= extra_zeroes; +    } +  /* Here y = round (2^s * 5^n * m) * 10^extra_zeroes. +     Before converting to decimal, we need to compute +     z = round (2^s * 5^n * m).  */ +  /* Compute 5^|n|, possibly shifted by |s| bits if n and s have the same +     sign.  2.322 is slightly larger than log(5)/log(2).  */ +  abs_n = (n >= 0 ? n : -n); +  abs_s = (s >= 0 ? s : -s); +  pow5_ptr = (mp_limb_t *) malloc (((int)(abs_n * (2.322f / GMP_LIMB_BITS)) + 1 +                                    + abs_s / GMP_LIMB_BITS + 1) +                                   * sizeof (mp_limb_t)); +  if (pow5_ptr == NULL) +    { +      free (memory); +      return NULL; +    } +  /* Initialize with 1.  */ +  pow5_ptr[0] = 1; +  pow5_len = 1; +  /* Multiply with 5^|n|.  */ +  if (abs_n > 0) +    { +      static mp_limb_t const small_pow5[13 + 1] = +        { +          1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, +          48828125, 244140625, 1220703125 +        }; +      unsigned int n13; +      for (n13 = 0; n13 <= abs_n; n13 += 13) +        { +          mp_limb_t digit1 = small_pow5[n13 + 13 <= abs_n ? 13 : abs_n - n13]; +          size_t j; +          mp_twolimb_t carry = 0; +          for (j = 0; j < pow5_len; j++) +            { +              mp_limb_t digit2 = pow5_ptr[j]; +              carry += (mp_twolimb_t) digit1 * (mp_twolimb_t) digit2; +              pow5_ptr[j] = (mp_limb_t) carry; +              carry = carry >> GMP_LIMB_BITS; +            } +          if (carry > 0) +            pow5_ptr[pow5_len++] = (mp_limb_t) carry; +        } +    } +  s_limbs = abs_s / GMP_LIMB_BITS; +  s_bits = abs_s % GMP_LIMB_BITS; +  if (n >= 0 ? s >= 0 : s <= 0) +    { +      /* Multiply with 2^|s|.  */ +      if (s_bits > 0) +        { +          mp_limb_t *ptr = pow5_ptr; +          mp_twolimb_t accu = 0; +          size_t count; +          for (count = pow5_len; count > 0; count--) +            { +              accu += (mp_twolimb_t) *ptr << s_bits; +              *ptr++ = (mp_limb_t) accu; +              accu = accu >> GMP_LIMB_BITS; +            } +          if (accu > 0) +            { +              *ptr = (mp_limb_t) accu; +              pow5_len++; +            } +        } +      if (s_limbs > 0) +        { +          size_t count; +          for (count = pow5_len; count > 0;) +            { +              count--; +              pow5_ptr[s_limbs + count] = pow5_ptr[count]; +            } +          for (count = s_limbs; count > 0;) +            { +              count--; +              pow5_ptr[count] = 0; +            } +          pow5_len += s_limbs; +        } +      pow5.limbs = pow5_ptr; +      pow5.nlimbs = pow5_len; +      if (n >= 0) +        { +          /* Multiply m with pow5.  No division needed.  */ +          z_memory = multiply (m, pow5, &z); +        } +      else +        { +          /* Divide m by pow5 and round.  */ +          z_memory = divide (m, pow5, &z); +        } +    } +  else +    { +      pow5.limbs = pow5_ptr; +      pow5.nlimbs = pow5_len; +      if (n >= 0) +        { +          /* n >= 0, s < 0. +             Multiply m with pow5, then divide by 2^|s|.  */ +          mpn_t numerator; +          mpn_t denominator; +          void *tmp_memory; +          tmp_memory = multiply (m, pow5, &numerator); +          if (tmp_memory == NULL) +            { +              free (pow5_ptr); +              free (memory); +              return NULL; +            } +          /* Construct 2^|s|.  */ +          { +            mp_limb_t *ptr = pow5_ptr + pow5_len; +            size_t i; +            for (i = 0; i < s_limbs; i++) +              ptr[i] = 0; +            ptr[s_limbs] = (mp_limb_t) 1 << s_bits; +            denominator.limbs = ptr; +            denominator.nlimbs = s_limbs + 1; +          } +          z_memory = divide (numerator, denominator, &z); +          free (tmp_memory); +        } +      else +        { +          /* n < 0, s > 0. +             Multiply m with 2^s, then divide by pow5.  */ +          mpn_t numerator; +          mp_limb_t *num_ptr; +          num_ptr = (mp_limb_t *) malloc ((m.nlimbs + s_limbs + 1) +                                          * sizeof (mp_limb_t)); +          if (num_ptr == NULL) +            { +              free (pow5_ptr); +              free (memory); +              return NULL; +            } +          { +            mp_limb_t *destptr = num_ptr; +            { +              size_t i; +              for (i = 0; i < s_limbs; i++) +                *destptr++ = 0; +            } +            if (s_bits > 0) +              { +                const mp_limb_t *sourceptr = m.limbs; +                mp_twolimb_t accu = 0; +                size_t count; +                for (count = m.nlimbs; count > 0; count--) +                  { +                    accu += (mp_twolimb_t) *sourceptr++ << s_bits; +                    *destptr++ = (mp_limb_t) accu; +                    accu = accu >> GMP_LIMB_BITS; +                  } +                if (accu > 0) +                  *destptr++ = (mp_limb_t) accu; +              } +            else +              { +                const mp_limb_t *sourceptr = m.limbs; +                size_t count; +                for (count = m.nlimbs; count > 0; count--) +                  *destptr++ = *sourceptr++; +              } +            numerator.limbs = num_ptr; +            numerator.nlimbs = destptr - num_ptr; +          } +          z_memory = divide (numerator, pow5, &z); +          free (num_ptr); +        } +    } +  free (pow5_ptr); +  free (memory); + +  /* Here y = round (x * 10^n) = z * 10^extra_zeroes.  */ + +  if (z_memory == NULL) +    return NULL; +  digits = convert_to_decimal (z, extra_zeroes); +  free (z_memory); +  return digits; +} + +# if NEED_PRINTF_LONG_DOUBLE + +/* Assuming x is finite and >= 0, and n is an integer: +   Returns the decimal representation of round (x * 10^n). +   Return the allocated memory - containing the decimal digits in low-to-high +   order, terminated with a NUL character - in case of success, NULL in case +   of memory allocation failure.  */ +static char * +scale10_round_decimal_long_double (long double x, int n) +{ +  int e IF_LINT(= 0); +  mpn_t m; +  void *memory = decode_long_double (x, &e, &m); +  return scale10_round_decimal_decoded (e, m, memory, n); +} + +# endif + +# if NEED_PRINTF_DOUBLE + +/* Assuming x is finite and >= 0, and n is an integer: +   Returns the decimal representation of round (x * 10^n). +   Return the allocated memory - containing the decimal digits in low-to-high +   order, terminated with a NUL character - in case of success, NULL in case +   of memory allocation failure.  */ +static char * +scale10_round_decimal_double (double x, int n) +{ +  int e IF_LINT(= 0); +  mpn_t m; +  void *memory = decode_double (x, &e, &m); +  return scale10_round_decimal_decoded (e, m, memory, n); +} + +# endif + +# if NEED_PRINTF_LONG_DOUBLE + +/* Assuming x is finite and > 0: +   Return an approximation for n with 10^n <= x < 10^(n+1). +   The approximation is usually the right n, but may be off by 1 sometimes.  */ +static int +floorlog10l (long double x) +{ +  int exp; +  long double y; +  double z; +  double l; + +  /* Split into exponential part and mantissa.  */ +  y = frexpl (x, &exp); +  if (!(y >= 0.0L && y < 1.0L)) +    abort (); +  if (y == 0.0L) +    return INT_MIN; +  if (y < 0.5L) +    { +      while (y < (1.0L / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2)))) +        { +          y *= 1.0L * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2)); +          exp -= GMP_LIMB_BITS; +        } +      if (y < (1.0L / (1 << 16))) +        { +          y *= 1.0L * (1 << 16); +          exp -= 16; +        } +      if (y < (1.0L / (1 << 8))) +        { +          y *= 1.0L * (1 << 8); +          exp -= 8; +        } +      if (y < (1.0L / (1 << 4))) +        { +          y *= 1.0L * (1 << 4); +          exp -= 4; +        } +      if (y < (1.0L / (1 << 2))) +        { +          y *= 1.0L * (1 << 2); +          exp -= 2; +        } +      if (y < (1.0L / (1 << 1))) +        { +          y *= 1.0L * (1 << 1); +          exp -= 1; +        } +    } +  if (!(y >= 0.5L && y < 1.0L)) +    abort (); +  /* Compute an approximation for l = log2(x) = exp + log2(y).  */ +  l = exp; +  z = y; +  if (z < 0.70710678118654752444) +    { +      z *= 1.4142135623730950488; +      l -= 0.5; +    } +  if (z < 0.8408964152537145431) +    { +      z *= 1.1892071150027210667; +      l -= 0.25; +    } +  if (z < 0.91700404320467123175) +    { +      z *= 1.0905077326652576592; +      l -= 0.125; +    } +  if (z < 0.9576032806985736469) +    { +      z *= 1.0442737824274138403; +      l -= 0.0625; +    } +  /* Now 0.95 <= z <= 1.01.  */ +  z = 1 - z; +  /* log2(1-z) = 1/log(2) * (- z - z^2/2 - z^3/3 - z^4/4 - ...) +     Four terms are enough to get an approximation with error < 10^-7.  */ +  l -= 1.4426950408889634074 * z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25))); +  /* Finally multiply with log(2)/log(10), yields an approximation for +     log10(x).  */ +  l *= 0.30102999566398119523; +  /* Round down to the next integer.  */ +  return (int) l + (l < 0 ? -1 : 0); +} + +# endif + +# if NEED_PRINTF_DOUBLE + +/* Assuming x is finite and > 0: +   Return an approximation for n with 10^n <= x < 10^(n+1). +   The approximation is usually the right n, but may be off by 1 sometimes.  */ +static int +floorlog10 (double x) +{ +  int exp; +  double y; +  double z; +  double l; + +  /* Split into exponential part and mantissa.  */ +  y = frexp (x, &exp); +  if (!(y >= 0.0 && y < 1.0)) +    abort (); +  if (y == 0.0) +    return INT_MIN; +  if (y < 0.5) +    { +      while (y < (1.0 / (1 << (GMP_LIMB_BITS / 2)) / (1 << (GMP_LIMB_BITS / 2)))) +        { +          y *= 1.0 * (1 << (GMP_LIMB_BITS / 2)) * (1 << (GMP_LIMB_BITS / 2)); +          exp -= GMP_LIMB_BITS; +        } +      if (y < (1.0 / (1 << 16))) +        { +          y *= 1.0 * (1 << 16); +          exp -= 16; +        } +      if (y < (1.0 / (1 << 8))) +        { +          y *= 1.0 * (1 << 8); +          exp -= 8; +        } +      if (y < (1.0 / (1 << 4))) +        { +          y *= 1.0 * (1 << 4); +          exp -= 4; +        } +      if (y < (1.0 / (1 << 2))) +        { +          y *= 1.0 * (1 << 2); +          exp -= 2; +        } +      if (y < (1.0 / (1 << 1))) +        { +          y *= 1.0 * (1 << 1); +          exp -= 1; +        } +    } +  if (!(y >= 0.5 && y < 1.0)) +    abort (); +  /* Compute an approximation for l = log2(x) = exp + log2(y).  */ +  l = exp; +  z = y; +  if (z < 0.70710678118654752444) +    { +      z *= 1.4142135623730950488; +      l -= 0.5; +    } +  if (z < 0.8408964152537145431) +    { +      z *= 1.1892071150027210667; +      l -= 0.25; +    } +  if (z < 0.91700404320467123175) +    { +      z *= 1.0905077326652576592; +      l -= 0.125; +    } +  if (z < 0.9576032806985736469) +    { +      z *= 1.0442737824274138403; +      l -= 0.0625; +    } +  /* Now 0.95 <= z <= 1.01.  */ +  z = 1 - z; +  /* log2(1-z) = 1/log(2) * (- z - z^2/2 - z^3/3 - z^4/4 - ...) +     Four terms are enough to get an approximation with error < 10^-7.  */ +  l -= 1.4426950408889634074 * z * (1.0 + z * (0.5 + z * ((1.0 / 3) + z * 0.25))); +  /* Finally multiply with log(2)/log(10), yields an approximation for +     log10(x).  */ +  l *= 0.30102999566398119523; +  /* Round down to the next integer.  */ +  return (int) l + (l < 0 ? -1 : 0); +} + +# endif + +/* Tests whether a string of digits consists of exactly PRECISION zeroes and +   a single '1' digit.  */ +static int +is_borderline (const char *digits, size_t precision) +{ +  for (; precision > 0; precision--, digits++) +    if (*digits != '0') +      return 0; +  if (*digits != '1') +    return 0; +  digits++; +  return *digits == '\0'; +} + +#endif + +#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 + +/* Use a different function name, to make it possible that the 'wchar_t' +   parametrization and the 'char' parametrization get compiled in the same +   translation unit.  */ +# if WIDE_CHAR_VERSION +#  define MAX_ROOM_NEEDED wmax_room_needed +# else +#  define MAX_ROOM_NEEDED max_room_needed +# endif + +/* Returns the number of TCHAR_T units needed as temporary space for the result +   of sprintf or SNPRINTF of a single conversion directive.  */ +static size_t +MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion, +                 arg_type type, int flags, size_t width, int has_precision, +                 size_t precision, int pad_ourselves) +{ +  size_t tmp_length; + +  switch (conversion) +    { +    case 'd': case 'i': case 'u': +# if HAVE_LONG_LONG_INT +      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long long) * CHAR_BIT +                          * 0.30103 /* binary -> decimal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +# endif +      if (type == TYPE_LONGINT || type == TYPE_ULONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long) * CHAR_BIT +                          * 0.30103 /* binary -> decimal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +        tmp_length = +          (unsigned int) (sizeof (unsigned int) * CHAR_BIT +                          * 0.30103 /* binary -> decimal */ +                         ) +          + 1; /* turn floor into ceil */ +      if (tmp_length < precision) +        tmp_length = precision; +      /* Multiply by 2, as an estimate for FLAG_GROUP.  */ +      tmp_length = xsum (tmp_length, tmp_length); +      /* Add 1, to account for a leading sign.  */ +      tmp_length = xsum (tmp_length, 1); +      break; + +    case 'o': +# if HAVE_LONG_LONG_INT +      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long long) * CHAR_BIT +                          * 0.333334 /* binary -> octal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +# endif +      if (type == TYPE_LONGINT || type == TYPE_ULONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long) * CHAR_BIT +                          * 0.333334 /* binary -> octal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +        tmp_length = +          (unsigned int) (sizeof (unsigned int) * CHAR_BIT +                          * 0.333334 /* binary -> octal */ +                         ) +          + 1; /* turn floor into ceil */ +      if (tmp_length < precision) +        tmp_length = precision; +      /* Add 1, to account for a leading sign.  */ +      tmp_length = xsum (tmp_length, 1); +      break; + +    case 'x': case 'X': +# if HAVE_LONG_LONG_INT +      if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long long) * CHAR_BIT +                          * 0.25 /* binary -> hexadecimal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +# endif +      if (type == TYPE_LONGINT || type == TYPE_ULONGINT) +        tmp_length = +          (unsigned int) (sizeof (unsigned long) * CHAR_BIT +                          * 0.25 /* binary -> hexadecimal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +        tmp_length = +          (unsigned int) (sizeof (unsigned int) * CHAR_BIT +                          * 0.25 /* binary -> hexadecimal */ +                         ) +          + 1; /* turn floor into ceil */ +      if (tmp_length < precision) +        tmp_length = precision; +      /* Add 2, to account for a leading sign or alternate form.  */ +      tmp_length = xsum (tmp_length, 2); +      break; + +    case 'f': case 'F': +      if (type == TYPE_LONGDOUBLE) +        tmp_length = +          (unsigned int) (LDBL_MAX_EXP +                          * 0.30103 /* binary -> decimal */ +                          * 2 /* estimate for FLAG_GROUP */ +                         ) +          + 1 /* turn floor into ceil */ +          + 10; /* sign, decimal point etc. */ +      else +        tmp_length = +          (unsigned int) (DBL_MAX_EXP +                          * 0.30103 /* binary -> decimal */ +                          * 2 /* estimate for FLAG_GROUP */ +                         ) +          + 1 /* turn floor into ceil */ +          + 10; /* sign, decimal point etc. */ +      tmp_length = xsum (tmp_length, precision); +      break; + +    case 'e': case 'E': case 'g': case 'G': +      tmp_length = +        12; /* sign, decimal point, exponent etc. */ +      tmp_length = xsum (tmp_length, precision); +      break; + +    case 'a': case 'A': +      if (type == TYPE_LONGDOUBLE) +        tmp_length = +          (unsigned int) (LDBL_DIG +                          * 0.831 /* decimal -> hexadecimal */ +                         ) +          + 1; /* turn floor into ceil */ +      else +        tmp_length = +          (unsigned int) (DBL_DIG +                          * 0.831 /* decimal -> hexadecimal */ +                         ) +          + 1; /* turn floor into ceil */ +      if (tmp_length < precision) +        tmp_length = precision; +      /* Account for sign, decimal point etc. */ +      tmp_length = xsum (tmp_length, 12); +      break; + +    case 'c': +# if HAVE_WINT_T && !WIDE_CHAR_VERSION +      if (type == TYPE_WIDE_CHAR) +        tmp_length = MB_CUR_MAX; +      else +# endif +        tmp_length = 1; +      break; + +    case 's': +# if HAVE_WCHAR_T +      if (type == TYPE_WIDE_STRING) +        { +#  if WIDE_CHAR_VERSION +          /* ISO C says about %ls in fwprintf: +               "If the precision is not specified or is greater than the size +                of the array, the array shall contain a null wide character." +             So if there is a precision, we must not use wcslen.  */ +          const wchar_t *arg = ap->arg[arg_index].a.a_wide_string; + +          if (has_precision) +            tmp_length = local_wcsnlen (arg, precision); +          else +            tmp_length = local_wcslen (arg); +#  else +          /* ISO C says about %ls in fprintf: +               "If a precision is specified, no more than that many bytes are +                written (including shift sequences, if any), and the array +                shall contain a null wide character if, to equal the multibyte +                character sequence length given by the precision, the function +                would need to access a wide character one past the end of the +                array." +             So if there is a precision, we must not use wcslen.  */ +          /* This case has already been handled separately in VASNPRINTF.  */ +          abort (); +#  endif +        } +      else +# endif +        { +# if WIDE_CHAR_VERSION +          /* ISO C says about %s in fwprintf: +               "If the precision is not specified or is greater than the size +                of the converted array, the converted array shall contain a +                null wide character." +             So if there is a precision, we must not use strlen.  */ +          /* This case has already been handled separately in VASNPRINTF.  */ +          abort (); +# else +          /* ISO C says about %s in fprintf: +               "If the precision is not specified or greater than the size of +                the array, the array shall contain a null character." +             So if there is a precision, we must not use strlen.  */ +          const char *arg = ap->arg[arg_index].a.a_string; + +          if (has_precision) +            tmp_length = local_strnlen (arg, precision); +          else +            tmp_length = strlen (arg); +# endif +        } +      break; + +    case 'p': +      tmp_length = +        (unsigned int) (sizeof (void *) * CHAR_BIT +                        * 0.25 /* binary -> hexadecimal */ +                       ) +          + 1 /* turn floor into ceil */ +          + 2; /* account for leading 0x */ +      break; + +    default: +      abort (); +    } + +  if (!pad_ourselves) +    { +# if ENABLE_UNISTDIO +      /* Padding considers the number of characters, therefore the number of +         elements after padding may be +           > max (tmp_length, width) +         but is certainly +           <= tmp_length + width.  */ +      tmp_length = xsum (tmp_length, width); +# else +      /* Padding considers the number of elements, says POSIX.  */ +      if (tmp_length < width) +        tmp_length = width; +# endif +    } + +  tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ + +  return tmp_length; +} + +#endif + +DCHAR_T * +VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp, +            const FCHAR_T *format, va_list args) +{ +  DIRECTIVES d; +  arguments a; + +  if (PRINTF_PARSE (format, &d, &a) < 0) +    /* errno is already set.  */ +    return NULL; + +#define CLEANUP() \ +  if (d.dir != d.direct_alloc_dir)                                      \ +    free (d.dir);                                                       \ +  if (a.arg != a.direct_alloc_arg)                                      \ +    free (a.arg); + +  if (PRINTF_FETCHARGS (args, &a) < 0) +    { +      CLEANUP (); +      errno = EINVAL; +      return NULL; +    } + +  { +    size_t buf_neededlength; +    TCHAR_T *buf; +    TCHAR_T *buf_malloced; +    const FCHAR_T *cp; +    size_t i; +    DIRECTIVE *dp; +    /* Output string accumulator.  */ +    DCHAR_T *result; +    size_t allocated; +    size_t length; + +    /* Allocate a small buffer that will hold a directive passed to +       sprintf or snprintf.  */ +    buf_neededlength = +      xsum4 (7, d.max_width_length, d.max_precision_length, 6); +#if HAVE_ALLOCA +    if (buf_neededlength < 4000 / sizeof (TCHAR_T)) +      { +        buf = (TCHAR_T *) alloca (buf_neededlength * sizeof (TCHAR_T)); +        buf_malloced = NULL; +      } +    else +#endif +      { +        size_t buf_memsize = xtimes (buf_neededlength, sizeof (TCHAR_T)); +        if (size_overflow_p (buf_memsize)) +          goto out_of_memory_1; +        buf = (TCHAR_T *) malloc (buf_memsize); +        if (buf == NULL) +          goto out_of_memory_1; +        buf_malloced = buf; +      } + +    if (resultbuf != NULL) +      { +        result = resultbuf; +        allocated = *lengthp; +      } +    else +      { +        result = NULL; +        allocated = 0; +      } +    length = 0; +    /* Invariants: +       result is either == resultbuf or == NULL or malloc-allocated. +       If length > 0, then result != NULL.  */ + +    /* Ensures that allocated >= needed.  Aborts through a jump to +       out_of_memory if needed is SIZE_MAX or otherwise too big.  */ +#define ENSURE_ALLOCATION(needed) \ +    if ((needed) > allocated)                                                \ +      {                                                                      \ +        size_t memory_size;                                                  \ +        DCHAR_T *memory;                                                     \ +                                                                             \ +        allocated = (allocated > 0 ? xtimes (allocated, 2) : 12);            \ +        if ((needed) > allocated)                                            \ +          allocated = (needed);                                              \ +        memory_size = xtimes (allocated, sizeof (DCHAR_T));                  \ +        if (size_overflow_p (memory_size))                                   \ +          goto out_of_memory;                                                \ +        if (result == resultbuf || result == NULL)                           \ +          memory = (DCHAR_T *) malloc (memory_size);                         \ +        else                                                                 \ +          memory = (DCHAR_T *) realloc (result, memory_size);                \ +        if (memory == NULL)                                                  \ +          goto out_of_memory;                                                \ +        if (result == resultbuf && length > 0)                               \ +          DCHAR_CPY (memory, result, length);                                \ +        result = memory;                                                     \ +      } + +    for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) +      { +        if (cp != dp->dir_start) +          { +            size_t n = dp->dir_start - cp; +            size_t augmented_length = xsum (length, n); + +            ENSURE_ALLOCATION (augmented_length); +            /* This copies a piece of FCHAR_T[] into a DCHAR_T[].  Here we +               need that the format string contains only ASCII characters +               if FCHAR_T and DCHAR_T are not the same type.  */ +            if (sizeof (FCHAR_T) == sizeof (DCHAR_T)) +              { +                DCHAR_CPY (result + length, (const DCHAR_T *) cp, n); +                length = augmented_length; +              } +            else +              { +                do +                  result[length++] = (unsigned char) *cp++; +                while (--n > 0); +              } +          } +        if (i == d.count) +          break; + +        /* Execute a single directive.  */ +        if (dp->conversion == '%') +          { +            size_t augmented_length; + +            if (!(dp->arg_index == ARG_NONE)) +              abort (); +            augmented_length = xsum (length, 1); +            ENSURE_ALLOCATION (augmented_length); +            result[length] = '%'; +            length = augmented_length; +          } +        else +          { +            if (!(dp->arg_index != ARG_NONE)) +              abort (); + +            if (dp->conversion == 'n') +              { +                switch (a.arg[dp->arg_index].type) +                  { +                  case TYPE_COUNT_SCHAR_POINTER: +                    *a.arg[dp->arg_index].a.a_count_schar_pointer = length; +                    break; +                  case TYPE_COUNT_SHORT_POINTER: +                    *a.arg[dp->arg_index].a.a_count_short_pointer = length; +                    break; +                  case TYPE_COUNT_INT_POINTER: +                    *a.arg[dp->arg_index].a.a_count_int_pointer = length; +                    break; +                  case TYPE_COUNT_LONGINT_POINTER: +                    *a.arg[dp->arg_index].a.a_count_longint_pointer = length; +                    break; +#if HAVE_LONG_LONG_INT +                  case TYPE_COUNT_LONGLONGINT_POINTER: +                    *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; +                    break; +#endif +                  default: +                    abort (); +                  } +              } +#if ENABLE_UNISTDIO +            /* The unistdio extensions.  */ +            else if (dp->conversion == 'U') +              { +                arg_type type = a.arg[dp->arg_index].type; +                int flags = dp->flags; +                int has_width; +                size_t width; +                int has_precision; +                size_t precision; + +                has_width = 0; +                width = 0; +                if (dp->width_start != dp->width_end) +                  { +                    if (dp->width_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->width_arg_index].a.a_int; +                        if (arg < 0) +                          { +                            /* "A negative field width is taken as a '-' flag +                                followed by a positive field width."  */ +                            flags |= FLAG_LEFT; +                            width = (unsigned int) (-arg); +                          } +                        else +                          width = arg; +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->width_start; + +                        do +                          width = xsum (xtimes (width, 10), *digitp++ - '0'); +                        while (digitp != dp->width_end); +                      } +                    has_width = 1; +                  } + +                has_precision = 0; +                precision = 0; +                if (dp->precision_start != dp->precision_end) +                  { +                    if (dp->precision_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->precision_arg_index].a.a_int; +                        /* "A negative precision is taken as if the precision +                            were omitted."  */ +                        if (arg >= 0) +                          { +                            precision = arg; +                            has_precision = 1; +                          } +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->precision_start + 1; + +                        precision = 0; +                        while (digitp != dp->precision_end) +                          precision = xsum (xtimes (precision, 10), *digitp++ - '0'); +                        has_precision = 1; +                      } +                  } + +                switch (type) +                  { +                  case TYPE_U8_STRING: +                    { +                      const uint8_t *arg = a.arg[dp->arg_index].a.a_u8_string; +                      const uint8_t *arg_end; +                      size_t characters; + +                      if (has_precision) +                        { +                          /* Use only PRECISION characters, from the left.  */ +                          arg_end = arg; +                          characters = 0; +                          for (; precision > 0; precision--) +                            { +                              int count = u8_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else if (has_width) +                        { +                          /* Use the entire string, and count the number of +                             characters.  */ +                          arg_end = arg; +                          characters = 0; +                          for (;;) +                            { +                              int count = u8_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else +                        { +                          /* Use the entire string.  */ +                          arg_end = arg + u8_strlen (arg); +                          /* The number of characters doesn't matter.  */ +                          characters = 0; +                        } + +                      if (has_width && width > characters +                          && !(dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } + +# if DCHAR_IS_UINT8_T +                      { +                        size_t n = arg_end - arg; +                        ENSURE_ALLOCATION (xsum (length, n)); +                        DCHAR_CPY (result + length, arg, n); +                        length += n; +                      } +# else +                      { /* Convert.  */ +                        DCHAR_T *converted = result + length; +                        size_t converted_len = allocated - length; +#  if DCHAR_IS_TCHAR +                        /* Convert from UTF-8 to locale encoding.  */ +                        converted = +                          u8_conv_to_encoding (locale_charset (), +                                               iconveh_question_mark, +                                               arg, arg_end - arg, NULL, +                                               converted, &converted_len); +#  else +                        /* Convert from UTF-8 to UTF-16/UTF-32.  */ +                        converted = +                          U8_TO_DCHAR (arg, arg_end - arg, +                                       converted, &converted_len); +#  endif +                        if (converted == NULL) +                          { +                            int saved_errno = errno; +                            if (!(result == resultbuf || result == NULL)) +                              free (result); +                            if (buf_malloced != NULL) +                              free (buf_malloced); +                            CLEANUP (); +                            errno = saved_errno; +                            return NULL; +                          } +                        if (converted != result + length) +                          { +                            ENSURE_ALLOCATION (xsum (length, converted_len)); +                            DCHAR_CPY (result + length, converted, converted_len); +                            free (converted); +                          } +                        length += converted_len; +                      } +# endif + +                      if (has_width && width > characters +                          && (dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } +                    } +                    break; + +                  case TYPE_U16_STRING: +                    { +                      const uint16_t *arg = a.arg[dp->arg_index].a.a_u16_string; +                      const uint16_t *arg_end; +                      size_t characters; + +                      if (has_precision) +                        { +                          /* Use only PRECISION characters, from the left.  */ +                          arg_end = arg; +                          characters = 0; +                          for (; precision > 0; precision--) +                            { +                              int count = u16_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else if (has_width) +                        { +                          /* Use the entire string, and count the number of +                             characters.  */ +                          arg_end = arg; +                          characters = 0; +                          for (;;) +                            { +                              int count = u16_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else +                        { +                          /* Use the entire string.  */ +                          arg_end = arg + u16_strlen (arg); +                          /* The number of characters doesn't matter.  */ +                          characters = 0; +                        } + +                      if (has_width && width > characters +                          && !(dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } + +# if DCHAR_IS_UINT16_T +                      { +                        size_t n = arg_end - arg; +                        ENSURE_ALLOCATION (xsum (length, n)); +                        DCHAR_CPY (result + length, arg, n); +                        length += n; +                      } +# else +                      { /* Convert.  */ +                        DCHAR_T *converted = result + length; +                        size_t converted_len = allocated - length; +#  if DCHAR_IS_TCHAR +                        /* Convert from UTF-16 to locale encoding.  */ +                        converted = +                          u16_conv_to_encoding (locale_charset (), +                                                iconveh_question_mark, +                                                arg, arg_end - arg, NULL, +                                                converted, &converted_len); +#  else +                        /* Convert from UTF-16 to UTF-8/UTF-32.  */ +                        converted = +                          U16_TO_DCHAR (arg, arg_end - arg, +                                        converted, &converted_len); +#  endif +                        if (converted == NULL) +                          { +                            int saved_errno = errno; +                            if (!(result == resultbuf || result == NULL)) +                              free (result); +                            if (buf_malloced != NULL) +                              free (buf_malloced); +                            CLEANUP (); +                            errno = saved_errno; +                            return NULL; +                          } +                        if (converted != result + length) +                          { +                            ENSURE_ALLOCATION (xsum (length, converted_len)); +                            DCHAR_CPY (result + length, converted, converted_len); +                            free (converted); +                          } +                        length += converted_len; +                      } +# endif + +                      if (has_width && width > characters +                          && (dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } +                    } +                    break; + +                  case TYPE_U32_STRING: +                    { +                      const uint32_t *arg = a.arg[dp->arg_index].a.a_u32_string; +                      const uint32_t *arg_end; +                      size_t characters; + +                      if (has_precision) +                        { +                          /* Use only PRECISION characters, from the left.  */ +                          arg_end = arg; +                          characters = 0; +                          for (; precision > 0; precision--) +                            { +                              int count = u32_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else if (has_width) +                        { +                          /* Use the entire string, and count the number of +                             characters.  */ +                          arg_end = arg; +                          characters = 0; +                          for (;;) +                            { +                              int count = u32_strmblen (arg_end); +                              if (count == 0) +                                break; +                              if (count < 0) +                                { +                                  if (!(result == resultbuf || result == NULL)) +                                    free (result); +                                  if (buf_malloced != NULL) +                                    free (buf_malloced); +                                  CLEANUP (); +                                  errno = EILSEQ; +                                  return NULL; +                                } +                              arg_end += count; +                              characters++; +                            } +                        } +                      else +                        { +                          /* Use the entire string.  */ +                          arg_end = arg + u32_strlen (arg); +                          /* The number of characters doesn't matter.  */ +                          characters = 0; +                        } + +                      if (has_width && width > characters +                          && !(dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } + +# if DCHAR_IS_UINT32_T +                      { +                        size_t n = arg_end - arg; +                        ENSURE_ALLOCATION (xsum (length, n)); +                        DCHAR_CPY (result + length, arg, n); +                        length += n; +                      } +# else +                      { /* Convert.  */ +                        DCHAR_T *converted = result + length; +                        size_t converted_len = allocated - length; +#  if DCHAR_IS_TCHAR +                        /* Convert from UTF-32 to locale encoding.  */ +                        converted = +                          u32_conv_to_encoding (locale_charset (), +                                                iconveh_question_mark, +                                                arg, arg_end - arg, NULL, +                                                converted, &converted_len); +#  else +                        /* Convert from UTF-32 to UTF-8/UTF-16.  */ +                        converted = +                          U32_TO_DCHAR (arg, arg_end - arg, +                                        converted, &converted_len); +#  endif +                        if (converted == NULL) +                          { +                            int saved_errno = errno; +                            if (!(result == resultbuf || result == NULL)) +                              free (result); +                            if (buf_malloced != NULL) +                              free (buf_malloced); +                            CLEANUP (); +                            errno = saved_errno; +                            return NULL; +                          } +                        if (converted != result + length) +                          { +                            ENSURE_ALLOCATION (xsum (length, converted_len)); +                            DCHAR_CPY (result + length, converted, converted_len); +                            free (converted); +                          } +                        length += converted_len; +                      } +# endif + +                      if (has_width && width > characters +                          && (dp->flags & FLAG_LEFT)) +                        { +                          size_t n = width - characters; +                          ENSURE_ALLOCATION (xsum (length, n)); +                          DCHAR_SET (result + length, ' ', n); +                          length += n; +                        } +                    } +                    break; + +                  default: +                    abort (); +                  } +              } +#endif +#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T +            else if (dp->conversion == 's' +# if WIDE_CHAR_VERSION +                     && a.arg[dp->arg_index].type != TYPE_WIDE_STRING +# else +                     && a.arg[dp->arg_index].type == TYPE_WIDE_STRING +# endif +                    ) +              { +                /* The normal handling of the 's' directive below requires +                   allocating a temporary buffer.  The determination of its +                   length (tmp_length), in the case when a precision is +                   specified, below requires a conversion between a char[] +                   string and a wchar_t[] wide string.  It could be done, but +                   we have no guarantee that the implementation of sprintf will +                   use the exactly same algorithm.  Without this guarantee, it +                   is possible to have buffer overrun bugs.  In order to avoid +                   such bugs, we implement the entire processing of the 's' +                   directive ourselves.  */ +                int flags = dp->flags; +                int has_width; +                size_t width; +                int has_precision; +                size_t precision; + +                has_width = 0; +                width = 0; +                if (dp->width_start != dp->width_end) +                  { +                    if (dp->width_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->width_arg_index].a.a_int; +                        if (arg < 0) +                          { +                            /* "A negative field width is taken as a '-' flag +                                followed by a positive field width."  */ +                            flags |= FLAG_LEFT; +                            width = (unsigned int) (-arg); +                          } +                        else +                          width = arg; +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->width_start; + +                        do +                          width = xsum (xtimes (width, 10), *digitp++ - '0'); +                        while (digitp != dp->width_end); +                      } +                    has_width = 1; +                  } + +                has_precision = 0; +                precision = 6; +                if (dp->precision_start != dp->precision_end) +                  { +                    if (dp->precision_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->precision_arg_index].a.a_int; +                        /* "A negative precision is taken as if the precision +                            were omitted."  */ +                        if (arg >= 0) +                          { +                            precision = arg; +                            has_precision = 1; +                          } +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->precision_start + 1; + +                        precision = 0; +                        while (digitp != dp->precision_end) +                          precision = xsum (xtimes (precision, 10), *digitp++ - '0'); +                        has_precision = 1; +                      } +                  } + +# if WIDE_CHAR_VERSION +                /* %s in vasnwprintf.  See the specification of fwprintf.  */ +                { +                  const char *arg = a.arg[dp->arg_index].a.a_string; +                  const char *arg_end; +                  size_t characters; + +                  if (has_precision) +                    { +                      /* Use only as many bytes as needed to produce PRECISION +                         wide characters, from the left.  */ +#  if HAVE_MBRTOWC +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      arg_end = arg; +                      characters = 0; +                      for (; precision > 0; precision--) +                        { +                          int count; +#  if HAVE_MBRTOWC +                          count = mbrlen (arg_end, MB_CUR_MAX, &state); +#  else +                          count = mblen (arg_end, MB_CUR_MAX); +#  endif +                          if (count == 0) +                            /* Found the terminating NUL.  */ +                            break; +                          if (count < 0) +                            { +                              /* Invalid or incomplete multibyte character.  */ +                              if (!(result == resultbuf || result == NULL)) +                                free (result); +                              if (buf_malloced != NULL) +                                free (buf_malloced); +                              CLEANUP (); +                              errno = EILSEQ; +                              return NULL; +                            } +                          arg_end += count; +                          characters++; +                        } +                    } +                  else if (has_width) +                    { +                      /* Use the entire string, and count the number of wide +                         characters.  */ +#  if HAVE_MBRTOWC +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      arg_end = arg; +                      characters = 0; +                      for (;;) +                        { +                          int count; +#  if HAVE_MBRTOWC +                          count = mbrlen (arg_end, MB_CUR_MAX, &state); +#  else +                          count = mblen (arg_end, MB_CUR_MAX); +#  endif +                          if (count == 0) +                            /* Found the terminating NUL.  */ +                            break; +                          if (count < 0) +                            { +                              /* Invalid or incomplete multibyte character.  */ +                              if (!(result == resultbuf || result == NULL)) +                                free (result); +                              if (buf_malloced != NULL) +                                free (buf_malloced); +                              CLEANUP (); +                              errno = EILSEQ; +                              return NULL; +                            } +                          arg_end += count; +                          characters++; +                        } +                    } +                  else +                    { +                      /* Use the entire string.  */ +                      arg_end = arg + strlen (arg); +                      /* The number of characters doesn't matter.  */ +                      characters = 0; +                    } + +                  if (has_width && width > characters +                      && !(dp->flags & FLAG_LEFT)) +                    { +                      size_t n = width - characters; +                      ENSURE_ALLOCATION (xsum (length, n)); +                      DCHAR_SET (result + length, ' ', n); +                      length += n; +                    } + +                  if (has_precision || has_width) +                    { +                      /* We know the number of wide characters in advance.  */ +                      size_t remaining; +#  if HAVE_MBRTOWC +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      ENSURE_ALLOCATION (xsum (length, characters)); +                      for (remaining = characters; remaining > 0; remaining--) +                        { +                          wchar_t wc; +                          int count; +#  if HAVE_MBRTOWC +                          count = mbrtowc (&wc, arg, arg_end - arg, &state); +#  else +                          count = mbtowc (&wc, arg, arg_end - arg); +#  endif +                          if (count <= 0) +                            /* mbrtowc not consistent with mbrlen, or mbtowc +                               not consistent with mblen.  */ +                            abort (); +                          result[length++] = wc; +                          arg += count; +                        } +                      if (!(arg == arg_end)) +                        abort (); +                    } +                  else +                    { +#  if HAVE_MBRTOWC +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      while (arg < arg_end) +                        { +                          wchar_t wc; +                          int count; +#  if HAVE_MBRTOWC +                          count = mbrtowc (&wc, arg, arg_end - arg, &state); +#  else +                          count = mbtowc (&wc, arg, arg_end - arg); +#  endif +                          if (count <= 0) +                            /* mbrtowc not consistent with mbrlen, or mbtowc +                               not consistent with mblen.  */ +                            abort (); +                          ENSURE_ALLOCATION (xsum (length, 1)); +                          result[length++] = wc; +                          arg += count; +                        } +                    } + +                  if (has_width && width > characters +                      && (dp->flags & FLAG_LEFT)) +                    { +                      size_t n = width - characters; +                      ENSURE_ALLOCATION (xsum (length, n)); +                      DCHAR_SET (result + length, ' ', n); +                      length += n; +                    } +                } +# else +                /* %ls in vasnprintf.  See the specification of fprintf.  */ +                { +                  const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; +                  const wchar_t *arg_end; +                  size_t characters; +#  if !DCHAR_IS_TCHAR +                  /* This code assumes that TCHAR_T is 'char'.  */ +                  verify (sizeof (TCHAR_T) == 1); +                  TCHAR_T *tmpsrc; +                  DCHAR_T *tmpdst; +                  size_t tmpdst_len; +#  endif +                  size_t w; + +                  if (has_precision) +                    { +                      /* Use only as many wide characters as needed to produce +                         at most PRECISION bytes, from the left.  */ +#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      arg_end = arg; +                      characters = 0; +                      while (precision > 0) +                        { +                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */ +                          int count; + +                          if (*arg_end == 0) +                            /* Found the terminating null wide character.  */ +                            break; +#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                          count = wcrtomb (cbuf, *arg_end, &state); +#  else +                          count = wctomb (cbuf, *arg_end); +#  endif +                          if (count < 0) +                            { +                              /* Cannot convert.  */ +                              if (!(result == resultbuf || result == NULL)) +                                free (result); +                              if (buf_malloced != NULL) +                                free (buf_malloced); +                              CLEANUP (); +                              errno = EILSEQ; +                              return NULL; +                            } +                          if (precision < count) +                            break; +                          arg_end++; +                          characters += count; +                          precision -= count; +                        } +                    } +#  if DCHAR_IS_TCHAR +                  else if (has_width) +#  else +                  else +#  endif +                    { +                      /* Use the entire string, and count the number of +                         bytes.  */ +#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#  endif +                      arg_end = arg; +                      characters = 0; +                      for (;;) +                        { +                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */ +                          int count; + +                          if (*arg_end == 0) +                            /* Found the terminating null wide character.  */ +                            break; +#  if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                          count = wcrtomb (cbuf, *arg_end, &state); +#  else +                          count = wctomb (cbuf, *arg_end); +#  endif +                          if (count < 0) +                            { +                              /* Cannot convert.  */ +                              if (!(result == resultbuf || result == NULL)) +                                free (result); +                              if (buf_malloced != NULL) +                                free (buf_malloced); +                              CLEANUP (); +                              errno = EILSEQ; +                              return NULL; +                            } +                          arg_end++; +                          characters += count; +                        } +                    } +#  if DCHAR_IS_TCHAR +                  else +                    { +                      /* Use the entire string.  */ +                      arg_end = arg + local_wcslen (arg); +                      /* The number of bytes doesn't matter.  */ +                      characters = 0; +                    } +#  endif + +#  if !DCHAR_IS_TCHAR +                  /* Convert the string into a piece of temporary memory.  */ +                  tmpsrc = (TCHAR_T *) malloc (characters * sizeof (TCHAR_T)); +                  if (tmpsrc == NULL) +                    goto out_of_memory; +                  { +                    TCHAR_T *tmpptr = tmpsrc; +                    size_t remaining; +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                    mbstate_t state; +                    memset (&state, '\0', sizeof (mbstate_t)); +#   endif +                    for (remaining = characters; remaining > 0; ) +                      { +                        char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */ +                        int count; + +                        if (*arg == 0) +                          abort (); +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                        count = wcrtomb (cbuf, *arg, &state); +#   else +                        count = wctomb (cbuf, *arg); +#   endif +                        if (count <= 0) +                          /* Inconsistency.  */ +                          abort (); +                        memcpy (tmpptr, cbuf, count); +                        tmpptr += count; +                        arg++; +                        remaining -= count; +                      } +                    if (!(arg == arg_end)) +                      abort (); +                  } + +                  /* Convert from TCHAR_T[] to DCHAR_T[].  */ +                  tmpdst = +                    DCHAR_CONV_FROM_ENCODING (locale_charset (), +                                              iconveh_question_mark, +                                              tmpsrc, characters, +                                              NULL, +                                              NULL, &tmpdst_len); +                  if (tmpdst == NULL) +                    { +                      int saved_errno = errno; +                      free (tmpsrc); +                      if (!(result == resultbuf || result == NULL)) +                        free (result); +                      if (buf_malloced != NULL) +                        free (buf_malloced); +                      CLEANUP (); +                      errno = saved_errno; +                      return NULL; +                    } +                  free (tmpsrc); +#  endif + +                  if (has_width) +                    { +#  if ENABLE_UNISTDIO +                      /* Outside POSIX, it's preferable to compare the width +                         against the number of _characters_ of the converted +                         value.  */ +                      w = DCHAR_MBSNLEN (result + length, characters); +#  else +                      /* The width is compared against the number of _bytes_ +                         of the converted value, says POSIX.  */ +                      w = characters; +#  endif +                    } +                  else +                    /* w doesn't matter.  */ +                    w = 0; + +                  if (has_width && width > w +                      && !(dp->flags & FLAG_LEFT)) +                    { +                      size_t n = width - w; +                      ENSURE_ALLOCATION (xsum (length, n)); +                      DCHAR_SET (result + length, ' ', n); +                      length += n; +                    } + +#  if DCHAR_IS_TCHAR +                  if (has_precision || has_width) +                    { +                      /* We know the number of bytes in advance.  */ +                      size_t remaining; +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#   endif +                      ENSURE_ALLOCATION (xsum (length, characters)); +                      for (remaining = characters; remaining > 0; ) +                        { +                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */ +                          int count; + +                          if (*arg == 0) +                            abort (); +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                          count = wcrtomb (cbuf, *arg, &state); +#   else +                          count = wctomb (cbuf, *arg); +#   endif +                          if (count <= 0) +                            /* Inconsistency.  */ +                            abort (); +                          memcpy (result + length, cbuf, count); +                          length += count; +                          arg++; +                          remaining -= count; +                        } +                      if (!(arg == arg_end)) +                        abort (); +                    } +                  else +                    { +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                      mbstate_t state; +                      memset (&state, '\0', sizeof (mbstate_t)); +#   endif +                      while (arg < arg_end) +                        { +                          char cbuf[64]; /* Assume MB_CUR_MAX <= 64.  */ +                          int count; + +                          if (*arg == 0) +                            abort (); +#   if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t +                          count = wcrtomb (cbuf, *arg, &state); +#   else +                          count = wctomb (cbuf, *arg); +#   endif +                          if (count <= 0) +                            { +                              /* Cannot convert.  */ +                              if (!(result == resultbuf || result == NULL)) +                                free (result); +                              if (buf_malloced != NULL) +                                free (buf_malloced); +                              CLEANUP (); +                              errno = EILSEQ; +                              return NULL; +                            } +                          ENSURE_ALLOCATION (xsum (length, count)); +                          memcpy (result + length, cbuf, count); +                          length += count; +                          arg++; +                        } +                    } +#  else +                  ENSURE_ALLOCATION (xsum (length, tmpdst_len)); +                  DCHAR_CPY (result + length, tmpdst, tmpdst_len); +                  free (tmpdst); +                  length += tmpdst_len; +#  endif + +                  if (has_width && width > w +                      && (dp->flags & FLAG_LEFT)) +                    { +                      size_t n = width - w; +                      ENSURE_ALLOCATION (xsum (length, n)); +                      DCHAR_SET (result + length, ' ', n); +                      length += n; +                    } +                } +# endif +              } +#endif +#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL +            else if ((dp->conversion == 'a' || dp->conversion == 'A') +# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) +                     && (0 +#  if NEED_PRINTF_DOUBLE +                         || a.arg[dp->arg_index].type == TYPE_DOUBLE +#  endif +#  if NEED_PRINTF_LONG_DOUBLE +                         || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE +#  endif +                        ) +# endif +                    ) +              { +                arg_type type = a.arg[dp->arg_index].type; +                int flags = dp->flags; +                int has_width; +                size_t width; +                int has_precision; +                size_t precision; +                size_t tmp_length; +                DCHAR_T tmpbuf[700]; +                DCHAR_T *tmp; +                DCHAR_T *pad_ptr; +                DCHAR_T *p; + +                has_width = 0; +                width = 0; +                if (dp->width_start != dp->width_end) +                  { +                    if (dp->width_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->width_arg_index].a.a_int; +                        if (arg < 0) +                          { +                            /* "A negative field width is taken as a '-' flag +                                followed by a positive field width."  */ +                            flags |= FLAG_LEFT; +                            width = (unsigned int) (-arg); +                          } +                        else +                          width = arg; +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->width_start; + +                        do +                          width = xsum (xtimes (width, 10), *digitp++ - '0'); +                        while (digitp != dp->width_end); +                      } +                    has_width = 1; +                  } + +                has_precision = 0; +                precision = 0; +                if (dp->precision_start != dp->precision_end) +                  { +                    if (dp->precision_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->precision_arg_index].a.a_int; +                        /* "A negative precision is taken as if the precision +                            were omitted."  */ +                        if (arg >= 0) +                          { +                            precision = arg; +                            has_precision = 1; +                          } +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->precision_start + 1; + +                        precision = 0; +                        while (digitp != dp->precision_end) +                          precision = xsum (xtimes (precision, 10), *digitp++ - '0'); +                        has_precision = 1; +                      } +                  } + +                /* Allocate a temporary buffer of sufficient size.  */ +                if (type == TYPE_LONGDOUBLE) +                  tmp_length = +                    (unsigned int) ((LDBL_DIG + 1) +                                    * 0.831 /* decimal -> hexadecimal */ +                                   ) +                    + 1; /* turn floor into ceil */ +                else +                  tmp_length = +                    (unsigned int) ((DBL_DIG + 1) +                                    * 0.831 /* decimal -> hexadecimal */ +                                   ) +                    + 1; /* turn floor into ceil */ +                if (tmp_length < precision) +                  tmp_length = precision; +                /* Account for sign, decimal point etc. */ +                tmp_length = xsum (tmp_length, 12); + +                if (tmp_length < width) +                  tmp_length = width; + +                tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ + +                if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T)) +                  tmp = tmpbuf; +                else +                  { +                    size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T)); + +                    if (size_overflow_p (tmp_memsize)) +                      /* Overflow, would lead to out of memory.  */ +                      goto out_of_memory; +                    tmp = (DCHAR_T *) malloc (tmp_memsize); +                    if (tmp == NULL) +                      /* Out of memory.  */ +                      goto out_of_memory; +                  } + +                pad_ptr = NULL; +                p = tmp; +                if (type == TYPE_LONGDOUBLE) +                  { +# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE +                    long double arg = a.arg[dp->arg_index].a.a_longdouble; + +                    if (isnanl (arg)) +                      { +                        if (dp->conversion == 'A') +                          { +                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; +                          } +                        else +                          { +                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; +                          } +                      } +                    else +                      { +                        int sign = 0; +                        DECL_LONG_DOUBLE_ROUNDING + +                        BEGIN_LONG_DOUBLE_ROUNDING (); + +                        if (signbit (arg)) /* arg < 0.0L or negative zero */ +                          { +                            sign = -1; +                            arg = -arg; +                          } + +                        if (sign < 0) +                          *p++ = '-'; +                        else if (flags & FLAG_SHOWSIGN) +                          *p++ = '+'; +                        else if (flags & FLAG_SPACE) +                          *p++ = ' '; + +                        if (arg > 0.0L && arg + arg == arg) +                          { +                            if (dp->conversion == 'A') +                              { +                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; +                              } +                            else +                              { +                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; +                              } +                          } +                        else +                          { +                            int exponent; +                            long double mantissa; + +                            if (arg > 0.0L) +                              mantissa = printf_frexpl (arg, &exponent); +                            else +                              { +                                exponent = 0; +                                mantissa = 0.0L; +                              } + +                            if (has_precision +                                && precision < (unsigned int) ((LDBL_DIG + 1) * 0.831) + 1) +                              { +                                /* Round the mantissa.  */ +                                long double tail = mantissa; +                                size_t q; + +                                for (q = precision; ; q--) +                                  { +                                    int digit = (int) tail; +                                    tail -= digit; +                                    if (q == 0) +                                      { +                                        if (digit & 1 ? tail >= 0.5L : tail > 0.5L) +                                          tail = 1 - tail; +                                        else +                                          tail = - tail; +                                        break; +                                      } +                                    tail *= 16.0L; +                                  } +                                if (tail != 0.0L) +                                  for (q = precision; q > 0; q--) +                                    tail *= 0.0625L; +                                mantissa += tail; +                              } + +                            *p++ = '0'; +                            *p++ = dp->conversion - 'A' + 'X'; +                            pad_ptr = p; +                            { +                              int digit; + +                              digit = (int) mantissa; +                              mantissa -= digit; +                              *p++ = '0' + digit; +                              if ((flags & FLAG_ALT) +                                  || mantissa > 0.0L || precision > 0) +                                { +                                  *p++ = decimal_point_char (); +                                  /* This loop terminates because we assume +                                     that FLT_RADIX is a power of 2.  */ +                                  while (mantissa > 0.0L) +                                    { +                                      mantissa *= 16.0L; +                                      digit = (int) mantissa; +                                      mantissa -= digit; +                                      *p++ = digit +                                             + (digit < 10 +                                                ? '0' +                                                : dp->conversion - 10); +                                      if (precision > 0) +                                        precision--; +                                    } +                                  while (precision > 0) +                                    { +                                      *p++ = '0'; +                                      precision--; +                                    } +                                } +                              } +                              *p++ = dp->conversion - 'A' + 'P'; +#  if WIDE_CHAR_VERSION +                              { +                                static const wchar_t decimal_format[] = +                                  { '%', '+', 'd', '\0' }; +                                SNPRINTF (p, 6 + 1, decimal_format, exponent); +                              } +                              while (*p != '\0') +                                p++; +#  else +                              if (sizeof (DCHAR_T) == 1) +                                { +                                  sprintf ((char *) p, "%+d", exponent); +                                  while (*p != '\0') +                                    p++; +                                } +                              else +                                { +                                  char expbuf[6 + 1]; +                                  const char *ep; +                                  sprintf (expbuf, "%+d", exponent); +                                  for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                    p++; +                                } +#  endif +                          } + +                        END_LONG_DOUBLE_ROUNDING (); +                      } +# else +                    abort (); +# endif +                  } +                else +                  { +# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE +                    double arg = a.arg[dp->arg_index].a.a_double; + +                    if (isnand (arg)) +                      { +                        if (dp->conversion == 'A') +                          { +                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; +                          } +                        else +                          { +                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; +                          } +                      } +                    else +                      { +                        int sign = 0; + +                        if (signbit (arg)) /* arg < 0.0 or negative zero */ +                          { +                            sign = -1; +                            arg = -arg; +                          } + +                        if (sign < 0) +                          *p++ = '-'; +                        else if (flags & FLAG_SHOWSIGN) +                          *p++ = '+'; +                        else if (flags & FLAG_SPACE) +                          *p++ = ' '; + +                        if (arg > 0.0 && arg + arg == arg) +                          { +                            if (dp->conversion == 'A') +                              { +                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; +                              } +                            else +                              { +                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; +                              } +                          } +                        else +                          { +                            int exponent; +                            double mantissa; + +                            if (arg > 0.0) +                              mantissa = printf_frexp (arg, &exponent); +                            else +                              { +                                exponent = 0; +                                mantissa = 0.0; +                              } + +                            if (has_precision +                                && precision < (unsigned int) ((DBL_DIG + 1) * 0.831) + 1) +                              { +                                /* Round the mantissa.  */ +                                double tail = mantissa; +                                size_t q; + +                                for (q = precision; ; q--) +                                  { +                                    int digit = (int) tail; +                                    tail -= digit; +                                    if (q == 0) +                                      { +                                        if (digit & 1 ? tail >= 0.5 : tail > 0.5) +                                          tail = 1 - tail; +                                        else +                                          tail = - tail; +                                        break; +                                      } +                                    tail *= 16.0; +                                  } +                                if (tail != 0.0) +                                  for (q = precision; q > 0; q--) +                                    tail *= 0.0625; +                                mantissa += tail; +                              } + +                            *p++ = '0'; +                            *p++ = dp->conversion - 'A' + 'X'; +                            pad_ptr = p; +                            { +                              int digit; + +                              digit = (int) mantissa; +                              mantissa -= digit; +                              *p++ = '0' + digit; +                              if ((flags & FLAG_ALT) +                                  || mantissa > 0.0 || precision > 0) +                                { +                                  *p++ = decimal_point_char (); +                                  /* This loop terminates because we assume +                                     that FLT_RADIX is a power of 2.  */ +                                  while (mantissa > 0.0) +                                    { +                                      mantissa *= 16.0; +                                      digit = (int) mantissa; +                                      mantissa -= digit; +                                      *p++ = digit +                                             + (digit < 10 +                                                ? '0' +                                                : dp->conversion - 10); +                                      if (precision > 0) +                                        precision--; +                                    } +                                  while (precision > 0) +                                    { +                                      *p++ = '0'; +                                      precision--; +                                    } +                                } +                              } +                              *p++ = dp->conversion - 'A' + 'P'; +#  if WIDE_CHAR_VERSION +                              { +                                static const wchar_t decimal_format[] = +                                  { '%', '+', 'd', '\0' }; +                                SNPRINTF (p, 6 + 1, decimal_format, exponent); +                              } +                              while (*p != '\0') +                                p++; +#  else +                              if (sizeof (DCHAR_T) == 1) +                                { +                                  sprintf ((char *) p, "%+d", exponent); +                                  while (*p != '\0') +                                    p++; +                                } +                              else +                                { +                                  char expbuf[6 + 1]; +                                  const char *ep; +                                  sprintf (expbuf, "%+d", exponent); +                                  for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                    p++; +                                } +#  endif +                          } +                      } +# else +                    abort (); +# endif +                  } +                /* The generated string now extends from tmp to p, with the +                   zero padding insertion point being at pad_ptr.  */ +                if (has_width && p - tmp < width) +                  { +                    size_t pad = width - (p - tmp); +                    DCHAR_T *end = p + pad; + +                    if (flags & FLAG_LEFT) +                      { +                        /* Pad with spaces on the right.  */ +                        for (; pad > 0; pad--) +                          *p++ = ' '; +                      } +                    else if ((flags & FLAG_ZERO) && pad_ptr != NULL) +                      { +                        /* Pad with zeroes.  */ +                        DCHAR_T *q = end; + +                        while (p > pad_ptr) +                          *--q = *--p; +                        for (; pad > 0; pad--) +                          *p++ = '0'; +                      } +                    else +                      { +                        /* Pad with spaces on the left.  */ +                        DCHAR_T *q = end; + +                        while (p > tmp) +                          *--q = *--p; +                        for (; pad > 0; pad--) +                          *p++ = ' '; +                      } + +                    p = end; +                  } + +                { +                  size_t count = p - tmp; + +                  if (count >= tmp_length) +                    /* tmp_length was incorrectly calculated - fix the +                       code above!  */ +                    abort (); + +                  /* Make room for the result.  */ +                  if (count >= allocated - length) +                    { +                      size_t n = xsum (length, count); + +                      ENSURE_ALLOCATION (n); +                    } + +                  /* Append the result.  */ +                  memcpy (result + length, tmp, count * sizeof (DCHAR_T)); +                  if (tmp != tmpbuf) +                    free (tmp); +                  length += count; +                } +              } +#endif +#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL +            else if ((dp->conversion == 'f' || dp->conversion == 'F' +                      || dp->conversion == 'e' || dp->conversion == 'E' +                      || dp->conversion == 'g' || dp->conversion == 'G' +                      || dp->conversion == 'a' || dp->conversion == 'A') +                     && (0 +# if NEED_PRINTF_DOUBLE +                         || a.arg[dp->arg_index].type == TYPE_DOUBLE +# elif NEED_PRINTF_INFINITE_DOUBLE +                         || (a.arg[dp->arg_index].type == TYPE_DOUBLE +                             /* The systems (mingw) which produce wrong output +                                for Inf, -Inf, and NaN also do so for -0.0. +                                Therefore we treat this case here as well.  */ +                             && is_infinite_or_zero (a.arg[dp->arg_index].a.a_double)) +# endif +# if NEED_PRINTF_LONG_DOUBLE +                         || a.arg[dp->arg_index].type == TYPE_LONGDOUBLE +# elif NEED_PRINTF_INFINITE_LONG_DOUBLE +                         || (a.arg[dp->arg_index].type == TYPE_LONGDOUBLE +                             /* Some systems produce wrong output for Inf, +                                -Inf, and NaN.  Some systems in this category +                                (IRIX 5.3) also do so for -0.0.  Therefore we +                                treat this case here as well.  */ +                             && is_infinite_or_zerol (a.arg[dp->arg_index].a.a_longdouble)) +# endif +                        )) +              { +# if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) +                arg_type type = a.arg[dp->arg_index].type; +# endif +                int flags = dp->flags; +                int has_width; +                size_t width; +                int has_precision; +                size_t precision; +                size_t tmp_length; +                DCHAR_T tmpbuf[700]; +                DCHAR_T *tmp; +                DCHAR_T *pad_ptr; +                DCHAR_T *p; + +                has_width = 0; +                width = 0; +                if (dp->width_start != dp->width_end) +                  { +                    if (dp->width_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->width_arg_index].a.a_int; +                        if (arg < 0) +                          { +                            /* "A negative field width is taken as a '-' flag +                                followed by a positive field width."  */ +                            flags |= FLAG_LEFT; +                            width = (unsigned int) (-arg); +                          } +                        else +                          width = arg; +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->width_start; + +                        do +                          width = xsum (xtimes (width, 10), *digitp++ - '0'); +                        while (digitp != dp->width_end); +                      } +                    has_width = 1; +                  } + +                has_precision = 0; +                precision = 0; +                if (dp->precision_start != dp->precision_end) +                  { +                    if (dp->precision_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->precision_arg_index].a.a_int; +                        /* "A negative precision is taken as if the precision +                            were omitted."  */ +                        if (arg >= 0) +                          { +                            precision = arg; +                            has_precision = 1; +                          } +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->precision_start + 1; + +                        precision = 0; +                        while (digitp != dp->precision_end) +                          precision = xsum (xtimes (precision, 10), *digitp++ - '0'); +                        has_precision = 1; +                      } +                  } + +                /* POSIX specifies the default precision to be 6 for %f, %F, +                   %e, %E, but not for %g, %G.  Implementations appear to use +                   the same default precision also for %g, %G.  But for %a, %A, +                   the default precision is 0.  */ +                if (!has_precision) +                  if (!(dp->conversion == 'a' || dp->conversion == 'A')) +                    precision = 6; + +                /* Allocate a temporary buffer of sufficient size.  */ +# if NEED_PRINTF_DOUBLE && NEED_PRINTF_LONG_DOUBLE +                tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : DBL_DIG + 1); +# elif NEED_PRINTF_INFINITE_DOUBLE && NEED_PRINTF_LONG_DOUBLE +                tmp_length = (type == TYPE_LONGDOUBLE ? LDBL_DIG + 1 : 0); +# elif NEED_PRINTF_LONG_DOUBLE +                tmp_length = LDBL_DIG + 1; +# elif NEED_PRINTF_DOUBLE +                tmp_length = DBL_DIG + 1; +# else +                tmp_length = 0; +# endif +                if (tmp_length < precision) +                  tmp_length = precision; +# if NEED_PRINTF_LONG_DOUBLE +#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE +                if (type == TYPE_LONGDOUBLE) +#  endif +                  if (dp->conversion == 'f' || dp->conversion == 'F') +                    { +                      long double arg = a.arg[dp->arg_index].a.a_longdouble; +                      if (!(isnanl (arg) || arg + arg == arg)) +                        { +                          /* arg is finite and nonzero.  */ +                          int exponent = floorlog10l (arg < 0 ? -arg : arg); +                          if (exponent >= 0 && tmp_length < exponent + precision) +                            tmp_length = exponent + precision; +                        } +                    } +# endif +# if NEED_PRINTF_DOUBLE +#  if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE +                if (type == TYPE_DOUBLE) +#  endif +                  if (dp->conversion == 'f' || dp->conversion == 'F') +                    { +                      double arg = a.arg[dp->arg_index].a.a_double; +                      if (!(isnand (arg) || arg + arg == arg)) +                        { +                          /* arg is finite and nonzero.  */ +                          int exponent = floorlog10 (arg < 0 ? -arg : arg); +                          if (exponent >= 0 && tmp_length < exponent + precision) +                            tmp_length = exponent + precision; +                        } +                    } +# endif +                /* Account for sign, decimal point etc. */ +                tmp_length = xsum (tmp_length, 12); + +                if (tmp_length < width) +                  tmp_length = width; + +                tmp_length = xsum (tmp_length, 1); /* account for trailing NUL */ + +                if (tmp_length <= sizeof (tmpbuf) / sizeof (DCHAR_T)) +                  tmp = tmpbuf; +                else +                  { +                    size_t tmp_memsize = xtimes (tmp_length, sizeof (DCHAR_T)); + +                    if (size_overflow_p (tmp_memsize)) +                      /* Overflow, would lead to out of memory.  */ +                      goto out_of_memory; +                    tmp = (DCHAR_T *) malloc (tmp_memsize); +                    if (tmp == NULL) +                      /* Out of memory.  */ +                      goto out_of_memory; +                  } + +                pad_ptr = NULL; +                p = tmp; + +# if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE +#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE +                if (type == TYPE_LONGDOUBLE) +#  endif +                  { +                    long double arg = a.arg[dp->arg_index].a.a_longdouble; + +                    if (isnanl (arg)) +                      { +                        if (dp->conversion >= 'A' && dp->conversion <= 'Z') +                          { +                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; +                          } +                        else +                          { +                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; +                          } +                      } +                    else +                      { +                        int sign = 0; +                        DECL_LONG_DOUBLE_ROUNDING + +                        BEGIN_LONG_DOUBLE_ROUNDING (); + +                        if (signbit (arg)) /* arg < 0.0L or negative zero */ +                          { +                            sign = -1; +                            arg = -arg; +                          } + +                        if (sign < 0) +                          *p++ = '-'; +                        else if (flags & FLAG_SHOWSIGN) +                          *p++ = '+'; +                        else if (flags & FLAG_SPACE) +                          *p++ = ' '; + +                        if (arg > 0.0L && arg + arg == arg) +                          { +                            if (dp->conversion >= 'A' && dp->conversion <= 'Z') +                              { +                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; +                              } +                            else +                              { +                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; +                              } +                          } +                        else +                          { +#  if NEED_PRINTF_LONG_DOUBLE +                            pad_ptr = p; + +                            if (dp->conversion == 'f' || dp->conversion == 'F') +                              { +                                char *digits; +                                size_t ndigits; + +                                digits = +                                  scale10_round_decimal_long_double (arg, precision); +                                if (digits == NULL) +                                  { +                                    END_LONG_DOUBLE_ROUNDING (); +                                    goto out_of_memory; +                                  } +                                ndigits = strlen (digits); + +                                if (ndigits > precision) +                                  do +                                    { +                                      --ndigits; +                                      *p++ = digits[ndigits]; +                                    } +                                  while (ndigits > precision); +                                else +                                  *p++ = '0'; +                                /* Here ndigits <= precision.  */ +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > ndigits; precision--) +                                      *p++ = '0'; +                                    while (ndigits > 0) +                                      { +                                        --ndigits; +                                        *p++ = digits[ndigits]; +                                      } +                                  } + +                                free (digits); +                              } +                            else if (dp->conversion == 'e' || dp->conversion == 'E') +                              { +                                int exponent; + +                                if (arg == 0.0L) +                                  { +                                    exponent = 0; +                                    *p++ = '0'; +                                    if ((flags & FLAG_ALT) || precision > 0) +                                      { +                                        *p++ = decimal_point_char (); +                                        for (; precision > 0; precision--) +                                          *p++ = '0'; +                                      } +                                  } +                                else +                                  { +                                    /* arg > 0.0L.  */ +                                    int adjusted; +                                    char *digits; +                                    size_t ndigits; + +                                    exponent = floorlog10l (arg); +                                    adjusted = 0; +                                    for (;;) +                                      { +                                        digits = +                                          scale10_round_decimal_long_double (arg, +                                                                             (int)precision - exponent); +                                        if (digits == NULL) +                                          { +                                            END_LONG_DOUBLE_ROUNDING (); +                                            goto out_of_memory; +                                          } +                                        ndigits = strlen (digits); + +                                        if (ndigits == precision + 1) +                                          break; +                                        if (ndigits < precision +                                            || ndigits > precision + 2) +                                          /* The exponent was not guessed +                                             precisely enough.  */ +                                          abort (); +                                        if (adjusted) +                                          /* None of two values of exponent is +                                             the right one.  Prevent an endless +                                             loop.  */ +                                          abort (); +                                        free (digits); +                                        if (ndigits == precision) +                                          exponent -= 1; +                                        else +                                          exponent += 1; +                                        adjusted = 1; +                                      } +                                    /* Here ndigits = precision+1.  */ +                                    if (is_borderline (digits, precision)) +                                      { +                                        /* Maybe the exponent guess was too high +                                           and a smaller exponent can be reached +                                           by turning a 10...0 into 9...9x.  */ +                                        char *digits2 = +                                          scale10_round_decimal_long_double (arg, +                                                                             (int)precision - exponent + 1); +                                        if (digits2 == NULL) +                                          { +                                            free (digits); +                                            END_LONG_DOUBLE_ROUNDING (); +                                            goto out_of_memory; +                                          } +                                        if (strlen (digits2) == precision + 1) +                                          { +                                            free (digits); +                                            digits = digits2; +                                            exponent -= 1; +                                          } +                                        else +                                          free (digits2); +                                      } +                                    /* Here ndigits = precision+1.  */ + +                                    *p++ = digits[--ndigits]; +                                    if ((flags & FLAG_ALT) || precision > 0) +                                      { +                                        *p++ = decimal_point_char (); +                                        while (ndigits > 0) +                                          { +                                            --ndigits; +                                            *p++ = digits[ndigits]; +                                          } +                                      } + +                                    free (digits); +                                  } + +                                *p++ = dp->conversion; /* 'e' or 'E' */ +#   if WIDE_CHAR_VERSION +                                { +                                  static const wchar_t decimal_format[] = +                                    { '%', '+', '.', '2', 'd', '\0' }; +                                  SNPRINTF (p, 6 + 1, decimal_format, exponent); +                                } +                                while (*p != '\0') +                                  p++; +#   else +                                if (sizeof (DCHAR_T) == 1) +                                  { +                                    sprintf ((char *) p, "%+.2d", exponent); +                                    while (*p != '\0') +                                      p++; +                                  } +                                else +                                  { +                                    char expbuf[6 + 1]; +                                    const char *ep; +                                    sprintf (expbuf, "%+.2d", exponent); +                                    for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                      p++; +                                  } +#   endif +                              } +                            else if (dp->conversion == 'g' || dp->conversion == 'G') +                              { +                                if (precision == 0) +                                  precision = 1; +                                /* precision >= 1.  */ + +                                if (arg == 0.0L) +                                  /* The exponent is 0, >= -4, < precision. +                                     Use fixed-point notation.  */ +                                  { +                                    size_t ndigits = precision; +                                    /* Number of trailing zeroes that have to be +                                       dropped.  */ +                                    size_t nzeroes = +                                      (flags & FLAG_ALT ? 0 : precision - 1); + +                                    --ndigits; +                                    *p++ = '0'; +                                    if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                      { +                                        *p++ = decimal_point_char (); +                                        while (ndigits > nzeroes) +                                          { +                                            --ndigits; +                                            *p++ = '0'; +                                          } +                                      } +                                  } +                                else +                                  { +                                    /* arg > 0.0L.  */ +                                    int exponent; +                                    int adjusted; +                                    char *digits; +                                    size_t ndigits; +                                    size_t nzeroes; + +                                    exponent = floorlog10l (arg); +                                    adjusted = 0; +                                    for (;;) +                                      { +                                        digits = +                                          scale10_round_decimal_long_double (arg, +                                                                             (int)(precision - 1) - exponent); +                                        if (digits == NULL) +                                          { +                                            END_LONG_DOUBLE_ROUNDING (); +                                            goto out_of_memory; +                                          } +                                        ndigits = strlen (digits); + +                                        if (ndigits == precision) +                                          break; +                                        if (ndigits < precision - 1 +                                            || ndigits > precision + 1) +                                          /* The exponent was not guessed +                                             precisely enough.  */ +                                          abort (); +                                        if (adjusted) +                                          /* None of two values of exponent is +                                             the right one.  Prevent an endless +                                             loop.  */ +                                          abort (); +                                        free (digits); +                                        if (ndigits < precision) +                                          exponent -= 1; +                                        else +                                          exponent += 1; +                                        adjusted = 1; +                                      } +                                    /* Here ndigits = precision.  */ +                                    if (is_borderline (digits, precision - 1)) +                                      { +                                        /* Maybe the exponent guess was too high +                                           and a smaller exponent can be reached +                                           by turning a 10...0 into 9...9x.  */ +                                        char *digits2 = +                                          scale10_round_decimal_long_double (arg, +                                                                             (int)(precision - 1) - exponent + 1); +                                        if (digits2 == NULL) +                                          { +                                            free (digits); +                                            END_LONG_DOUBLE_ROUNDING (); +                                            goto out_of_memory; +                                          } +                                        if (strlen (digits2) == precision) +                                          { +                                            free (digits); +                                            digits = digits2; +                                            exponent -= 1; +                                          } +                                        else +                                          free (digits2); +                                      } +                                    /* Here ndigits = precision.  */ + +                                    /* Determine the number of trailing zeroes +                                       that have to be dropped.  */ +                                    nzeroes = 0; +                                    if ((flags & FLAG_ALT) == 0) +                                      while (nzeroes < ndigits +                                             && digits[nzeroes] == '0') +                                        nzeroes++; + +                                    /* The exponent is now determined.  */ +                                    if (exponent >= -4 +                                        && exponent < (long)precision) +                                      { +                                        /* Fixed-point notation: +                                           max(exponent,0)+1 digits, then the +                                           decimal point, then the remaining +                                           digits without trailing zeroes.  */ +                                        if (exponent >= 0) +                                          { +                                            size_t count = exponent + 1; +                                            /* Note: count <= precision = ndigits.  */ +                                            for (; count > 0; count--) +                                              *p++ = digits[--ndigits]; +                                            if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                              { +                                                *p++ = decimal_point_char (); +                                                while (ndigits > nzeroes) +                                                  { +                                                    --ndigits; +                                                    *p++ = digits[ndigits]; +                                                  } +                                              } +                                          } +                                        else +                                          { +                                            size_t count = -exponent - 1; +                                            *p++ = '0'; +                                            *p++ = decimal_point_char (); +                                            for (; count > 0; count--) +                                              *p++ = '0'; +                                            while (ndigits > nzeroes) +                                              { +                                                --ndigits; +                                                *p++ = digits[ndigits]; +                                              } +                                          } +                                      } +                                    else +                                      { +                                        /* Exponential notation.  */ +                                        *p++ = digits[--ndigits]; +                                        if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                          { +                                            *p++ = decimal_point_char (); +                                            while (ndigits > nzeroes) +                                              { +                                                --ndigits; +                                                *p++ = digits[ndigits]; +                                              } +                                          } +                                        *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ +#   if WIDE_CHAR_VERSION +                                        { +                                          static const wchar_t decimal_format[] = +                                            { '%', '+', '.', '2', 'd', '\0' }; +                                          SNPRINTF (p, 6 + 1, decimal_format, exponent); +                                        } +                                        while (*p != '\0') +                                          p++; +#   else +                                        if (sizeof (DCHAR_T) == 1) +                                          { +                                            sprintf ((char *) p, "%+.2d", exponent); +                                            while (*p != '\0') +                                              p++; +                                          } +                                        else +                                          { +                                            char expbuf[6 + 1]; +                                            const char *ep; +                                            sprintf (expbuf, "%+.2d", exponent); +                                            for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                              p++; +                                          } +#   endif +                                      } + +                                    free (digits); +                                  } +                              } +                            else +                              abort (); +#  else +                            /* arg is finite.  */ +                            if (!(arg == 0.0L)) +                              abort (); + +                            pad_ptr = p; + +                            if (dp->conversion == 'f' || dp->conversion == 'F') +                              { +                                *p++ = '0'; +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > 0; precision--) +                                      *p++ = '0'; +                                  } +                              } +                            else if (dp->conversion == 'e' || dp->conversion == 'E') +                              { +                                *p++ = '0'; +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > 0; precision--) +                                      *p++ = '0'; +                                  } +                                *p++ = dp->conversion; /* 'e' or 'E' */ +                                *p++ = '+'; +                                *p++ = '0'; +                                *p++ = '0'; +                              } +                            else if (dp->conversion == 'g' || dp->conversion == 'G') +                              { +                                *p++ = '0'; +                                if (flags & FLAG_ALT) +                                  { +                                    size_t ndigits = +                                      (precision > 0 ? precision - 1 : 0); +                                    *p++ = decimal_point_char (); +                                    for (; ndigits > 0; --ndigits) +                                      *p++ = '0'; +                                  } +                              } +                            else if (dp->conversion == 'a' || dp->conversion == 'A') +                              { +                                *p++ = '0'; +                                *p++ = dp->conversion - 'A' + 'X'; +                                pad_ptr = p; +                                *p++ = '0'; +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > 0; precision--) +                                      *p++ = '0'; +                                  } +                                *p++ = dp->conversion - 'A' + 'P'; +                                *p++ = '+'; +                                *p++ = '0'; +                              } +                            else +                              abort (); +#  endif +                          } + +                        END_LONG_DOUBLE_ROUNDING (); +                      } +                  } +#  if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE +                else +#  endif +# endif +# if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE +                  { +                    double arg = a.arg[dp->arg_index].a.a_double; + +                    if (isnand (arg)) +                      { +                        if (dp->conversion >= 'A' && dp->conversion <= 'Z') +                          { +                            *p++ = 'N'; *p++ = 'A'; *p++ = 'N'; +                          } +                        else +                          { +                            *p++ = 'n'; *p++ = 'a'; *p++ = 'n'; +                          } +                      } +                    else +                      { +                        int sign = 0; + +                        if (signbit (arg)) /* arg < 0.0 or negative zero */ +                          { +                            sign = -1; +                            arg = -arg; +                          } + +                        if (sign < 0) +                          *p++ = '-'; +                        else if (flags & FLAG_SHOWSIGN) +                          *p++ = '+'; +                        else if (flags & FLAG_SPACE) +                          *p++ = ' '; + +                        if (arg > 0.0 && arg + arg == arg) +                          { +                            if (dp->conversion >= 'A' && dp->conversion <= 'Z') +                              { +                                *p++ = 'I'; *p++ = 'N'; *p++ = 'F'; +                              } +                            else +                              { +                                *p++ = 'i'; *p++ = 'n'; *p++ = 'f'; +                              } +                          } +                        else +                          { +#  if NEED_PRINTF_DOUBLE +                            pad_ptr = p; + +                            if (dp->conversion == 'f' || dp->conversion == 'F') +                              { +                                char *digits; +                                size_t ndigits; + +                                digits = +                                  scale10_round_decimal_double (arg, precision); +                                if (digits == NULL) +                                  goto out_of_memory; +                                ndigits = strlen (digits); + +                                if (ndigits > precision) +                                  do +                                    { +                                      --ndigits; +                                      *p++ = digits[ndigits]; +                                    } +                                  while (ndigits > precision); +                                else +                                  *p++ = '0'; +                                /* Here ndigits <= precision.  */ +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > ndigits; precision--) +                                      *p++ = '0'; +                                    while (ndigits > 0) +                                      { +                                        --ndigits; +                                        *p++ = digits[ndigits]; +                                      } +                                  } + +                                free (digits); +                              } +                            else if (dp->conversion == 'e' || dp->conversion == 'E') +                              { +                                int exponent; + +                                if (arg == 0.0) +                                  { +                                    exponent = 0; +                                    *p++ = '0'; +                                    if ((flags & FLAG_ALT) || precision > 0) +                                      { +                                        *p++ = decimal_point_char (); +                                        for (; precision > 0; precision--) +                                          *p++ = '0'; +                                      } +                                  } +                                else +                                  { +                                    /* arg > 0.0.  */ +                                    int adjusted; +                                    char *digits; +                                    size_t ndigits; + +                                    exponent = floorlog10 (arg); +                                    adjusted = 0; +                                    for (;;) +                                      { +                                        digits = +                                          scale10_round_decimal_double (arg, +                                                                        (int)precision - exponent); +                                        if (digits == NULL) +                                          goto out_of_memory; +                                        ndigits = strlen (digits); + +                                        if (ndigits == precision + 1) +                                          break; +                                        if (ndigits < precision +                                            || ndigits > precision + 2) +                                          /* The exponent was not guessed +                                             precisely enough.  */ +                                          abort (); +                                        if (adjusted) +                                          /* None of two values of exponent is +                                             the right one.  Prevent an endless +                                             loop.  */ +                                          abort (); +                                        free (digits); +                                        if (ndigits == precision) +                                          exponent -= 1; +                                        else +                                          exponent += 1; +                                        adjusted = 1; +                                      } +                                    /* Here ndigits = precision+1.  */ +                                    if (is_borderline (digits, precision)) +                                      { +                                        /* Maybe the exponent guess was too high +                                           and a smaller exponent can be reached +                                           by turning a 10...0 into 9...9x.  */ +                                        char *digits2 = +                                          scale10_round_decimal_double (arg, +                                                                        (int)precision - exponent + 1); +                                        if (digits2 == NULL) +                                          { +                                            free (digits); +                                            goto out_of_memory; +                                          } +                                        if (strlen (digits2) == precision + 1) +                                          { +                                            free (digits); +                                            digits = digits2; +                                            exponent -= 1; +                                          } +                                        else +                                          free (digits2); +                                      } +                                    /* Here ndigits = precision+1.  */ + +                                    *p++ = digits[--ndigits]; +                                    if ((flags & FLAG_ALT) || precision > 0) +                                      { +                                        *p++ = decimal_point_char (); +                                        while (ndigits > 0) +                                          { +                                            --ndigits; +                                            *p++ = digits[ndigits]; +                                          } +                                      } + +                                    free (digits); +                                  } + +                                *p++ = dp->conversion; /* 'e' or 'E' */ +#   if WIDE_CHAR_VERSION +                                { +                                  static const wchar_t decimal_format[] = +                                    /* Produce the same number of exponent digits +                                       as the native printf implementation.  */ +#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                                    { '%', '+', '.', '3', 'd', '\0' }; +#    else +                                    { '%', '+', '.', '2', 'd', '\0' }; +#    endif +                                  SNPRINTF (p, 6 + 1, decimal_format, exponent); +                                } +                                while (*p != '\0') +                                  p++; +#   else +                                { +                                  static const char decimal_format[] = +                                    /* Produce the same number of exponent digits +                                       as the native printf implementation.  */ +#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                                    "%+.3d"; +#    else +                                    "%+.2d"; +#    endif +                                  if (sizeof (DCHAR_T) == 1) +                                    { +                                      sprintf ((char *) p, decimal_format, exponent); +                                      while (*p != '\0') +                                        p++; +                                    } +                                  else +                                    { +                                      char expbuf[6 + 1]; +                                      const char *ep; +                                      sprintf (expbuf, decimal_format, exponent); +                                      for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                        p++; +                                    } +                                } +#   endif +                              } +                            else if (dp->conversion == 'g' || dp->conversion == 'G') +                              { +                                if (precision == 0) +                                  precision = 1; +                                /* precision >= 1.  */ + +                                if (arg == 0.0) +                                  /* The exponent is 0, >= -4, < precision. +                                     Use fixed-point notation.  */ +                                  { +                                    size_t ndigits = precision; +                                    /* Number of trailing zeroes that have to be +                                       dropped.  */ +                                    size_t nzeroes = +                                      (flags & FLAG_ALT ? 0 : precision - 1); + +                                    --ndigits; +                                    *p++ = '0'; +                                    if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                      { +                                        *p++ = decimal_point_char (); +                                        while (ndigits > nzeroes) +                                          { +                                            --ndigits; +                                            *p++ = '0'; +                                          } +                                      } +                                  } +                                else +                                  { +                                    /* arg > 0.0.  */ +                                    int exponent; +                                    int adjusted; +                                    char *digits; +                                    size_t ndigits; +                                    size_t nzeroes; + +                                    exponent = floorlog10 (arg); +                                    adjusted = 0; +                                    for (;;) +                                      { +                                        digits = +                                          scale10_round_decimal_double (arg, +                                                                        (int)(precision - 1) - exponent); +                                        if (digits == NULL) +                                          goto out_of_memory; +                                        ndigits = strlen (digits); + +                                        if (ndigits == precision) +                                          break; +                                        if (ndigits < precision - 1 +                                            || ndigits > precision + 1) +                                          /* The exponent was not guessed +                                             precisely enough.  */ +                                          abort (); +                                        if (adjusted) +                                          /* None of two values of exponent is +                                             the right one.  Prevent an endless +                                             loop.  */ +                                          abort (); +                                        free (digits); +                                        if (ndigits < precision) +                                          exponent -= 1; +                                        else +                                          exponent += 1; +                                        adjusted = 1; +                                      } +                                    /* Here ndigits = precision.  */ +                                    if (is_borderline (digits, precision - 1)) +                                      { +                                        /* Maybe the exponent guess was too high +                                           and a smaller exponent can be reached +                                           by turning a 10...0 into 9...9x.  */ +                                        char *digits2 = +                                          scale10_round_decimal_double (arg, +                                                                        (int)(precision - 1) - exponent + 1); +                                        if (digits2 == NULL) +                                          { +                                            free (digits); +                                            goto out_of_memory; +                                          } +                                        if (strlen (digits2) == precision) +                                          { +                                            free (digits); +                                            digits = digits2; +                                            exponent -= 1; +                                          } +                                        else +                                          free (digits2); +                                      } +                                    /* Here ndigits = precision.  */ + +                                    /* Determine the number of trailing zeroes +                                       that have to be dropped.  */ +                                    nzeroes = 0; +                                    if ((flags & FLAG_ALT) == 0) +                                      while (nzeroes < ndigits +                                             && digits[nzeroes] == '0') +                                        nzeroes++; + +                                    /* The exponent is now determined.  */ +                                    if (exponent >= -4 +                                        && exponent < (long)precision) +                                      { +                                        /* Fixed-point notation: +                                           max(exponent,0)+1 digits, then the +                                           decimal point, then the remaining +                                           digits without trailing zeroes.  */ +                                        if (exponent >= 0) +                                          { +                                            size_t count = exponent + 1; +                                            /* Note: count <= precision = ndigits.  */ +                                            for (; count > 0; count--) +                                              *p++ = digits[--ndigits]; +                                            if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                              { +                                                *p++ = decimal_point_char (); +                                                while (ndigits > nzeroes) +                                                  { +                                                    --ndigits; +                                                    *p++ = digits[ndigits]; +                                                  } +                                              } +                                          } +                                        else +                                          { +                                            size_t count = -exponent - 1; +                                            *p++ = '0'; +                                            *p++ = decimal_point_char (); +                                            for (; count > 0; count--) +                                              *p++ = '0'; +                                            while (ndigits > nzeroes) +                                              { +                                                --ndigits; +                                                *p++ = digits[ndigits]; +                                              } +                                          } +                                      } +                                    else +                                      { +                                        /* Exponential notation.  */ +                                        *p++ = digits[--ndigits]; +                                        if ((flags & FLAG_ALT) || ndigits > nzeroes) +                                          { +                                            *p++ = decimal_point_char (); +                                            while (ndigits > nzeroes) +                                              { +                                                --ndigits; +                                                *p++ = digits[ndigits]; +                                              } +                                          } +                                        *p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */ +#   if WIDE_CHAR_VERSION +                                        { +                                          static const wchar_t decimal_format[] = +                                            /* Produce the same number of exponent digits +                                               as the native printf implementation.  */ +#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                                            { '%', '+', '.', '3', 'd', '\0' }; +#    else +                                            { '%', '+', '.', '2', 'd', '\0' }; +#    endif +                                          SNPRINTF (p, 6 + 1, decimal_format, exponent); +                                        } +                                        while (*p != '\0') +                                          p++; +#   else +                                        { +                                          static const char decimal_format[] = +                                            /* Produce the same number of exponent digits +                                               as the native printf implementation.  */ +#    if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                                            "%+.3d"; +#    else +                                            "%+.2d"; +#    endif +                                          if (sizeof (DCHAR_T) == 1) +                                            { +                                              sprintf ((char *) p, decimal_format, exponent); +                                              while (*p != '\0') +                                                p++; +                                            } +                                          else +                                            { +                                              char expbuf[6 + 1]; +                                              const char *ep; +                                              sprintf (expbuf, decimal_format, exponent); +                                              for (ep = expbuf; (*p = *ep) != '\0'; ep++) +                                                p++; +                                            } +                                        } +#   endif +                                      } + +                                    free (digits); +                                  } +                              } +                            else +                              abort (); +#  else +                            /* arg is finite.  */ +                            if (!(arg == 0.0)) +                              abort (); + +                            pad_ptr = p; + +                            if (dp->conversion == 'f' || dp->conversion == 'F') +                              { +                                *p++ = '0'; +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > 0; precision--) +                                      *p++ = '0'; +                                  } +                              } +                            else if (dp->conversion == 'e' || dp->conversion == 'E') +                              { +                                *p++ = '0'; +                                if ((flags & FLAG_ALT) || precision > 0) +                                  { +                                    *p++ = decimal_point_char (); +                                    for (; precision > 0; precision--) +                                      *p++ = '0'; +                                  } +                                *p++ = dp->conversion; /* 'e' or 'E' */ +                                *p++ = '+'; +                                /* Produce the same number of exponent digits as +                                   the native printf implementation.  */ +#   if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                                *p++ = '0'; +#   endif +                                *p++ = '0'; +                                *p++ = '0'; +                              } +                            else if (dp->conversion == 'g' || dp->conversion == 'G') +                              { +                                *p++ = '0'; +                                if (flags & FLAG_ALT) +                                  { +                                    size_t ndigits = +                                      (precision > 0 ? precision - 1 : 0); +                                    *p++ = decimal_point_char (); +                                    for (; ndigits > 0; --ndigits) +                                      *p++ = '0'; +                                  } +                              } +                            else +                              abort (); +#  endif +                          } +                      } +                  } +# endif + +                /* The generated string now extends from tmp to p, with the +                   zero padding insertion point being at pad_ptr.  */ +                if (has_width && p - tmp < width) +                  { +                    size_t pad = width - (p - tmp); +                    DCHAR_T *end = p + pad; + +                    if (flags & FLAG_LEFT) +                      { +                        /* Pad with spaces on the right.  */ +                        for (; pad > 0; pad--) +                          *p++ = ' '; +                      } +                    else if ((flags & FLAG_ZERO) && pad_ptr != NULL) +                      { +                        /* Pad with zeroes.  */ +                        DCHAR_T *q = end; + +                        while (p > pad_ptr) +                          *--q = *--p; +                        for (; pad > 0; pad--) +                          *p++ = '0'; +                      } +                    else +                      { +                        /* Pad with spaces on the left.  */ +                        DCHAR_T *q = end; + +                        while (p > tmp) +                          *--q = *--p; +                        for (; pad > 0; pad--) +                          *p++ = ' '; +                      } + +                    p = end; +                  } + +                { +                  size_t count = p - tmp; + +                  if (count >= tmp_length) +                    /* tmp_length was incorrectly calculated - fix the +                       code above!  */ +                    abort (); + +                  /* Make room for the result.  */ +                  if (count >= allocated - length) +                    { +                      size_t n = xsum (length, count); + +                      ENSURE_ALLOCATION (n); +                    } + +                  /* Append the result.  */ +                  memcpy (result + length, tmp, count * sizeof (DCHAR_T)); +                  if (tmp != tmpbuf) +                    free (tmp); +                  length += count; +                } +              } +#endif +            else +              { +                arg_type type = a.arg[dp->arg_index].type; +                int flags = dp->flags; +#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +                int has_width; +                size_t width; +#endif +#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION +                int has_precision; +                size_t precision; +#endif +#if NEED_PRINTF_UNBOUNDED_PRECISION +                int prec_ourselves; +#else +#               define prec_ourselves 0 +#endif +#if NEED_PRINTF_FLAG_LEFTADJUST +#               define pad_ourselves 1 +#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +                int pad_ourselves; +#else +#               define pad_ourselves 0 +#endif +                TCHAR_T *fbp; +                unsigned int prefix_count; +                int prefixes[2] IF_LINT (= { 0 }); +                int orig_errno; +#if !USE_SNPRINTF +                size_t tmp_length; +                TCHAR_T tmpbuf[700]; +                TCHAR_T *tmp; +#endif + +#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +                has_width = 0; +                width = 0; +                if (dp->width_start != dp->width_end) +                  { +                    if (dp->width_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->width_arg_index].a.a_int; +                        if (arg < 0) +                          { +                            /* "A negative field width is taken as a '-' flag +                                followed by a positive field width."  */ +                            flags |= FLAG_LEFT; +                            width = (unsigned int) (-arg); +                          } +                        else +                          width = arg; +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->width_start; + +                        do +                          width = xsum (xtimes (width, 10), *digitp++ - '0'); +                        while (digitp != dp->width_end); +                      } +                    has_width = 1; +                  } +#endif + +#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION +                has_precision = 0; +                precision = 6; +                if (dp->precision_start != dp->precision_end) +                  { +                    if (dp->precision_arg_index != ARG_NONE) +                      { +                        int arg; + +                        if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                          abort (); +                        arg = a.arg[dp->precision_arg_index].a.a_int; +                        /* "A negative precision is taken as if the precision +                            were omitted."  */ +                        if (arg >= 0) +                          { +                            precision = arg; +                            has_precision = 1; +                          } +                      } +                    else +                      { +                        const FCHAR_T *digitp = dp->precision_start + 1; + +                        precision = 0; +                        while (digitp != dp->precision_end) +                          precision = xsum (xtimes (precision, 10), *digitp++ - '0'); +                        has_precision = 1; +                      } +                  } +#endif + +                /* Decide whether to handle the precision ourselves.  */ +#if NEED_PRINTF_UNBOUNDED_PRECISION +                switch (dp->conversion) +                  { +                  case 'd': case 'i': case 'u': +                  case 'o': +                  case 'x': case 'X': case 'p': +                    prec_ourselves = has_precision && (precision > 0); +                    break; +                  default: +                    prec_ourselves = 0; +                    break; +                  } +#endif + +                /* Decide whether to perform the padding ourselves.  */ +#if !NEED_PRINTF_FLAG_LEFTADJUST && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION) +                switch (dp->conversion) +                  { +# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO +                  /* If we need conversion from TCHAR_T[] to DCHAR_T[], we need +                     to perform the padding after this conversion.  Functions +                     with unistdio extensions perform the padding based on +                     character count rather than element count.  */ +                  case 'c': case 's': +# endif +# if NEED_PRINTF_FLAG_ZERO +                  case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': +                  case 'a': case 'A': +# endif +                    pad_ourselves = 1; +                    break; +                  default: +                    pad_ourselves = prec_ourselves; +                    break; +                  } +#endif + +#if !USE_SNPRINTF +                /* Allocate a temporary buffer of sufficient size for calling +                   sprintf.  */ +                tmp_length = +                  MAX_ROOM_NEEDED (&a, dp->arg_index, dp->conversion, type, +                                   flags, width, has_precision, precision, +                                   pad_ourselves); + +                if (tmp_length <= sizeof (tmpbuf) / sizeof (TCHAR_T)) +                  tmp = tmpbuf; +                else +                  { +                    size_t tmp_memsize = xtimes (tmp_length, sizeof (TCHAR_T)); + +                    if (size_overflow_p (tmp_memsize)) +                      /* Overflow, would lead to out of memory.  */ +                      goto out_of_memory; +                    tmp = (TCHAR_T *) malloc (tmp_memsize); +                    if (tmp == NULL) +                      /* Out of memory.  */ +                      goto out_of_memory; +                  } +#endif + +                /* Construct the format string for calling snprintf or +                   sprintf.  */ +                fbp = buf; +                *fbp++ = '%'; +#if NEED_PRINTF_FLAG_GROUPING +                /* The underlying implementation doesn't support the ' flag. +                   Produce no grouping characters in this case; this is +                   acceptable because the grouping is locale dependent.  */ +#else +                if (flags & FLAG_GROUP) +                  *fbp++ = '\''; +#endif +                if (flags & FLAG_LEFT) +                  *fbp++ = '-'; +                if (flags & FLAG_SHOWSIGN) +                  *fbp++ = '+'; +                if (flags & FLAG_SPACE) +                  *fbp++ = ' '; +                if (flags & FLAG_ALT) +                  *fbp++ = '#'; +#if __GLIBC__ >= 2 && !defined __UCLIBC__ +                if (flags & FLAG_LOCALIZED) +                  *fbp++ = 'I'; +#endif +                if (!pad_ourselves) +                  { +                    if (flags & FLAG_ZERO) +                      *fbp++ = '0'; +                    if (dp->width_start != dp->width_end) +                      { +                        size_t n = dp->width_end - dp->width_start; +                        /* The width specification is known to consist only +                           of standard ASCII characters.  */ +                        if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) +                          { +                            memcpy (fbp, dp->width_start, n * sizeof (TCHAR_T)); +                            fbp += n; +                          } +                        else +                          { +                            const FCHAR_T *mp = dp->width_start; +                            do +                              *fbp++ = (unsigned char) *mp++; +                            while (--n > 0); +                          } +                      } +                  } +                if (!prec_ourselves) +                  { +                    if (dp->precision_start != dp->precision_end) +                      { +                        size_t n = dp->precision_end - dp->precision_start; +                        /* The precision specification is known to consist only +                           of standard ASCII characters.  */ +                        if (sizeof (FCHAR_T) == sizeof (TCHAR_T)) +                          { +                            memcpy (fbp, dp->precision_start, n * sizeof (TCHAR_T)); +                            fbp += n; +                          } +                        else +                          { +                            const FCHAR_T *mp = dp->precision_start; +                            do +                              *fbp++ = (unsigned char) *mp++; +                            while (--n > 0); +                          } +                      } +                  } + +                switch (type) +                  { +#if HAVE_LONG_LONG_INT +                  case TYPE_LONGLONGINT: +                  case TYPE_ULONGLONGINT: +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +                    *fbp++ = 'I'; +                    *fbp++ = '6'; +                    *fbp++ = '4'; +                    break; +# else +                    *fbp++ = 'l'; +                    /*FALLTHROUGH*/ +# endif +#endif +                  case TYPE_LONGINT: +                  case TYPE_ULONGINT: +#if HAVE_WINT_T +                  case TYPE_WIDE_CHAR: +#endif +#if HAVE_WCHAR_T +                  case TYPE_WIDE_STRING: +#endif +                    *fbp++ = 'l'; +                    break; +                  case TYPE_LONGDOUBLE: +                    *fbp++ = 'L'; +                    break; +                  default: +                    break; +                  } +#if NEED_PRINTF_DIRECTIVE_F +                if (dp->conversion == 'F') +                  *fbp = 'f'; +                else +#endif +                  *fbp = dp->conversion; +#if USE_SNPRINTF +# if !(((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined __UCLIBC__) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)) +                fbp[1] = '%'; +                fbp[2] = 'n'; +                fbp[3] = '\0'; +# else +                /* On glibc2 systems from glibc >= 2.3 - probably also older +                   ones - we know that snprintf's return value conforms to +                   ISO C 99: the tests gl_SNPRINTF_RETVAL_C99 and +                   gl_SNPRINTF_TRUNCATION_C99 pass. +                   Therefore we can avoid using %n in this situation. +                   On glibc2 systems from 2004-10-18 or newer, the use of %n +                   in format strings in writable memory may crash the program +                   (if compiled with _FORTIFY_SOURCE=2), so we should avoid it +                   in this situation.  */ +                /* On native Windows systems (such as mingw), we can avoid using +                   %n because: +                     - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, +                       snprintf does not write more than the specified number +                       of bytes. (snprintf (buf, 3, "%d %d", 4567, 89) writes +                       '4', '5', '6' into buf, not '4', '5', '\0'.) +                     - Although the gl_SNPRINTF_RETVAL_C99 test fails, snprintf +                       allows us to recognize the case of an insufficient +                       buffer size: it returns -1 in this case. +                   On native Windows systems (such as mingw) where the OS is +                   Windows Vista, the use of %n in format strings by default +                   crashes the program. See +                     <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and +                     <http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx> +                   So we should avoid %n in this situation.  */ +                fbp[1] = '\0'; +# endif +#else +                fbp[1] = '\0'; +#endif + +                /* Construct the arguments for calling snprintf or sprintf.  */ +                prefix_count = 0; +                if (!pad_ourselves && dp->width_arg_index != ARG_NONE) +                  { +                    if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) +                      abort (); +                    prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int; +                  } +                if (!prec_ourselves && dp->precision_arg_index != ARG_NONE) +                  { +                    if (!(a.arg[dp->precision_arg_index].type == TYPE_INT)) +                      abort (); +                    prefixes[prefix_count++] = a.arg[dp->precision_arg_index].a.a_int; +                  } + +#if USE_SNPRINTF +                /* The SNPRINTF result is appended after result[0..length]. +                   The latter is an array of DCHAR_T; SNPRINTF appends an +                   array of TCHAR_T to it.  This is possible because +                   sizeof (TCHAR_T) divides sizeof (DCHAR_T) and +                   alignof (TCHAR_T) <= alignof (DCHAR_T).  */ +# define TCHARS_PER_DCHAR (sizeof (DCHAR_T) / sizeof (TCHAR_T)) +                /* Ensure that maxlen below will be >= 2.  Needed on BeOS, +                   where an snprintf() with maxlen==1 acts like sprintf().  */ +                ENSURE_ALLOCATION (xsum (length, +                                         (2 + TCHARS_PER_DCHAR - 1) +                                         / TCHARS_PER_DCHAR)); +                /* Prepare checking whether snprintf returns the count +                   via %n.  */ +                *(TCHAR_T *) (result + length) = '\0'; +#endif + +                orig_errno = errno; + +                for (;;) +                  { +                    int count = -1; + +#if USE_SNPRINTF +                    int retcount = 0; +                    size_t maxlen = allocated - length; +                    /* SNPRINTF can fail if its second argument is +                       > INT_MAX.  */ +                    if (maxlen > INT_MAX / TCHARS_PER_DCHAR) +                      maxlen = INT_MAX / TCHARS_PER_DCHAR; +                    maxlen = maxlen * TCHARS_PER_DCHAR; +# define SNPRINTF_BUF(arg) \ +                    switch (prefix_count)                                   \ +                      {                                                     \ +                      case 0:                                               \ +                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \ +                                             maxlen, buf,                   \ +                                             arg, &count);                  \ +                        break;                                              \ +                      case 1:                                               \ +                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \ +                                             maxlen, buf,                   \ +                                             prefixes[0], arg, &count);     \ +                        break;                                              \ +                      case 2:                                               \ +                        retcount = SNPRINTF ((TCHAR_T *) (result + length), \ +                                             maxlen, buf,                   \ +                                             prefixes[0], prefixes[1], arg, \ +                                             &count);                       \ +                        break;                                              \ +                      default:                                              \ +                        abort ();                                           \ +                      } +#else +# define SNPRINTF_BUF(arg) \ +                    switch (prefix_count)                                   \ +                      {                                                     \ +                      case 0:                                               \ +                        count = sprintf (tmp, buf, arg);                    \ +                        break;                                              \ +                      case 1:                                               \ +                        count = sprintf (tmp, buf, prefixes[0], arg);       \ +                        break;                                              \ +                      case 2:                                               \ +                        count = sprintf (tmp, buf, prefixes[0], prefixes[1],\ +                                         arg);                              \ +                        break;                                              \ +                      default:                                              \ +                        abort ();                                           \ +                      } +#endif + +                    errno = 0; +                    switch (type) +                      { +                      case TYPE_SCHAR: +                        { +                          int arg = a.arg[dp->arg_index].a.a_schar; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_UCHAR: +                        { +                          unsigned int arg = a.arg[dp->arg_index].a.a_uchar; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_SHORT: +                        { +                          int arg = a.arg[dp->arg_index].a.a_short; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_USHORT: +                        { +                          unsigned int arg = a.arg[dp->arg_index].a.a_ushort; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_INT: +                        { +                          int arg = a.arg[dp->arg_index].a.a_int; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_UINT: +                        { +                          unsigned int arg = a.arg[dp->arg_index].a.a_uint; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_LONGINT: +                        { +                          long int arg = a.arg[dp->arg_index].a.a_longint; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_ULONGINT: +                        { +                          unsigned long int arg = a.arg[dp->arg_index].a.a_ulongint; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#if HAVE_LONG_LONG_INT +                      case TYPE_LONGLONGINT: +                        { +                          long long int arg = a.arg[dp->arg_index].a.a_longlongint; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_ULONGLONGINT: +                        { +                          unsigned long long int arg = a.arg[dp->arg_index].a.a_ulonglongint; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#endif +                      case TYPE_DOUBLE: +                        { +                          double arg = a.arg[dp->arg_index].a.a_double; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_LONGDOUBLE: +                        { +                          long double arg = a.arg[dp->arg_index].a.a_longdouble; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      case TYPE_CHAR: +                        { +                          int arg = a.arg[dp->arg_index].a.a_char; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#if HAVE_WINT_T +                      case TYPE_WIDE_CHAR: +                        { +                          wint_t arg = a.arg[dp->arg_index].a.a_wide_char; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#endif +                      case TYPE_STRING: +                        { +                          const char *arg = a.arg[dp->arg_index].a.a_string; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#if HAVE_WCHAR_T +                      case TYPE_WIDE_STRING: +                        { +                          const wchar_t *arg = a.arg[dp->arg_index].a.a_wide_string; +                          SNPRINTF_BUF (arg); +                        } +                        break; +#endif +                      case TYPE_POINTER: +                        { +                          void *arg = a.arg[dp->arg_index].a.a_pointer; +                          SNPRINTF_BUF (arg); +                        } +                        break; +                      default: +                        abort (); +                      } + +#if USE_SNPRINTF +                    /* Portability: Not all implementations of snprintf() +                       are ISO C 99 compliant.  Determine the number of +                       bytes that snprintf() has produced or would have +                       produced.  */ +                    if (count >= 0) +                      { +                        /* Verify that snprintf() has NUL-terminated its +                           result.  */ +                        if (count < maxlen +                            && ((TCHAR_T *) (result + length)) [count] != '\0') +                          abort (); +                        /* Portability hack.  */ +                        if (retcount > count) +                          count = retcount; +                      } +                    else +                      { +                        /* snprintf() doesn't understand the '%n' +                           directive.  */ +                        if (fbp[1] != '\0') +                          { +                            /* Don't use the '%n' directive; instead, look +                               at the snprintf() return value.  */ +                            fbp[1] = '\0'; +                            continue; +                          } +                        else +                          { +                            /* Look at the snprintf() return value.  */ +                            if (retcount < 0) +                              { +# if !HAVE_SNPRINTF_RETVAL_C99 +                                /* HP-UX 10.20 snprintf() is doubly deficient: +                                   It doesn't understand the '%n' directive, +                                   *and* it returns -1 (rather than the length +                                   that would have been required) when the +                                   buffer is too small. +                                   But a failure at this point can also come +                                   from other reasons than a too small buffer, +                                   such as an invalid wide string argument to +                                   the %ls directive, or possibly an invalid +                                   floating-point argument.  */ +                                size_t tmp_length = +                                  MAX_ROOM_NEEDED (&a, dp->arg_index, +                                                   dp->conversion, type, flags, +                                                   width, has_precision, +                                                   precision, pad_ourselves); + +                                if (maxlen < tmp_length) +                                  { +                                    /* Make more room.  But try to do through +                                       this reallocation only once.  */ +                                    size_t bigger_need = +                                      xsum (length, +                                            xsum (tmp_length, +                                                  TCHARS_PER_DCHAR - 1) +                                            / TCHARS_PER_DCHAR); +                                    /* And always grow proportionally. +                                       (There may be several arguments, each +                                       needing a little more room than the +                                       previous one.)  */ +                                    size_t bigger_need2 = +                                      xsum (xtimes (allocated, 2), 12); +                                    if (bigger_need < bigger_need2) +                                      bigger_need = bigger_need2; +                                    ENSURE_ALLOCATION (bigger_need); +                                    continue; +                                  } +# endif +                              } +                            else +                              count = retcount; +                          } +                      } +#endif + +                    /* Attempt to handle failure.  */ +                    if (count < 0) +                      { +                        /* SNPRINTF or sprintf failed.  Save and use the errno +                           that it has set, if any.  */ +                        int saved_errno = errno; + +                        if (!(result == resultbuf || result == NULL)) +                          free (result); +                        if (buf_malloced != NULL) +                          free (buf_malloced); +                        CLEANUP (); +                        errno = +                          (saved_errno != 0 +                           ? saved_errno +                           : (dp->conversion == 'c' || dp->conversion == 's' +                              ? EILSEQ +                              : EINVAL)); +                        return NULL; +                      } + +#if USE_SNPRINTF +                    /* Handle overflow of the allocated buffer. +                       If such an overflow occurs, a C99 compliant snprintf() +                       returns a count >= maxlen.  However, a non-compliant +                       snprintf() function returns only count = maxlen - 1.  To +                       cover both cases, test whether count >= maxlen - 1.  */ +                    if ((unsigned int) count + 1 >= maxlen) +                      { +                        /* If maxlen already has attained its allowed maximum, +                           allocating more memory will not increase maxlen. +                           Instead of looping, bail out.  */ +                        if (maxlen == INT_MAX / TCHARS_PER_DCHAR) +                          goto overflow; +                        else +                          { +                            /* Need at least (count + 1) * sizeof (TCHAR_T) +                               bytes.  (The +1 is for the trailing NUL.) +                               But ask for (count + 2) * sizeof (TCHAR_T) +                               bytes, so that in the next round, we likely get +                                 maxlen > (unsigned int) count + 1 +                               and so we don't get here again. +                               And allocate proportionally, to avoid looping +                               eternally if snprintf() reports a too small +                               count.  */ +                            size_t n = +                              xmax (xsum (length, +                                          ((unsigned int) count + 2 +                                           + TCHARS_PER_DCHAR - 1) +                                          / TCHARS_PER_DCHAR), +                                    xtimes (allocated, 2)); + +                            ENSURE_ALLOCATION (n); +                            continue; +                          } +                      } +#endif + +#if NEED_PRINTF_UNBOUNDED_PRECISION +                    if (prec_ourselves) +                      { +                        /* Handle the precision.  */ +                        TCHAR_T *prec_ptr = +# if USE_SNPRINTF +                          (TCHAR_T *) (result + length); +# else +                          tmp; +# endif +                        size_t prefix_count; +                        size_t move; + +                        prefix_count = 0; +                        /* Put the additional zeroes after the sign.  */ +                        if (count >= 1 +                            && (*prec_ptr == '-' || *prec_ptr == '+' +                                || *prec_ptr == ' ')) +                          prefix_count = 1; +                        /* Put the additional zeroes after the 0x prefix if +                           (flags & FLAG_ALT) || (dp->conversion == 'p').  */ +                        else if (count >= 2 +                                 && prec_ptr[0] == '0' +                                 && (prec_ptr[1] == 'x' || prec_ptr[1] == 'X')) +                          prefix_count = 2; + +                        move = count - prefix_count; +                        if (precision > move) +                          { +                            /* Insert zeroes.  */ +                            size_t insert = precision - move; +                            TCHAR_T *prec_end; + +# if USE_SNPRINTF +                            size_t n = +                              xsum (length, +                                    (count + insert + TCHARS_PER_DCHAR - 1) +                                    / TCHARS_PER_DCHAR); +                            length += (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR; +                            ENSURE_ALLOCATION (n); +                            length -= (count + TCHARS_PER_DCHAR - 1) / TCHARS_PER_DCHAR; +                            prec_ptr = (TCHAR_T *) (result + length); +# endif + +                            prec_end = prec_ptr + count; +                            prec_ptr += prefix_count; + +                            while (prec_end > prec_ptr) +                              { +                                prec_end--; +                                prec_end[insert] = prec_end[0]; +                              } + +                            prec_end += insert; +                            do +                              *--prec_end = '0'; +                            while (prec_end > prec_ptr); + +                            count += insert; +                          } +                      } +#endif + +#if !USE_SNPRINTF +                    if (count >= tmp_length) +                      /* tmp_length was incorrectly calculated - fix the +                         code above!  */ +                      abort (); +#endif + +#if !DCHAR_IS_TCHAR +                    /* Convert from TCHAR_T[] to DCHAR_T[].  */ +                    if (dp->conversion == 'c' || dp->conversion == 's') +                      { +                        /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING +                           TYPE_WIDE_STRING. +                           The result string is not certainly ASCII.  */ +                        const TCHAR_T *tmpsrc; +                        DCHAR_T *tmpdst; +                        size_t tmpdst_len; +                        /* This code assumes that TCHAR_T is 'char'.  */ +                        verify (sizeof (TCHAR_T) == 1); +# if USE_SNPRINTF +                        tmpsrc = (TCHAR_T *) (result + length); +# else +                        tmpsrc = tmp; +# endif +                        tmpdst = +                          DCHAR_CONV_FROM_ENCODING (locale_charset (), +                                                    iconveh_question_mark, +                                                    tmpsrc, count, +                                                    NULL, +                                                    NULL, &tmpdst_len); +                        if (tmpdst == NULL) +                          { +                            int saved_errno = errno; +                            if (!(result == resultbuf || result == NULL)) +                              free (result); +                            if (buf_malloced != NULL) +                              free (buf_malloced); +                            CLEANUP (); +                            errno = saved_errno; +                            return NULL; +                          } +                        ENSURE_ALLOCATION (xsum (length, tmpdst_len)); +                        DCHAR_CPY (result + length, tmpdst, tmpdst_len); +                        free (tmpdst); +                        count = tmpdst_len; +                      } +                    else +                      { +                        /* The result string is ASCII. +                           Simple 1:1 conversion.  */ +# if USE_SNPRINTF +                        /* If sizeof (DCHAR_T) == sizeof (TCHAR_T), it's a +                           no-op conversion, in-place on the array starting +                           at (result + length).  */ +                        if (sizeof (DCHAR_T) != sizeof (TCHAR_T)) +# endif +                          { +                            const TCHAR_T *tmpsrc; +                            DCHAR_T *tmpdst; +                            size_t n; + +# if USE_SNPRINTF +                            if (result == resultbuf) +                              { +                                tmpsrc = (TCHAR_T *) (result + length); +                                /* ENSURE_ALLOCATION will not move tmpsrc +                                   (because it's part of resultbuf).  */ +                                ENSURE_ALLOCATION (xsum (length, count)); +                              } +                            else +                              { +                                /* ENSURE_ALLOCATION will move the array +                                   (because it uses realloc().  */ +                                ENSURE_ALLOCATION (xsum (length, count)); +                                tmpsrc = (TCHAR_T *) (result + length); +                              } +# else +                            tmpsrc = tmp; +                            ENSURE_ALLOCATION (xsum (length, count)); +# endif +                            tmpdst = result + length; +                            /* Copy backwards, because of overlapping.  */ +                            tmpsrc += count; +                            tmpdst += count; +                            for (n = count; n > 0; n--) +                              *--tmpdst = (unsigned char) *--tmpsrc; +                          } +                      } +#endif + +#if DCHAR_IS_TCHAR && !USE_SNPRINTF +                    /* Make room for the result.  */ +                    if (count > allocated - length) +                      { +                        /* Need at least count elements.  But allocate +                           proportionally.  */ +                        size_t n = +                          xmax (xsum (length, count), xtimes (allocated, 2)); + +                        ENSURE_ALLOCATION (n); +                      } +#endif + +                    /* Here count <= allocated - length.  */ + +                    /* Perform padding.  */ +#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION +                    if (pad_ourselves && has_width) +                      { +                        size_t w; +# if ENABLE_UNISTDIO +                        /* Outside POSIX, it's preferable to compare the width +                           against the number of _characters_ of the converted +                           value.  */ +                        w = DCHAR_MBSNLEN (result + length, count); +# else +                        /* The width is compared against the number of _bytes_ +                           of the converted value, says POSIX.  */ +                        w = count; +# endif +                        if (w < width) +                          { +                            size_t pad = width - w; + +                            /* Make room for the result.  */ +                            if (xsum (count, pad) > allocated - length) +                              { +                                /* Need at least count + pad elements.  But +                                   allocate proportionally.  */ +                                size_t n = +                                  xmax (xsum3 (length, count, pad), +                                        xtimes (allocated, 2)); + +# if USE_SNPRINTF +                                length += count; +                                ENSURE_ALLOCATION (n); +                                length -= count; +# else +                                ENSURE_ALLOCATION (n); +# endif +                              } +                            /* Here count + pad <= allocated - length.  */ + +                            { +# if !DCHAR_IS_TCHAR || USE_SNPRINTF +                              DCHAR_T * const rp = result + length; +# else +                              DCHAR_T * const rp = tmp; +# endif +                              DCHAR_T *p = rp + count; +                              DCHAR_T *end = p + pad; +                              DCHAR_T *pad_ptr; +# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO +                              if (dp->conversion == 'c' +                                  || dp->conversion == 's') +                                /* No zero-padding for string directives.  */ +                                pad_ptr = NULL; +                              else +# endif +                                { +                                  pad_ptr = (*rp == '-' ? rp + 1 : rp); +                                  /* No zero-padding of "inf" and "nan".  */ +                                  if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z') +                                      || (*pad_ptr >= 'a' && *pad_ptr <= 'z')) +                                    pad_ptr = NULL; +                                } +                              /* The generated string now extends from rp to p, +                                 with the zero padding insertion point being at +                                 pad_ptr.  */ + +                              count = count + pad; /* = end - rp */ + +                              if (flags & FLAG_LEFT) +                                { +                                  /* Pad with spaces on the right.  */ +                                  for (; pad > 0; pad--) +                                    *p++ = ' '; +                                } +                              else if ((flags & FLAG_ZERO) && pad_ptr != NULL) +                                { +                                  /* Pad with zeroes.  */ +                                  DCHAR_T *q = end; + +                                  while (p > pad_ptr) +                                    *--q = *--p; +                                  for (; pad > 0; pad--) +                                    *p++ = '0'; +                                } +                              else +                                { +                                  /* Pad with spaces on the left.  */ +                                  DCHAR_T *q = end; + +                                  while (p > rp) +                                    *--q = *--p; +                                  for (; pad > 0; pad--) +                                    *p++ = ' '; +                                } +                            } +                          } +                      } +#endif + +                    /* Here still count <= allocated - length.  */ + +#if !DCHAR_IS_TCHAR || USE_SNPRINTF +                    /* The snprintf() result did fit.  */ +#else +                    /* Append the sprintf() result.  */ +                    memcpy (result + length, tmp, count * sizeof (DCHAR_T)); +#endif +#if !USE_SNPRINTF +                    if (tmp != tmpbuf) +                      free (tmp); +#endif + +#if NEED_PRINTF_DIRECTIVE_F +                    if (dp->conversion == 'F') +                      { +                        /* Convert the %f result to upper case for %F.  */ +                        DCHAR_T *rp = result + length; +                        size_t rc; +                        for (rc = count; rc > 0; rc--, rp++) +                          if (*rp >= 'a' && *rp <= 'z') +                            *rp = *rp - 'a' + 'A'; +                      } +#endif + +                    length += count; +                    break; +                  } +                errno = orig_errno; +#undef pad_ourselves +#undef prec_ourselves +              } +          } +      } + +    /* Add the final NUL.  */ +    ENSURE_ALLOCATION (xsum (length, 1)); +    result[length] = '\0'; + +    if (result != resultbuf && length + 1 < allocated) +      { +        /* Shrink the allocated memory if possible.  */ +        DCHAR_T *memory; + +        memory = (DCHAR_T *) realloc (result, (length + 1) * sizeof (DCHAR_T)); +        if (memory != NULL) +          result = memory; +      } + +    if (buf_malloced != NULL) +      free (buf_malloced); +    CLEANUP (); +    *lengthp = length; +    /* Note that we can produce a big string of a length > INT_MAX.  POSIX +       says that snprintf() fails with errno = EOVERFLOW in this case, but +       that's only because snprintf() returns an 'int'.  This function does +       not have this limitation.  */ +    return result; + +#if USE_SNPRINTF +  overflow: +    if (!(result == resultbuf || result == NULL)) +      free (result); +    if (buf_malloced != NULL) +      free (buf_malloced); +    CLEANUP (); +    errno = EOVERFLOW; +    return NULL; +#endif + +  out_of_memory: +    if (!(result == resultbuf || result == NULL)) +      free (result); +    if (buf_malloced != NULL) +      free (buf_malloced); +  out_of_memory_1: +    CLEANUP (); +    errno = ENOMEM; +    return NULL; +  } +} + +#undef MAX_ROOM_NEEDED +#undef TCHARS_PER_DCHAR +#undef SNPRINTF +#undef USE_SNPRINTF +#undef DCHAR_SET +#undef DCHAR_CPY +#undef PRINTF_PARSE +#undef DIRECTIVES +#undef DIRECTIVE +#undef DCHAR_IS_TCHAR +#undef TCHAR_T +#undef DCHAR_T +#undef FCHAR_T +#undef VASNPRINTF | 
