/* vsprintf with automatic memory allocation.
Copyright (C) 1999, 2002-2010 Free Software Foundation, Inc.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* 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().
<features.h>, and once <features.h> has been included, it's too late. */
#ifndef _GNU_SOURCE
#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 <math.h>
# include "float+.h"
#endif
# include <math.h>
# include "isnand-nolibm.h"
#endif
# include <math.h>
# include "isnanl-nolibm.h"
# include "fpucw.h"
#endif
# include <math.h>
# include "isnand-nolibm.h"
# include "printf-frexp.h"
#endif
# include <math.h>
# include "isnanl-nolibm.h"
# include "printf-frexpl.h"
# include "fpucw.h"
#endif
/* Default parameters. */
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
# else
# define FCHAR_T char
# define DCHAR_T char
# define TCHAR_T char
# endif
#endif
/* TCHAR_T is wchar_t. */
# 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__
# else
# endif
# else
/* Unix. */
# 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. */
# 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__
/* Here we need to call the native snprintf, not rpl_snprintf. */
# else
# endif
# else
/* Unix. */
/* Here we need to call the native snprintf, not rpl_snprintf. */
# endif
#endif
/* Here we need to call the native sprintf, not rpl_sprintf. */
/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
warnings in this file. Use -Dlint to suppress them. */
#ifdef lint
#else
#endif
/* Avoid some warnings from "gcc -Wshadow".
This file doesn't use the exp() and remainder() functions. */
# if (HAVE_STRNLEN && !defined _AIX)
# else
# ifndef local_strnlen_defined
static size_t
{
}
# 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
# 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
static size_t
{
;
return ptr - s;
}
# endif
# endif
#endif
# if HAVE_WCSNLEN
# else
# ifndef local_wcsnlen_defined
static size_t
{
;
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
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 MacOS X systems, but is not required
to be multithread-safe by POSIX. sprintf(), however, is multithread-safe.
localeconv() is rarely multithread-safe. */
# elif 1
# else
# endif
/* The decimal point is always a single byte: either '.' or ','. */
}
# endif
#endif
/* 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
/* 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
/* 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;
typedef unsigned long long mp_twolimb_t;
/* Representation of a bignum >= 0. */
typedef struct
{
} 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 *
{
{
}
else
{
}
/* Now 0 <= len1 <= len2. */
if (len1 == 0)
{
/* src1 or src2 is zero. */
}
else
{
/* Here 1 <= len1 <= len2. */
size_t k, i, j;
return NULL;
for (k = len2; k > 0; )
dp[--k] = 0;
for (i = 0; i < len1; i++)
{
for (j = 0; j < len2; j++)
{
}
}
/* Normalise. */
dlen--;
}
}
/* 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 *
{
/* 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.
*/
/* 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.) */
return NULL;
/* Normalise a. */
a_len--;
/* Normalise b. */
for (;;)
{
if (b_len == 0)
/* Division by zero. */
abort ();
b_len--;
else
break;
}
/* Here m = a_len >= 0 and n = b_len > 0. */
{
/* m<n: trivial case. q=0, r := copy of a. */
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 */
{
{
}
/* Normalise and store r. */
if (remainder > 0)
{
r_len = 1;
}
else
r_len = 0;
/* Normalise q. */
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;
{
s = 31;
if (msd >= 0x10000)
{
s -= 16;
}
if (msd >= 0x100)
{
s -= 8;
}
if (msd >= 0x10)
{
s -= 4;
}
if (msd >= 0x4)
{
s -= 2;
}
if (msd >= 0x2)
{
s -= 1;
}
}
/* 0 <= s < GMP_LIMB_BITS.
Copy b, shifting it left by s bits. */
if (s > 0)
{
if (tmp_roomptr == NULL)
{
return NULL;
}
{
{
}
/* 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] */
if (s == 0)
{
}
else
{
{
}
}
{
/* Division loop, traversed m-n+1 times.
j counts down, b is unchanged, beta/2 <= b[n-1] < beta. */
for (;;)
{
{
/* Divide r[j+n]*beta+r[j+n-1] by b[n-1], no overflow. */
}
else
{
/* Overflow, hence r[j+n]*beta+r[j+n-1] >= beta*b[n-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] ) */
/* 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). */
{
/* 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 (q_star > 0)
{
/* Subtract r := r - b * q* * beta^j. */
{
{
/* Here 0 <= carry <= q*. */
carry =
/* Here 0 <= carry <= beta*q* + beta-1. */
}
}
/* Subtract cr from r_ptr[j + b_len], then forget about
r_ptr[j + b_len]. */
{
/* Subtraction gave a carry. */
/* Add b back. */
{
{
carry =
}
}
/* Forget about the carry and about r[j+n]. */
}
}
/* q* is determined. Store it as q[j]. */
if (j == 0)
break;
j--;
}
}
/* Normalise q. */
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_twolimb_t accu = 0;
{
}
}
# endif
/* Normalise r. */
r_len--;
}
/* Compare r << 1 with b. */
goto increment_q;
{
size_t i;
for (i = b_len;;)
{
goto increment_q;
goto keep_q;
if (i == 0)
break;
i--;
}
}
/* q is odd. */
{
size_t i;
for (i = 0; i < q_len; i++)
if (++(q_ptr[i]) != 0)
goto keep_q;
}
if (tmp_roomptr != NULL)
free (tmp_roomptr);
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 *
{
/* 0.03345 is slightly larger than log(2)/(9*log(10)). */
{
for (; extra_zeroes > 0; extra_zeroes--)
*d_ptr++ = '0';
while (a_len > 0)
{
/* Divide a by 10^9, in-place. */
{
}
/* Store the remainder as 9 decimal digits. */
{
}
/* Normalize a. */
a_len--;
}
/* Remove leading zeroes. */
d_ptr--;
/* But keep at least one zero. */
*d_ptr++ = '0';
/* Terminate the string. */
*d_ptr = '\0';
}
return c_ptr;
}
/* 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 *
{
mpn_t m;
int exp;
long double y;
size_t i;
/* Allocate memory for result. */
return NULL;
/* Split into exponential part and mantissa. */
if (!(y >= 0.0L && y < 1.0L))
abort ();
/* x = 2^exp * y = 2^(exp - LDBL_MANT_BIT) * (y * LDBL_MANT_BIT), and the
latter is an integer. */
/* Convert the mantissa (y * 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
{
hi = (int) y;
y -= hi;
if (!(y >= 0.0L && y < 1.0L))
abort ();
lo = (int) y;
y -= lo;
if (!(y >= 0.0L && y < 1.0L))
abort ();
}
# else
{
mp_limb_t d;
d = (int) y;
y -= d;
if (!(y >= 0.0L && y < 1.0L))
abort ();
}
# endif
# endif
for (i = LDBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
{
hi = (int) y;
y -= hi;
if (!(y >= 0.0L && y < 1.0L))
abort ();
lo = (int) y;
y -= lo;
if (!(y >= 0.0L && y < 1.0L))
abort ();
}
#if 0 /* On FreeBSD 6.1/x86, 'long double' numbers sometimes have excess
precision. */
if (!(y == 0.0L))
abort ();
#endif
/* Normalise. */
m.nlimbs--;
*mp = m;
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 *
{
mpn_t m;
int exp;
double y;
size_t i;
/* Allocate memory for result. */
return NULL;
/* Split into exponential part and mantissa. */
if (!(y >= 0.0 && y < 1.0))
abort ();
/* x = 2^exp * y = 2^(exp - DBL_MANT_BIT) * (y * DBL_MANT_BIT), and the
latter is an integer. */
/* Convert the mantissa (y * 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
{
hi = (int) y;
y -= hi;
if (!(y >= 0.0 && y < 1.0))
abort ();
lo = (int) y;
y -= lo;
if (!(y >= 0.0 && y < 1.0))
abort ();
}
# else
{
mp_limb_t d;
d = (int) y;
y -= d;
if (!(y >= 0.0 && y < 1.0))
abort ();
}
# endif
# endif
for (i = DBL_MANT_BIT / GMP_LIMB_BITS; i > 0; )
{
hi = (int) y;
y -= hi;
if (!(y >= 0.0 && y < 1.0))
abort ();
lo = (int) y;
y -= lo;
if (!(y >= 0.0 && y < 1.0))
abort ();
}
if (!(y == 0.0))
abort ();
/* Normalise. */
m.nlimbs--;
*mp = m;
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 *
{
int s;
unsigned int abs_n;
unsigned int abs_s;
unsigned int s_limbs;
unsigned int s_bits;
mpn_t z;
void *z_memory;
char *digits;
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);
* sizeof (mp_limb_t));
{
return NULL;
}
/* Initialize with 1. */
pow5_ptr[0] = 1;
pow5_len = 1;
/* Multiply with 5^|n|. */
if (abs_n > 0)
{
{
1, 5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625,
48828125, 244140625, 1220703125
};
unsigned int n13;
{
size_t j;
for (j = 0; j < pow5_len; j++)
{
}
if (carry > 0)
}
}
if (n >= 0 ? s >= 0 : s <= 0)
{
/* Multiply with 2^|s|. */
if (s_bits > 0)
{
{
}
if (accu > 0)
{
pow5_len++;
}
}
if (s_limbs > 0)
{
{
count--;
}
{
count--;
}
}
if (n >= 0)
{
/* Multiply m with pow5. No division needed. */
}
else
{
/* Divide m by pow5 and round. */
}
}
else
{
if (n >= 0)
{
/* n >= 0, s < 0.
Multiply m with pow5, then divide by 2^|s|. */
void *tmp_memory;
if (tmp_memory == NULL)
{
return NULL;
}
/* Construct 2^|s|. */
{
size_t i;
for (i = 0; i < s_limbs; i++)
ptr[i] = 0;
}
free (tmp_memory);
}
else
{
/* n < 0, s > 0.
Multiply m with 2^s, then divide by pow5. */
* sizeof (mp_limb_t));
{
return NULL;
}
{
{
size_t i;
for (i = 0; i < s_limbs; i++)
*destptr++ = 0;
}
if (s_bits > 0)
{
{
}
if (accu > 0)
}
else
{
}
}
}
}
/* Here y = round (x * 10^n) = z * 10^extra_zeroes. */
return NULL;
return digits;
}
/* 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;
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;
return scale10_round_decimal_decoded (e, m, memory, n);
}
# endif
/* 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. */
if (!(y >= 0.0L && y < 1.0L))
abort ();
if (y == 0.0L)
return INT_MIN;
if (y < 0.5L)
{
{
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. */
if (!(y >= 0.0 && y < 1.0))
abort ();
if (y == 0.0)
return INT_MIN;
if (y < 0.5)
{
{
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
{
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
# else
# 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 inline size_t
{
switch (conversion)
{
case 'd': case 'i': case 'u':
# if HAVE_LONG_LONG_INT
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
else
# endif
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
else
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.30103 /* binary -> decimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
/* Multiply by 2, as an estimate for FLAG_GROUP. */
/* Add 1, to account for a leading sign. */
break;
case 'o':
# if HAVE_LONG_LONG_INT
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
else
# endif
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
else
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
/* Add 1, to account for a leading sign. */
break;
case 'x': case 'X':
# if HAVE_LONG_LONG_INT
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
# endif
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
/* Add 2, to account for a leading sign or alternate form. */
break;
case 'f': case 'F':
if (type == TYPE_LONGDOUBLE)
(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
(unsigned int) (DBL_MAX_EXP
* 0.30103 /* binary -> decimal */
* 2 /* estimate for FLAG_GROUP */
)
+ 1 /* turn floor into ceil */
+ 10; /* sign, decimal point etc. */
break;
case 'e': case 'E': case 'g': case 'G':
12; /* sign, decimal point, exponent etc. */
break;
case 'a': case 'A':
if (type == TYPE_LONGDOUBLE)
(unsigned int) (LDBL_DIG
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
(unsigned int) (DBL_DIG
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
/* Account for sign, decimal point etc. */
break;
case 'c':
# if HAVE_WINT_T && !WIDE_CHAR_VERSION
if (type == TYPE_WIDE_CHAR)
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. */
if (has_precision)
else
# 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. */
if (has_precision)
else
# endif
}
break;
case 'p':
(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. */
# else
/* Padding considers the number of elements, says POSIX. */
if (tmp_length < width)
tmp_length = width;
# endif
}
return tmp_length;
}
#endif
DCHAR_T *
{
DIRECTIVES d;
arguments a;
if (PRINTF_PARSE (format, &d, &a) < 0)
/* errno is already set. */
return NULL;
#define CLEANUP() \
if (a.arg) \
if (PRINTF_FETCHARGS (args, &a) < 0)
{
CLEANUP ();
return NULL;
}
{
size_t i;
/* Output string accumulator. */
/* Allocate a small buffer that will hold a directive passed to
sprintf or snprintf. */
#if HAVE_ALLOCA
{
buf_malloced = NULL;
}
else
#endif
{
if (size_overflow_p (buf_memsize))
goto out_of_memory_1;
goto out_of_memory_1;
buf_malloced = buf;
}
{
}
else
{
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. */
{ \
\
if (size_overflow_p (memory_size)) \
goto out_of_memory; \
else \
goto out_of_memory; \
}
{
{
/* 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. */
{
}
else
{
do
while (--n > 0);
}
}
if (i == d.count)
break;
/* Execute a single directive. */
{
abort ();
}
else
{
abort ();
{
{
case TYPE_COUNT_SCHAR_POINTER:
break;
case TYPE_COUNT_SHORT_POINTER:
break;
case TYPE_COUNT_INT_POINTER:
break;
break;
break;
#endif
default:
abort ();
}
}
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
{
int has_width;
int has_precision;
has_width = 0;
width = 0;
{
{
int arg;
abort ();
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
}
else
}
else
{
do
}
has_width = 1;
}
has_precision = 0;
precision = 0;
{
{
int arg;
abort ();
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
has_precision = 1;
}
}
else
{
precision = 0;
has_precision = 1;
}
}
switch (type)
{
case TYPE_U8_STRING:
{
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
characters = 0;
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
characters = 0;
for (;;)
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else
{
/* Use the entire string. */
/* The number of characters doesn't matter. */
characters = 0;
}
{
length += n;
}
# if DCHAR_IS_UINT8_T
{
length += n;
}
# else
{ /* Convert. */
# if DCHAR_IS_TCHAR
/* Convert from UTF-8 to locale encoding. */
# else
# endif
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
{
}
length += converted_len;
}
# endif
{
length += n;
}
}
break;
case TYPE_U16_STRING:
{
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
characters = 0;
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
characters = 0;
for (;;)
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else
{
/* Use the entire string. */
/* The number of characters doesn't matter. */
characters = 0;
}
{
length += n;
}
# if DCHAR_IS_UINT16_T
{
length += n;
}
# else
{ /* Convert. */
# if DCHAR_IS_TCHAR
/* Convert from UTF-16 to locale encoding. */
# else
# endif
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
{
}
length += converted_len;
}
# endif
{
length += n;
}
}
break;
case TYPE_U32_STRING:
{
if (has_precision)
{
/* Use only PRECISION characters, from the left. */
characters = 0;
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of
characters. */
characters = 0;
for (;;)
{
if (count == 0)
break;
if (count < 0)
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else
{
/* Use the entire string. */
/* The number of characters doesn't matter. */
characters = 0;
}
{
length += n;
}
# if DCHAR_IS_UINT32_T
{
length += n;
}
# else
{ /* Convert. */
# if DCHAR_IS_TCHAR
/* Convert from UTF-32 to locale encoding. */
# else
# endif
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
{
}
length += converted_len;
}
# endif
{
length += n;
}
}
break;
default:
abort ();
}
}
#endif
#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
# if WIDE_CHAR_VERSION
# else
# 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 has_width;
int has_precision;
has_width = 0;
width = 0;
{
{
int arg;
abort ();
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
}
else
}
else
{
do
}
has_width = 1;
}
has_precision = 0;
precision = 6;
{
{
int arg;
abort ();
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
has_precision = 1;
}
}
else
{
precision = 0;
has_precision = 1;
}
}
# if WIDE_CHAR_VERSION
/* %s in vasnwprintf. See the specification of fwprintf. */
{
const char *arg_end;
if (has_precision)
{
/* Use only as many bytes as needed to produce PRECISION
wide characters, from the left. */
# if HAVE_MBRTOWC
# endif
characters = 0;
{
int count;
# if HAVE_MBRTOWC
# else
# endif
if (count == 0)
/* Found the terminating NUL. */
break;
if (count < 0)
{
/* Invalid or incomplete multibyte character. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else if (has_width)
{
/* Use the entire string, and count the number of wide
characters. */
# if HAVE_MBRTOWC
# endif
characters = 0;
for (;;)
{
int count;
# if HAVE_MBRTOWC
# else
# endif
if (count == 0)
/* Found the terminating NUL. */
break;
if (count < 0)
{
/* Invalid or incomplete multibyte character. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
characters++;
}
}
else
{
/* Use the entire string. */
/* The number of characters doesn't matter. */
characters = 0;
}
{
length += n;
}
if (has_precision || has_width)
{
/* We know the number of wide characters in advance. */
# if HAVE_MBRTOWC
# endif
{
int count;
# if HAVE_MBRTOWC
# else
# endif
if (count <= 0)
/* mbrtowc not consistent with mbrlen, or mbtowc
not consistent with mblen. */
abort ();
}
abort ();
}
else
{
# if HAVE_MBRTOWC
# endif
{
int count;
# if HAVE_MBRTOWC
# else
# endif
if (count <= 0)
/* mbrtowc not consistent with mbrlen, or mbtowc
not consistent with mblen. */
abort ();
}
}
{
length += n;
}
}
# else
/* %ls in vasnprintf. See the specification of fprintf. */
{
# if !DCHAR_IS_TCHAR
/* This code assumes that TCHAR_T is 'char'. */
# 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
# endif
characters = 0;
while (precision > 0)
{
int count;
if (*arg_end == 0)
/* Found the terminating null wide character. */
break;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# else
# endif
if (count < 0)
{
/* Cannot convert. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
break;
arg_end++;
characters += 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
# endif
characters = 0;
for (;;)
{
int count;
if (*arg_end == 0)
/* Found the terminating null wide character. */
break;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# else
# endif
if (count < 0)
{
/* Cannot convert. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
arg_end++;
characters += count;
}
}
# if DCHAR_IS_TCHAR
else
{
/* Use the entire string. */
/* The number of bytes doesn't matter. */
characters = 0;
}
# endif
# if !DCHAR_IS_TCHAR
/* Convert the string into a piece of temporary memory. */
goto out_of_memory;
{
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# endif
{
int count;
if (*arg == 0)
abort ();
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# else
# endif
if (count <= 0)
/* Inconsistency. */
abort ();
arg++;
}
abort ();
}
/* Convert from TCHAR_T[] to DCHAR_T[]. */
tmpdst =
NULL,
NULL, &tmpdst_len);
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
# endif
if (has_width)
{
# if ENABLE_UNISTDIO
/* Outside POSIX, it's preferrable to compare the width
against the number of _characters_ of the converted
value. */
# 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;
{
length += n;
}
# if DCHAR_IS_TCHAR
if (has_precision || has_width)
{
/* We know the number of bytes in advance. */
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# endif
{
int count;
if (*arg == 0)
abort ();
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# else
# endif
if (count <= 0)
/* Inconsistency. */
abort ();
arg++;
}
abort ();
}
else
{
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# endif
{
int count;
if (*arg == 0)
abort ();
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
# else
# endif
if (count <= 0)
{
/* Cannot convert. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
arg++;
}
}
# else
length += tmpdst_len;
# endif
{
length += n;
}
}
# endif
}
#endif
#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
&& (0
# if NEED_PRINTF_DOUBLE
# endif
# endif
)
# endif
)
{
int has_width;
int has_precision;
DCHAR_T *p;
has_width = 0;
width = 0;
{
{
int arg;
abort ();
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
}
else
}
else
{
do
}
has_width = 1;
}
has_precision = 0;
precision = 0;
{
{
int arg;
abort ();
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
has_precision = 1;
}
}
else
{
precision = 0;
has_precision = 1;
}
}
/* Allocate a temporary buffer of sufficient size. */
if (type == TYPE_LONGDOUBLE)
(unsigned int) ((LDBL_DIG + 1)
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
else
(unsigned int) ((DBL_DIG + 1)
* 0.831 /* decimal -> hexadecimal */
)
+ 1; /* turn floor into ceil */
if (tmp_length < precision)
/* Account for sign, decimal point etc. */
if (tmp_length < width)
tmp_length = width;
else
{
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
/* Out of memory. */
goto out_of_memory;
}
p = tmp;
if (type == TYPE_LONGDOUBLE)
{
{
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
{
sign = -1;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
{
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
int exponent;
long double mantissa;
if (arg > 0.0L)
else
{
exponent = 0;
mantissa = 0.0L;
}
if (has_precision
{
/* Round the mantissa. */
size_t q;
for (q = precision; ; q--)
{
if (q == 0)
{
else
break;
}
tail *= 16.0L;
}
if (tail != 0.0L)
for (q = precision; q > 0; q--)
tail *= 0.0625L;
}
*p++ = '0';
pad_ptr = p;
{
int digit;
*p++ = '0' + digit;
{
*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;
*p++ = digit
+ (digit < 10
? '0'
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
# if WIDE_CHAR_VERSION
{
{ '%', '+', 'd', '\0' };
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *ep;
p++;
}
# endif
}
}
# else
abort ();
# endif
}
else
{
{
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
{
sign = -1;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
{
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
int exponent;
double mantissa;
if (arg > 0.0)
else
{
exponent = 0;
mantissa = 0.0;
}
if (has_precision
{
/* Round the mantissa. */
size_t q;
for (q = precision; ; q--)
{
if (q == 0)
{
else
break;
}
tail *= 16.0;
}
if (tail != 0.0)
for (q = precision; q > 0; q--)
tail *= 0.0625;
}
*p++ = '0';
pad_ptr = p;
{
int digit;
*p++ = '0' + digit;
{
*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;
*p++ = digit
+ (digit < 10
? '0'
if (precision > 0)
precision--;
}
while (precision > 0)
{
*p++ = '0';
precision--;
}
}
}
# if WIDE_CHAR_VERSION
{
{ '%', '+', 'd', '\0' };
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *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. */
{
{
/* Pad with spaces on the right. */
*p++ = ' ';
}
{
/* Pad with zeroes. */
while (p > pad_ptr)
*--q = *--p;
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
while (p > tmp)
*--q = *--p;
*p++ = ' ';
}
p = end;
}
{
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
{
ENSURE_ALLOCATION (n);
}
/* Append the result. */
}
}
#endif
#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
&& (0
# if NEED_PRINTF_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. */
# endif
/* 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. */
# endif
))
{
# if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE)
# endif
int has_width;
int has_precision;
DCHAR_T *p;
has_width = 0;
width = 0;
{
{
int arg;
abort ();
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
}
else
}
else
{
do
}
has_width = 1;
}
has_precision = 0;
precision = 0;
{
{
int arg;
abort ();
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
has_precision = 1;
}
}
else
{
precision = 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)
precision = 6;
/* Allocate a temporary buffer of sufficient size. */
# else
tmp_length = 0;
# endif
if (tmp_length < precision)
if (type == TYPE_LONGDOUBLE)
# endif
{
{
/* arg is finite and nonzero. */
}
}
# endif
# if NEED_PRINTF_DOUBLE
if (type == TYPE_DOUBLE)
# endif
{
{
/* arg is finite and nonzero. */
}
}
# endif
/* Account for sign, decimal point etc. */
if (tmp_length < width)
tmp_length = width;
else
{
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
/* Out of memory. */
goto out_of_memory;
}
p = tmp;
if (type == TYPE_LONGDOUBLE)
# endif
{
{
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
{
sign = -1;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
{
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
pad_ptr = p;
{
char *digits;
digits =
{
goto out_of_memory;
}
do
{
--ndigits;
}
else
*p++ = '0';
/* Here ndigits <= precision. */
{
*p++ = decimal_point_char ();
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
}
}
}
{
int exponent;
if (arg == 0.0L)
{
exponent = 0;
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
}
else
{
/* arg > 0.0L. */
int adjusted;
char *digits;
adjusted = 0;
for (;;)
{
digits =
{
goto out_of_memory;
}
break;
/* 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 ();
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = 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 =
{
goto out_of_memory;
}
{
exponent -= 1;
}
else
}
/* Here ndigits = precision+1. */
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
}
}
}
# if WIDE_CHAR_VERSION
{
{ '%', '+', '.', '2', 'd', '\0' };
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *ep;
p++;
}
# endif
}
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0L)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
/* Number of trailing zeroes that have to be
dropped. */
--ndigits;
*p++ = '0';
{
*p++ = decimal_point_char ();
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0L. */
int exponent;
int adjusted;
char *digits;
adjusted = 0;
for (;;)
{
digits =
{
goto out_of_memory;
}
break;
/* 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 ();
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = 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 =
{
goto out_of_memory;
}
{
exponent -= 1;
}
else
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
/* Note: count <= precision = ndigits. */
{
*p++ = decimal_point_char ();
{
--ndigits;
}
}
}
else
{
*p++ = '0';
*p++ = decimal_point_char ();
*p++ = '0';
{
--ndigits;
}
}
}
else
{
/* Exponential notation. */
{
*p++ = decimal_point_char ();
{
--ndigits;
}
}
# if WIDE_CHAR_VERSION
{
{ '%', '+', '.', '2', 'd', '\0' };
}
while (*p != '\0')
p++;
# else
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *ep;
p++;
}
# endif
}
}
}
else
abort ();
# else
/* arg is finite. */
if (!(arg == 0.0L))
abort ();
pad_ptr = p;
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
}
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
*p++ = '+';
*p++ = '0';
*p++ = '0';
}
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
}
{
*p++ = '0';
pad_ptr = p;
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
*p++ = '+';
*p++ = '0';
}
else
abort ();
# endif
}
}
}
else
# endif
# endif
{
{
{
*p++ = 'N'; *p++ = 'A'; *p++ = 'N';
}
else
{
*p++ = 'n'; *p++ = 'a'; *p++ = 'n';
}
}
else
{
int sign = 0;
{
sign = -1;
}
if (sign < 0)
*p++ = '-';
else if (flags & FLAG_SHOWSIGN)
*p++ = '+';
else if (flags & FLAG_SPACE)
*p++ = ' ';
{
{
*p++ = 'I'; *p++ = 'N'; *p++ = 'F';
}
else
{
*p++ = 'i'; *p++ = 'n'; *p++ = 'f';
}
}
else
{
# if NEED_PRINTF_DOUBLE
pad_ptr = p;
{
char *digits;
digits =
goto out_of_memory;
do
{
--ndigits;
}
else
*p++ = '0';
/* Here ndigits <= precision. */
{
*p++ = decimal_point_char ();
*p++ = '0';
while (ndigits > 0)
{
--ndigits;
}
}
}
{
int exponent;
if (arg == 0.0)
{
exponent = 0;
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
}
else
{
/* arg > 0.0. */
int adjusted;
char *digits;
adjusted = 0;
for (;;)
{
digits =
goto out_of_memory;
break;
/* 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 ();
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = 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 =
{
goto out_of_memory;
}
{
exponent -= 1;
}
else
}
/* Here ndigits = precision+1. */
{
*p++ = decimal_point_char ();
while (ndigits > 0)
{
--ndigits;
}
}
}
# if WIDE_CHAR_VERSION
{
/* Produce the same number of exponent digits
as the native printf implementation. */
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *ep;
p++;
}
}
# endif
}
{
if (precision == 0)
precision = 1;
/* precision >= 1. */
if (arg == 0.0)
/* The exponent is 0, >= -4, < precision.
Use fixed-point notation. */
{
/* Number of trailing zeroes that have to be
dropped. */
--ndigits;
*p++ = '0';
{
*p++ = decimal_point_char ();
{
--ndigits;
*p++ = '0';
}
}
}
else
{
/* arg > 0.0. */
int exponent;
int adjusted;
char *digits;
adjusted = 0;
for (;;)
{
digits =
goto out_of_memory;
break;
/* 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 ();
exponent -= 1;
else
exponent += 1;
adjusted = 1;
}
/* Here ndigits = 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 =
{
goto out_of_memory;
}
{
exponent -= 1;
}
else
}
/* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
nzeroes = 0;
nzeroes++;
/* The exponent is now determined. */
if (exponent >= -4
{
/* Fixed-point notation:
max(exponent,0)+1 digits, then the
decimal point, then the remaining
digits without trailing zeroes. */
if (exponent >= 0)
{
/* Note: count <= precision = ndigits. */
{
*p++ = decimal_point_char ();
{
--ndigits;
}
}
}
else
{
*p++ = '0';
*p++ = decimal_point_char ();
*p++ = '0';
{
--ndigits;
}
}
}
else
{
/* Exponential notation. */
{
*p++ = decimal_point_char ();
{
--ndigits;
}
}
# if WIDE_CHAR_VERSION
{
/* Produce the same number of exponent digits
as the native printf implementation. */
{ '%', '+', '.', '3', 'd', '\0' };
# else
{ '%', '+', '.', '2', 'd', '\0' };
# endif
}
while (*p != '\0')
p++;
# else
{
static const char decimal_format[] =
/* Produce the same number of exponent digits
as the native printf implementation. */
"%+.3d";
# else
"%+.2d";
# endif
if (sizeof (DCHAR_T) == 1)
{
while (*p != '\0')
p++;
}
else
{
const char *ep;
p++;
}
}
# endif
}
}
}
else
abort ();
# else
/* arg is finite. */
if (!(arg == 0.0))
abort ();
pad_ptr = p;
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
}
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*p++ = '0';
}
*p++ = '+';
/* Produce the same number of exponent digits as
the native printf implementation. */
*p++ = '0';
# endif
*p++ = '0';
*p++ = '0';
}
{
*p++ = '0';
{
*p++ = decimal_point_char ();
*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. */
{
{
/* Pad with spaces on the right. */
*p++ = ' ';
}
{
/* Pad with zeroes. */
while (p > pad_ptr)
*--q = *--p;
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
while (p > tmp)
*--q = *--p;
*p++ = ' ';
}
p = end;
}
{
if (count >= tmp_length)
/* tmp_length was incorrectly calculated - fix the
code above! */
abort ();
/* Make room for the result. */
{
ENSURE_ALLOCATION (n);
}
/* Append the result. */
}
}
#endif
else
{
#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;
#endif
int has_precision;
#endif
int prec_ourselves;
#else
# define prec_ourselves 0
#endif
#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int pad_ourselves;
#else
# define pad_ourselves 0
#endif
unsigned int prefix_count;
#if !USE_SNPRINTF
#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;
{
{
int arg;
abort ();
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
}
else
}
else
{
do
}
has_width = 1;
}
#endif
has_precision = 0;
precision = 6;
{
{
int arg;
abort ();
/* "A negative precision is taken as if the precision
were omitted." */
if (arg >= 0)
{
has_precision = 1;
}
}
else
{
precision = 0;
has_precision = 1;
}
}
#endif
/* Decide whether to handle the precision ourselves. */
switch (dp->conversion)
{
case 'd': case 'i': case 'u':
case 'o':
case 'x': case 'X': case 'p':
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
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
# endif
pad_ourselves = 1;
break;
default:
break;
}
#endif
#if !USE_SNPRINTF
/* Allocate a temporary buffer of sufficient size for calling
sprintf. */
else
{
if (size_overflow_p (tmp_memsize))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
/* Out of memory. */
goto out_of_memory;
}
#endif
/* Construct the format string for calling snprintf or
sprintf. */
*fbp++ = '%';
/* 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
*fbp++ = '-';
if (flags & FLAG_SHOWSIGN)
*fbp++ = '+';
if (flags & FLAG_SPACE)
*fbp++ = ' ';
*fbp++ = '#';
if (!pad_ourselves)
{
*fbp++ = '0';
{
/* The width specification is known to consist only
of standard ASCII characters. */
{
fbp += n;
}
else
{
do
while (--n > 0);
}
}
}
if (!prec_ourselves)
{
{
/* The precision specification is known to consist only
of standard ASCII characters. */
{
fbp += n;
}
else
{
do
while (--n > 0);
}
}
}
switch (type)
{
case TYPE_LONGLONGINT:
case TYPE_ULONGLONGINT:
*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;
}
*fbp = 'f';
else
#endif
#if USE_SNPRINTF
# if !(__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
# else
/* On glibc2 systems from glibc >= 2.3 - probably also older
ones - we know that snprintf's returns value conforms to
ISO C 99: the gl_SNPRINTF_DIRECTIVE_N test passes.
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 Win32 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 Win32 systems (such as mingw) where the OS is
Windows Vista, the use of %n in format strings by default
crashes the program. See
<http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx>
So we should avoid %n in this situation. */
# endif
#else
#endif
/* Construct the arguments for calling snprintf or sprintf. */
prefix_count = 0;
{
abort ();
}
{
abort ();
}
#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). */
/* Ensure that maxlen below will be >= 2. Needed on BeOS,
where an snprintf() with maxlen==1 acts like sprintf(). */
/ TCHARS_PER_DCHAR));
/* Prepare checking whether snprintf returns the count
via %n. */
#endif
for (;;)
{
#if USE_SNPRINTF
int retcount = 0;
/* SNPRINTF can fail if its second argument is
> INT_MAX. */
switch (prefix_count) \
{ \
case 0: \
break; \
case 1: \
break; \
case 2: \
&count); \
break; \
default: \
abort (); \
}
#else
switch (prefix_count) \
{ \
case 0: \
break; \
case 1: \
break; \
case 2: \
arg); \
break; \
default: \
abort (); \
}
#endif
errno = 0;
switch (type)
{
case TYPE_SCHAR:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_UCHAR:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_SHORT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_USHORT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_INT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_UINT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_LONGINT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_ULONGINT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_LONGLONGINT:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_ULONGLONGINT:
{
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_DOUBLE:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_LONGDOUBLE:
{
SNPRINTF_BUF (arg);
}
break;
case TYPE_CHAR:
{
SNPRINTF_BUF (arg);
}
break;
#if HAVE_WINT_T
case TYPE_WIDE_CHAR:
{
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_STRING:
{
SNPRINTF_BUF (arg);
}
break;
#if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
{
SNPRINTF_BUF (arg);
}
break;
#endif
case TYPE_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. */
abort ();
/* Portability hack. */
}
else
{
/* snprintf() doesn't understand the '%n'
directive. */
{
/* Don't use the '%n' directive; instead, look
at the snprintf() return value. */
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. */
if (maxlen < tmp_length)
{
/* Make more room. But try to do through
this reallocation only once. */
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.) */
if (bigger_need < bigger_need2)
continue;
}
# endif
}
else
}
}
#endif
/* Attempt to handle failure. */
if (count < 0)
{
/* SNPRINTF or sprintf failed. Save and use the errno
that it has set, if any. */
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno =
(saved_errno != 0
? 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 maxlen already has attained its allowed maximum,
allocating more memory will not increase maxlen.
Instead of looping, bail out. */
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 =
((unsigned int) count + 2
+ TCHARS_PER_DCHAR - 1)
/ TCHARS_PER_DCHAR),
ENSURE_ALLOCATION (n);
continue;
}
}
#endif
if (prec_ourselves)
{
/* Handle the precision. */
# if USE_SNPRINTF
# else
tmp;
# endif
prefix_count = 0;
/* Put the additional zeroes after the sign. */
if (count >= 1
|| *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'
prefix_count = 2;
{
/* Insert zeroes. */
# if USE_SNPRINTF
size_t n =
/ TCHARS_PER_DCHAR);
ENSURE_ALLOCATION (n);
# endif
prec_ptr += prefix_count;
{
prec_end--;
}
do
*--prec_end = '0';
}
}
#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[]. */
{
/* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
TYPE_WIDE_STRING.
The result string is not certainly ASCII. */
/* This code assumes that TCHAR_T is 'char'. */
typedef int TCHAR_T_verify
# if USE_SNPRINTF
# else
# endif
tmpdst =
NULL,
NULL, &tmpdst_len);
{
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
errno = saved_errno;
return NULL;
}
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). */
# endif
{
size_t n;
# if USE_SNPRINTF
{
/* ENSURE_ALLOCATION will not move tmpsrc
(because it's part of resultbuf). */
}
else
{
/* ENSURE_ALLOCATION will move the array
(because it uses realloc(). */
}
# else
# endif
/* Copy backwards, because of overlapping. */
for (n = count; n > 0; n--)
}
}
#endif
#if DCHAR_IS_TCHAR && !USE_SNPRINTF
/* Make room for the result. */
{
/* Need at least count elements. But allocate
proportionally. */
size_t n =
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 preferrable to compare the width
against the number of _characters_ of the converted
value. */
# else
/* The width is compared against the number of _bytes_
of the converted value, says POSIX. */
w = count;
# endif
if (w < width)
{
/* Make room for the result. */
{
/* Need at least count + pad elements. But
allocate proportionally. */
size_t n =
# if USE_SNPRINTF
ENSURE_ALLOCATION (n);
# else
ENSURE_ALLOCATION (n);
# endif
}
/* Here count + pad <= allocated - length. */
{
# if !DCHAR_IS_TCHAR || USE_SNPRINTF
# else
# endif
# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
/* No zero-padding for string directives. */
else
# endif
{
/* No zero-padding of "inf" and "nan". */
}
/* The generated string now extends from rp to p,
with the zero padding insertion point being at
pad_ptr. */
{
/* Pad with spaces on the right. */
*p++ = ' ';
}
{
/* Pad with zeroes. */
while (p > pad_ptr)
*--q = *--p;
*p++ = '0';
}
else
{
/* Pad with spaces on the left. */
while (p > rp)
*--q = *--p;
*p++ = ' ';
}
}
}
}
#endif
/* Here still count <= allocated - length. */
#if !DCHAR_IS_TCHAR || USE_SNPRINTF
/* The snprintf() result did fit. */
#else
/* Append the sprintf() result. */
#endif
#if !USE_SNPRINTF
#endif
{
/* Convert the %f result to upper case for %F. */
}
#endif
break;
}
}
}
}
/* Add the final NUL. */
{
/* Shrink the allocated memory if possible. */
}
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
/* 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
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
#endif
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
return NULL;
}
}