summaryrefslogtreecommitdiff
path: root/lib/vasnprintf.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff.email>2024-03-24 08:54:48 +0100
committerJörg Frings-Fürst <debian@jff.email>2024-03-24 08:54:48 +0100
commit163a663518f33bab48b28431972e580b366b4d49 (patch)
treef518ffabaca4a0b93f0103d617e803792d3b0b43 /lib/vasnprintf.c
parent1b3a8d5ad2ea2f099d514d9dd51ebf926a628076 (diff)
parentdd0000f7e25abe6c28d4329d324fd7fcab54094f (diff)
Merge branch 'release/debian/1.2-1'HEADdebian/1.2-1master
Diffstat (limited to 'lib/vasnprintf.c')
-rw-r--r--lib/vasnprintf.c1667
1 files changed, 1455 insertions, 212 deletions
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 01d18bf5..de204458 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -1,5 +1,5 @@
/* vsprintf with automatic memory allocation.
- Copyright (C) 1999, 2002-2022 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002-2024 Free Software Foundation, Inc.
This file is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
@@ -83,8 +83,9 @@
#include <stdio.h> /* snprintf(), sprintf() */
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
#include <string.h> /* memcpy(), strlen() */
+#include <wchar.h> /* mbstate_t, mbrtowc(), mbrlen(), wcrtomb(), mbszero() */
#include <errno.h> /* errno */
-#include <limits.h> /* CHAR_BIT */
+#include <limits.h> /* CHAR_BIT, INT_WIDTH, LONG_WIDTH */
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
#if HAVE_NL_LANGINFO
# include <langinfo.h>
@@ -102,29 +103,29 @@
#include "attribute.h"
-#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include <math.h>
# include "float+.h"
#endif
-#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE
# include <math.h>
# include "isnand-nolibm.h"
#endif
-#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include <math.h>
# include "isnanl-nolibm.h"
# include "fpucw.h"
#endif
-#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_DOUBLE
# include <math.h>
# include "isnand-nolibm.h"
# include "printf-frexp.h"
#endif
-#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
# include <math.h>
# include "isnanl-nolibm.h"
# include "printf-frexpl.h"
@@ -137,8 +138,6 @@
# 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
@@ -158,24 +157,32 @@
# 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
+ /* DCHAR_T is wchar_t. */
+# if HAVE_DECL__SNWPRINTF || (HAVE_SWPRINTF && HAVE_WORKING_SWPRINTF)
+# define TCHAR_T wchar_t
+# define DCHAR_IS_TCHAR 1
+# 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
+# define USE_MSVC__SNPRINTF 1
+# endif
# else
-# define SNPRINTF _snwprintf
-# define USE_MSVC__SNPRINTF 1
+ /* Unix. */
+# define SNPRINTF swprintf
# endif
# else
- /* Unix. */
-# define SNPRINTF swprintf
+ /* Old platforms such as NetBSD 3.0, OpenBSD 3.8, HP-UX 11.00, IRIX 6.5. */
+# define TCHAR_T char
# endif
-#else
+#endif
+#if !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR
/* 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
@@ -240,7 +247,7 @@ local_strnlen (const char *string, size_t maxlen)
# endif
#endif
-#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
+#if (((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_WPRINTF_DIRECTIVE_LC) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
# if HAVE_WCSLEN
# define local_wcslen wcslen
# else
@@ -263,8 +270,8 @@ local_wcslen (const wchar_t *s)
# endif
#endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
-# if HAVE_WCSNLEN
+#if (!USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+# if HAVE_WCSNLEN && HAVE_DECL_WCSNLEN
# define local_wcsnlen wcsnlen
# else
# ifndef local_wcsnlen_defined
@@ -282,12 +289,12 @@ local_wcsnlen (const wchar_t *s, size_t maxlen)
# endif
#endif
-#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || (ENABLE_WCHAR_FALLBACK && HAVE_WINT_T)) && !WIDE_CHAR_VERSION
+#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T)) && !WIDE_CHAR_VERSION
# if ENABLE_WCHAR_FALLBACK
static size_t
wctomb_fallback (char *s, wchar_t wc)
{
- static char hex[16] = "0123456789ABCDEF";
+ static char const hex[16] = "0123456789ABCDEF";
s[0] = '\\';
if (sizeof (wchar_t) > 2 && wc > 0xffff)
@@ -350,7 +357,7 @@ local_wctomb (char *s, wchar_t wc)
# 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
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
/* Determine the decimal-point character according to the current locale. */
# ifndef decimal_point_char_defined
# define decimal_point_char_defined 1
@@ -377,7 +384,7 @@ decimal_point_char (void)
# endif
#endif
-#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE && !defined IN_LIBINTL
+#if NEED_PRINTF_INFINITE_DOUBLE && !NEED_PRINTF_DOUBLE
/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
static int
@@ -388,7 +395,7 @@ is_infinite_or_zero (double x)
#endif
-#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE && !defined IN_LIBINTL
+#if NEED_PRINTF_INFINITE_LONG_DOUBLE && !NEED_PRINTF_LONG_DOUBLE
/* Equivalent to !isfinite(x) || x == 0, but does not require libm. */
static int
@@ -399,7 +406,7 @@ is_infinite_or_zerol (long double x)
#endif
-#if (NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE
/* Converting 'long double' to decimal without rare rounding bugs requires
real bignums. We use the naming conventions of GNU gmp, but vastly simpler
@@ -920,6 +927,14 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
return roomptr;
}
+/* Avoid pointless GCC warning "argument 1 value '18446744073709551615' exceeds
+ maximum object size 9223372036854775807", triggered by the use of xsum as
+ argument of malloc. */
+# if __GNUC__ >= 7
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Walloc-size-larger-than="
+# endif
+
/* Convert a bignum a >= 0, multiplied with 10^extra_zeroes, to decimal
representation.
Destroys the contents of a.
@@ -976,6 +991,10 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
return c_ptr;
}
+# if __GNUC__ >= 7
+# pragma GCC diagnostic pop
+# endif
+
# if NEED_PRINTF_LONG_DOUBLE
/* Assuming x is finite and >= 0:
@@ -1170,8 +1189,6 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
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). */
@@ -1379,10 +1396,13 @@ scale10_round_decimal_decoded (int e, mpn_t m, void *memory, int n)
static char *
scale10_round_decimal_long_double (long double x, int n)
{
- int e IF_LINT(= 0);
+ int e;
mpn_t m;
void *memory = decode_long_double (x, &e, &m);
- return scale10_round_decimal_decoded (e, m, memory, n);
+ if (memory != NULL)
+ return scale10_round_decimal_decoded (e, m, memory, n);
+ else
+ return NULL;
}
# endif
@@ -1397,10 +1417,13 @@ scale10_round_decimal_long_double (long double x, int n)
static char *
scale10_round_decimal_double (double x, int n)
{
- int e IF_LINT(= 0);
+ int e;
mpn_t m;
void *memory = decode_double (x, &e, &m);
- return scale10_round_decimal_decoded (e, m, memory, n);
+ if (memory != NULL)
+ return scale10_round_decimal_decoded (e, m, memory, n);
+ else
+ return NULL;
}
# endif
@@ -1603,7 +1626,7 @@ is_borderline (const char *digits, size_t precision)
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
/* Use a different function name, to make it possible that the 'wchar_t'
parametrization and the 'char' parametrization get compiled in the same
@@ -1626,24 +1649,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
switch (conversion)
{
case 'd': case 'i': case 'u':
- 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 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 */
+ switch (type)
+ {
+ default:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_LONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (long int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_LONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (long long int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (int8_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint8_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (int16_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint16_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (int32_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint32_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (int64_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint64_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (int_fast8_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (int_fast16_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (int_fast32_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_INT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (int_fast64_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
+ * 0.30103 /* binary -> decimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ }
if (tmp_length < precision)
tmp_length = precision;
/* Multiply by 2, as an estimate for FLAG_GROUP. */
@@ -1652,25 +1807,156 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
tmp_length = xsum (tmp_length, 1);
break;
+ case 'b':
+ #if SUPPORT_GNU_PRINTF_DIRECTIVES \
+ || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
+ case 'B':
+ #endif
+ switch (type)
+ {
+ default:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ }
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a prefix from the alternate form. */
+ tmp_length = xsum (tmp_length, 2);
+ break;
+
case 'o':
- 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 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 */
+ switch (type)
+ {
+ default:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint8_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint16_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint32_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint64_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
+ * 0.333334 /* binary -> octal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ }
if (tmp_length < precision)
tmp_length = precision;
/* Add 1, to account for a leading sign. */
@@ -1678,27 +1964,89 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
break;
case 'x': case 'X':
- 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 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 */
+ switch (type)
+ {
+ default:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint8_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint16_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint32_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint64_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT
+ * 0.25 /* binary -> hexadecimal */
+ )
+ + 1; /* turn floor into ceil */
+ break;
+ }
if (tmp_length < precision)
tmp_length = precision;
- /* Add 2, to account for a leading sign or alternate form. */
+ /* Add 2, to account for a prefix from the alternate form. */
tmp_length = xsum (tmp_length, 2);
break;
@@ -1987,6 +2335,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if (dp->conversion == 'n')
{
+#if NEED_PRINTF_WITH_N_DIRECTIVE
switch (a.arg[dp->arg_index].type)
{
case TYPE_COUNT_SCHAR_POINTER:
@@ -2004,9 +2353,36 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
case TYPE_COUNT_LONGLONGINT_POINTER:
*a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
break;
+ case TYPE_COUNT_INT8_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int8_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT16_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int16_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT32_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int32_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT64_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int64_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT_FAST8_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_fast8_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT_FAST16_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_fast16_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT_FAST32_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_fast32_t_pointer = length;
+ break;
+ case TYPE_COUNT_INT_FAST64_T_POINTER:
+ *a.arg[dp->arg_index].a.a_count_int_fast64_t_pointer = length;
+ break;
default:
abort ();
}
+#else
+ abort ();
+#endif
}
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
@@ -2129,7 +2505,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
characters = 0;
}
- if (characters < width && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2174,7 +2550,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
# endif
- if (characters < width && (dp->flags & FLAG_LEFT))
+ if (characters < width && (flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2231,7 +2607,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
characters = 0;
}
- if (characters < width && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2276,7 +2652,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
# endif
- if (characters < width && (dp->flags & FLAG_LEFT))
+ if (characters < width && (flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2333,7 +2709,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
characters = 0;
}
- if (characters < width && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2378,7 +2754,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
# endif
- if (characters < width && (dp->flags & FLAG_LEFT))
+ if (characters < width && (flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2393,7 +2769,150 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
#endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T
+#if WIDE_CHAR_VERSION && (!DCHAR_IS_TCHAR || NEED_WPRINTF_DIRECTIVE_LC)
+ else if ((dp->conversion == 's'
+ && a.arg[dp->arg_index].type == TYPE_WIDE_STRING)
+ || (dp->conversion == 'c'
+ && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR))
+ {
+ /* %ls or %lc in vasnwprintf. See the specification of
+ fwprintf. */
+ /* It would be silly to use snprintf ("%ls", ...) and then
+ convert back the result from a char[] to a wchar_t[].
+ Instead, just copy the argument wchar_t[] to the result. */
+ int flags = dp->flags;
+ size_t width;
+
+ 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;
+ width = arg;
+ if (arg < 0)
+ {
+ /* "A negative field width is taken as a '-' flag
+ followed by a positive field width." */
+ flags |= FLAG_LEFT;
+ width = -width;
+ }
+ }
+ else
+ {
+ const FCHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ {
+ const wchar_t *ls_arg;
+ wchar_t lc_arg[1];
+ size_t characters;
+
+ if (dp->conversion == 's')
+ {
+ int has_precision;
+ size_t 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;
+ }
+ }
+
+ ls_arg = a.arg[dp->arg_index].a.a_wide_string;
+
+ if (has_precision)
+ {
+ /* Use only at most PRECISION wide characters, from
+ the left. */
+ const wchar_t *ls_arg_end;
+
+ ls_arg_end = ls_arg;
+ characters = 0;
+ for (; precision > 0; precision--)
+ {
+ if (*ls_arg_end == 0)
+ /* Found the terminating null wide character. */
+ break;
+ ls_arg_end++;
+ characters++;
+ }
+ }
+ else
+ {
+ /* Use the entire string, and count the number of wide
+ characters. */
+ characters = local_wcslen (ls_arg);
+ }
+ }
+ else /* dp->conversion == 'c' */
+ {
+ lc_arg[0] = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
+ ls_arg = lc_arg;
+ characters = 1;
+ }
+
+ {
+ size_t total = (characters < width ? width : characters);
+ ENSURE_ALLOCATION (xsum (length, total));
+
+ if (characters < width && !(flags & FLAG_LEFT))
+ {
+ size_t n = width - characters;
+ DCHAR_SET (result + length, ' ', n);
+ length += n;
+ }
+
+ if (characters > 0)
+ {
+ DCHAR_CPY (result + length, ls_arg, characters);
+ length += characters;
+ }
+
+ if (characters < width && (flags & FLAG_LEFT))
+ {
+ size_t n = width - characters;
+ DCHAR_SET (result + length, ' ', n);
+ length += n;
+ }
+ }
+ }
+ }
+#endif
+#if (!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T
else if (dp->conversion == 's'
# if WIDE_CHAR_VERSION
&& a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2492,7 +3011,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
wide characters, from the left. */
# if HAVE_MBRTOWC
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
arg_end = arg;
characters = 0;
@@ -2520,7 +3039,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
characters. */
# if HAVE_MBRTOWC
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
arg_end = arg;
characters = 0;
@@ -2550,7 +3069,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
characters = 0;
}
- if (characters < width && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2564,7 +3083,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
size_t remaining;
# if HAVE_MBRTOWC
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
ENSURE_ALLOCATION (xsum (length, characters));
for (remaining = characters; remaining > 0; remaining--)
@@ -2590,7 +3109,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
# if HAVE_MBRTOWC
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
while (arg < arg_end)
{
@@ -2601,17 +3120,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# else
count = mbtowc (&wc, arg, arg_end - arg);
# endif
- if (count <= 0)
- /* mbrtowc not consistent with mbrlen, or mbtowc
- not consistent with mblen. */
+ if (count == 0)
+ /* mbrtowc not consistent with strlen. */
abort ();
+ if (count < 0)
+ /* Invalid or incomplete multibyte character. */
+ goto fail_with_EILSEQ;
ENSURE_ALLOCATION (xsum (length, 1));
result[length++] = wc;
arg += count;
}
}
- if (characters < width && (dp->flags & FLAG_LEFT))
+ if (characters < width && (flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2640,7 +3161,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
at most PRECISION bytes, from the left. */
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
arg_end = arg;
characters = 0;
@@ -2673,7 +3194,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
bytes. */
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
arg_end = arg;
characters = 0;
@@ -2713,7 +3234,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
size_t remaining;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
for (remaining = characters; remaining > 0; )
{
@@ -2767,7 +3288,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* w doesn't matter. */
w = 0;
- if (w < width && !(dp->flags & FLAG_LEFT))
+ if (w < width && !(flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2782,7 +3303,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
size_t remaining;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
ENSURE_ALLOCATION (xsum (length, characters));
for (remaining = characters; remaining > 0; )
@@ -2808,7 +3329,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
while (arg < arg_end)
{
@@ -2835,7 +3356,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
length += tmpdst_len;
# endif
- if (w < width && (dp->flags & FLAG_LEFT))
+ if (w < width && (flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2846,12 +3367,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
}
#endif
-#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION
+#if (NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION
else if (dp->conversion == 'c'
&& a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)
{
/* Implement the 'lc' directive ourselves, in order to provide
- the fallback that avoids EILSEQ. */
+ a correct behaviour for the null wint_t argument and/or the
+ fallback that avoids EILSEQ. */
int flags = dp->flags;
int has_width;
size_t width;
@@ -2906,21 +3428,18 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* Count the number of bytes. */
characters = 0;
- if (arg != 0)
- {
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
- mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbstate_t state;
+ mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
- if (count < 0)
- /* Inconsistency. */
- abort ();
- characters = count;
- }
+ count = local_wcrtomb (cbuf, arg, &state);
+ if (count < 0)
+ /* Cannot convert. */
+ goto fail_with_EILSEQ;
+ characters = count;
}
# if DCHAR_IS_TCHAR
else
@@ -2932,13 +3451,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# if !DCHAR_IS_TCHAR
/* Convert the string into a piece of temporary memory. */
- if (characters > 0) /* implies arg != 0 */
+ if (characters > 0)
{
char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
count = local_wcrtomb (cbuf, arg, &state);
@@ -2976,7 +3495,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* w doesn't matter. */
w = 0;
- if (w < width && !(dp->flags & FLAG_LEFT))
+ if (w < width && !(flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
@@ -2989,12 +3508,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
/* We know the number of bytes in advance. */
ENSURE_ALLOCATION (xsum (length, characters));
- if (characters > 0) /* implies arg != 0 */
+ if (characters > 0)
{
int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbszero (&state);
# endif
count = local_wcrtomb (result + length, arg, &state);
@@ -3006,23 +3525,20 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
else
{
- if (arg != 0)
- {
- char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
- int count;
+ char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
+ int count;
# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
- mbstate_t state;
- memset (&state, '\0', sizeof (mbstate_t));
+ mbstate_t state;
+ mbszero (&state);
# endif
- count = local_wcrtomb (cbuf, arg, &state);
- if (count <= 0)
- /* Inconsistency. */
- abort ();
- ENSURE_ALLOCATION (xsum (length, count));
- memcpy (result + length, cbuf, count);
- length += count;
- }
+ count = local_wcrtomb (cbuf, arg, &state);
+ if (count < 0)
+ /* Cannot convert. */
+ goto fail_with_EILSEQ;
+ ENSURE_ALLOCATION (xsum (length, count));
+ memcpy (result + length, cbuf, count);
+ length += count;
}
# else
ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
@@ -3032,7 +3548,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
length += tmpdst_len;
# endif
- if (w < width && (dp->flags & FLAG_LEFT))
+ if (w < width && (flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
@@ -3042,14 +3558,399 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
#endif
-#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
+#if NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION
+ else if (dp->conversion == 'c'
+ && a.arg[dp->arg_index].type != TYPE_WIDE_CHAR)
+ {
+ /* Implement the 'c' directive ourselves, in order to avoid
+ EILSEQ in the "C" locale. */
+ int flags = dp->flags;
+ size_t width;
+
+ 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;
+ width = arg;
+ if (arg < 0)
+ {
+ /* "A negative field width is taken as a '-' flag
+ followed by a positive field width." */
+ flags |= FLAG_LEFT;
+ width = -width;
+ }
+ }
+ else
+ {
+ const FCHAR_T *digitp = dp->width_start;
+
+ do
+ width = xsum (xtimes (width, 10), *digitp++ - '0');
+ while (digitp != dp->width_end);
+ }
+ }
+
+ /* %c in vasnwprintf. See the specification of fwprintf. */
+ {
+ char arg = (char) a.arg[dp->arg_index].a.a_char;
+ mbstate_t state;
+ wchar_t wc;
+
+ mbszero (&state);
+ int count = mbrtowc (&wc, &arg, 1, &state);
+ if (count < 0)
+ /* Invalid or incomplete multibyte character. */
+ goto fail_with_EILSEQ;
+
+ if (1 < width && !(flags & FLAG_LEFT))
+ {
+ size_t n = width - 1;
+ ENSURE_ALLOCATION (xsum (length, n));
+ DCHAR_SET (result + length, ' ', n);
+ length += n;
+ }
+
+ ENSURE_ALLOCATION (xsum (length, 1));
+ result[length++] = wc;
+
+ if (1 < width && (flags & FLAG_LEFT))
+ {
+ size_t n = width - 1;
+ ENSURE_ALLOCATION (xsum (length, n));
+ DCHAR_SET (result + length, ' ', n);
+ length += n;
+ }
+ }
+ }
+#endif
+#if NEED_PRINTF_DIRECTIVE_B || NEED_PRINTF_DIRECTIVE_UPPERCASE_B
+ else if (0
+# if NEED_PRINTF_DIRECTIVE_B
+ || (dp->conversion == 'b')
+# endif
+# if NEED_PRINTF_DIRECTIVE_UPPERCASE_B
+ || (dp->conversion == 'B')
+# 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;
+ size_t count;
+ DCHAR_T tmpbuf[700];
+ DCHAR_T *tmp;
+ DCHAR_T *tmp_end;
+ DCHAR_T *tmp_start;
+ 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;
+ width = arg;
+ if (arg < 0)
+ {
+ /* "A negative field width is taken as a '-' flag
+ followed by a positive field width." */
+ flags |= FLAG_LEFT;
+ width = -width;
+ }
+ }
+ 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 = 1;
+ 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. */
+ switch (type)
+ {
+ default:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_ULONGLONGINT:
+ tmp_length =
+ (unsigned int) (sizeof (unsigned long long int) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint8_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint16_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint32_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint64_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST8_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast8_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST16_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast16_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST32_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast32_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ case TYPE_UINT_FAST64_T:
+ tmp_length =
+ (unsigned int) (sizeof (uint_fast64_t) * CHAR_BIT)
+ + 1; /* turn floor into ceil */
+ break;
+ }
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a prefix from the alternate form. */
+ tmp_length = xsum (tmp_length, 2);
+
+ if (tmp_length < width)
+ tmp_length = width;
+
+ 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;
+ }
+
+ tmp_end = tmp + tmp_length;
+
+ unsigned long long arg;
+ switch (type)
+ {
+ case TYPE_UCHAR:
+ arg = a.arg[dp->arg_index].a.a_uchar;
+ break;
+ case TYPE_USHORT:
+ arg = a.arg[dp->arg_index].a.a_ushort;
+ break;
+ case TYPE_UINT:
+ arg = a.arg[dp->arg_index].a.a_uint;
+ break;
+ case TYPE_ULONGINT:
+ arg = a.arg[dp->arg_index].a.a_ulongint;
+ break;
+ case TYPE_ULONGLONGINT:
+ arg = a.arg[dp->arg_index].a.a_ulonglongint;
+ break;
+ case TYPE_UINT8_T:
+ arg = a.arg[dp->arg_index].a.a_uint8_t;
+ break;
+ case TYPE_UINT16_T:
+ arg = a.arg[dp->arg_index].a.a_uint16_t;
+ break;
+ case TYPE_UINT32_T:
+ arg = a.arg[dp->arg_index].a.a_uint32_t;
+ break;
+ case TYPE_UINT64_T:
+ arg = a.arg[dp->arg_index].a.a_uint64_t;
+ break;
+ case TYPE_UINT_FAST8_T:
+ arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
+ break;
+ case TYPE_UINT_FAST16_T:
+ arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
+ break;
+ case TYPE_UINT_FAST32_T:
+ arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
+ break;
+ case TYPE_UINT_FAST64_T:
+ arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
+ break;
+ default:
+ abort ();
+ }
+ int need_prefix = ((flags & FLAG_ALT) && arg != 0);
+
+ p = tmp_end;
+ /* "The result of converting a zero value with a precision
+ of zero is no characters." */
+ if (!(has_precision && precision == 0 && arg == 0))
+ {
+ do
+ {
+ *--p = '0' + (arg & 1);
+ arg = arg >> 1;
+ }
+ while (arg != 0);
+ }
+
+ if (has_precision)
+ {
+ DCHAR_T *digits_start = tmp_end - precision;
+ while (p > digits_start)
+ *--p = '0';
+ }
+
+ pad_ptr = p;
+
+ if (need_prefix)
+ {
+# if NEED_PRINTF_DIRECTIVE_B && !NEED_PRINTF_DIRECTIVE_UPPERCASE_B
+ *--p = 'b';
+# elif NEED_PRINTF_DIRECTIVE_UPPERCASE_B && !NEED_PRINTF_DIRECTIVE_B
+ *--p = 'B';
+# else
+ *--p = dp->conversion;
+# endif
+ *--p = '0';
+ }
+ tmp_start = p;
+
+ /* The generated string now extends from tmp_start to tmp_end,
+ with the zero padding insertion point being at pad_ptr,
+ tmp_start <= pad_ptr <= tmp_end. */
+ count = tmp_end - tmp_start;
+
+ if (count < width)
+ {
+ size_t pad = width - count;
+
+ if (flags & FLAG_LEFT)
+ {
+ /* Pad with spaces on the right. */
+ for (p = tmp_start; p < tmp_end; p++)
+ *(p - pad) = *p;
+ for (p = tmp_end - pad; p < tmp_end; p++)
+ *p = ' ';
+ }
+ else if ((flags & FLAG_ZERO)
+ /* Neither ISO C nor POSIX specify that the '0'
+ flag is ignored when a width and a precision
+ are both present. But most implementations
+ do so. */
+ && !(has_width && has_precision))
+ {
+ /* Pad with zeroes. */
+ for (p = tmp_start; p < pad_ptr; p++)
+ *(p - pad) = *p;
+ for (p = pad_ptr - pad; p < pad_ptr; p++)
+ *p = '0';
+ }
+ else
+ {
+ /* Pad with spaces on the left. */
+ for (p = tmp_start - pad; p < tmp_start; p++)
+ *p = ' ';
+ }
+
+ tmp_start = tmp_start - pad;
+ }
+
+ count = tmp_end - tmp_start;
+
+ 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_start, count * sizeof (DCHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+ length += count;
+ }
+#endif
+#if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
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
+# if NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
|| a.arg[dp->arg_index].type == TYPE_LONGDOUBLE
# endif
)
@@ -3169,7 +4070,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
p = tmp;
if (type == TYPE_LONGDOUBLE)
{
-# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE
+# if NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || (NEED_WPRINTF_DIRECTIVE_LA && WIDE_CHAR_VERSION)
long double arg = a.arg[dp->arg_index].a.a_longdouble;
if (isnanl (arg))
@@ -3289,7 +4190,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
*p++ = dp->conversion - 'A' + 'P';
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
@@ -3440,7 +4341,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
*p++ = dp->conversion - 'A' + 'P';
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
{ '%', '+', 'd', '\0' };
@@ -3532,7 +4433,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
length += count;
}
#endif
-#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
+#if NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE
else if ((dp->conversion == 'f' || dp->conversion == 'F'
|| dp->conversion == 'e' || dp->conversion == 'E'
|| dp->conversion == 'g' || dp->conversion == 'G'
@@ -3900,7 +4801,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
*p++ = dp->conversion; /* 'e' or 'E' */
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
@@ -4081,7 +4982,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
{ '%', '+', '.', '2', 'd', '\0' };
@@ -4358,7 +5259,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
*p++ = dp->conversion; /* 'e' or 'E' */
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
/* Produce the same number of exponent digits
@@ -4551,7 +5452,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
}
*p++ = dp->conversion - 'G' + 'E'; /* 'e' or 'E' */
-# if WIDE_CHAR_VERSION
+# if WIDE_CHAR_VERSION && DCHAR_IS_TCHAR
{
static const wchar_t decimal_format[] =
/* Produce the same number of exponent digits
@@ -4719,24 +5620,24 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_width;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
size_t width;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_precision;
size_t precision;
#endif
-#if NEED_PRINTF_UNBOUNDED_PRECISION
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int prec_ourselves;
#else
# define prec_ourselves 0
#endif
-#if NEED_PRINTF_FLAG_LEFTADJUST
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST
# define pad_ourselves 1
-#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#elif !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int pad_ourselves;
#else
# define pad_ourselves 0
@@ -4751,10 +5652,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
TCHAR_T *tmp;
#endif
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 0;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
width = 0;
if (dp->width_start != dp->width_end)
{
@@ -4782,13 +5683,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
-#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+# if (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 1;
-#endif
+# endif
}
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_precision = 0;
precision = 6;
if (dp->precision_start != dp->precision_end)
@@ -4821,14 +5722,32 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#endif
/* Decide whether to handle the precision ourselves. */
-#if NEED_PRINTF_UNBOUNDED_PRECISION
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
switch (dp->conversion)
{
+# if NEED_PRINTF_UNBOUNDED_PRECISION
case 'd': case 'i': case 'u':
+ case 'b':
+ #if SUPPORT_GNU_PRINTF_DIRECTIVES \
+ || (__GLIBC__ + (__GLIBC_MINOR__ >= 35) > 2)
+ case 'B':
+ #endif
case 'o':
- case 'x': case 'X': case 'p':
prec_ourselves = has_precision && (precision > 0);
break;
+# endif
+ case 'x': case 'X': case 'p':
+ prec_ourselves =
+ has_precision
+ && (0
+# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
+ || (precision == 0)
+# endif
+# if NEED_PRINTF_UNBOUNDED_PRECISION
+ || (precision > 0)
+# endif
+ );
+ break;
default:
prec_ourselves = 0;
break;
@@ -4836,7 +5755,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#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)
+#if !((WIDE_CHAR_VERSION && MUSL_LIBC) || NEED_PRINTF_FLAG_LEFTADJUST) && (!DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION)
switch (dp->conversion)
{
# if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO
@@ -4955,6 +5874,54 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
{
case TYPE_LONGLONGINT:
case TYPE_ULONGLONGINT:
+ #if INT8_WIDTH > LONG_WIDTH
+ case TYPE_INT8_T:
+ #endif
+ #if UINT8_WIDTH > LONG_WIDTH
+ case TYPE_UINT8_T:
+ #endif
+ #if INT16_WIDTH > LONG_WIDTH
+ case TYPE_INT16_T:
+ #endif
+ #if UINT16_WIDTH > LONG_WIDTH
+ case TYPE_UINT16_T:
+ #endif
+ #if INT32_WIDTH > LONG_WIDTH
+ case TYPE_INT32_T:
+ #endif
+ #if UINT32_WIDTH > LONG_WIDTH
+ case TYPE_UINT32_T:
+ #endif
+ #if INT64_WIDTH > LONG_WIDTH
+ case TYPE_INT64_T:
+ #endif
+ #if UINT64_WIDTH > LONG_WIDTH
+ case TYPE_UINT64_T:
+ #endif
+ #if INT_FAST8_WIDTH > LONG_WIDTH
+ case TYPE_INT_FAST8_T:
+ #endif
+ #if UINT_FAST8_WIDTH > LONG_WIDTH
+ case TYPE_UINT_FAST8_T:
+ #endif
+ #if INT_FAST16_WIDTH > LONG_WIDTH
+ case TYPE_INT_FAST16_T:
+ #endif
+ #if UINT_FAST16_WIDTH > LONG_WIDTH
+ case TYPE_UINT_FAST16_T:
+ #endif
+ #if INT_FAST32_WIDTH > LONG_WIDTH
+ case TYPE_INT3_FAST2_T:
+ #endif
+ #if UINT_FAST32_WIDTH > LONG_WIDTH
+ case TYPE_UINT_FAST32_T:
+ #endif
+ #if INT_FAST64_WIDTH > LONG_WIDTH
+ case TYPE_INT_FAST64_T:
+ #endif
+ #if UINT_FAST64_WIDTH > LONG_WIDTH
+ case TYPE_UINT_FAST64_T:
+ #endif
#if defined _WIN32 && ! defined __CYGWIN__
*fbp++ = 'I';
*fbp++ = '6';
@@ -4966,12 +5933,60 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
FALLTHROUGH;
case TYPE_LONGINT:
case TYPE_ULONGINT:
-#if HAVE_WINT_T
+ #if INT8_WIDTH > INT_WIDTH && INT8_WIDTH <= LONG_WIDTH
+ case TYPE_INT8_T:
+ #endif
+ #if UINT8_WIDTH > INT_WIDTH && UINT8_WIDTH <= LONG_WIDTH
+ case TYPE_UINT8_T:
+ #endif
+ #if INT16_WIDTH > INT_WIDTH && INT16_WIDTH <= LONG_WIDTH
+ case TYPE_INT16_T:
+ #endif
+ #if UINT16_WIDTH > INT_WIDTH && UINT16_WIDTH <= LONG_WIDTH
+ case TYPE_UINT16_T:
+ #endif
+ #if INT32_WIDTH > INT_WIDTH && INT32_WIDTH <= LONG_WIDTH
+ case TYPE_INT32_T:
+ #endif
+ #if UINT32_WIDTH > INT_WIDTH && UINT32_WIDTH <= LONG_WIDTH
+ case TYPE_UINT32_T:
+ #endif
+ #if INT64_WIDTH > INT_WIDTH && INT64_WIDTH <= LONG_WIDTH
+ case TYPE_INT64_T:
+ #endif
+ #if UINT64_WIDTH > INT_WIDTH && UINT64_WIDTH <= LONG_WIDTH
+ case TYPE_UINT64_T:
+ #endif
+ #if INT_FAST8_WIDTH > INT_WIDTH && INT_FAST8_WIDTH <= LONG_WIDTH
+ case TYPE_INT_FAST8_T:
+ #endif
+ #if UINT_FAST8_WIDTH > INT_WIDTH && UINT_FAST8_WIDTH <= LONG_WIDTH
+ case TYPE_UINT_FAST8_T:
+ #endif
+ #if INT_FAST16_WIDTH > INT_WIDTH && INT_FAST16_WIDTH <= LONG_WIDTH
+ case TYPE_INT_FAST16_T:
+ #endif
+ #if UINT_FAST16_WIDTH > INT_WIDTH && UINT_FAST16_WIDTH <= LONG_WIDTH
+ case TYPE_UINT_FAST16_T:
+ #endif
+ #if INT_FAST32_WIDTH > INT_WIDTH && INT_FAST32_WIDTH <= LONG_WIDTH
+ case TYPE_INT_FAST32_T:
+ #endif
+ #if UINT_FAST32_WIDTH > INT_WIDTH && UINT_FAST32_WIDTH <= LONG_WIDTH
+ case TYPE_UINT_FAST32_T:
+ #endif
+ #if INT_FAST64_WIDTH > INT_WIDTH && INT_FAST64_WIDTH <= LONG_WIDTH
+ case TYPE_INT_FAST64_T:
+ #endif
+ #if UINT_FAST64_WIDTH > INT_WIDTH && UINT_FAST64_WIDTH <= LONG_WIDTH
+ case TYPE_UINT_FAST64_T:
+ #endif
+ #if HAVE_WINT_T
case TYPE_WIDE_CHAR:
-#endif
-#if HAVE_WCHAR_T
+ #endif
+ #if HAVE_WCHAR_T
case TYPE_WIDE_STRING:
-#endif
+ #endif
*fbp++ = 'l';
break;
case TYPE_LONGDOUBLE:
@@ -4987,47 +6002,74 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#endif
*fbp = dp->conversion;
#if USE_SNPRINTF
-# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \
+ /* Decide whether to pass %n in the format string
+ to SNPRINTF. */
+# if (((!WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR) \
+ && (HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99)) \
|| ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
&& !defined __UCLIBC__) \
|| (defined __APPLE__ && defined __MACH__) \
+ || defined __OpenBSD__ \
|| defined __ANDROID__ \
- || (defined _WIN32 && ! defined __CYGWIN__))
- /* On systems where we know that snprintf's return value
- conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that
- snprintf always produces NUL-terminated strings
- (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid
- using %n. And it is desirable to do so, because more and
- more platforms no longer support %n, for "security reasons".
- In particular, the following platforms:
+ || (defined _WIN32 && ! defined __CYGWIN__)) \
+ || (WIDE_CHAR_VERSION && MUSL_LIBC)
+ /* We can avoid passing %n and instead rely on SNPRINTF's
+ return value if
+ - !WIDE_CHAR_VERSION || !DCHAR_IS_TCHAR, because otherwise,
+ when WIDE_CHAR_VERSION && DCHAR_IS_TCHAR,
+ snwprintf()/_snwprintf() (Windows) and swprintf() (Unix)
+ don't return the needed buffer size,
+ and
+ - we're compiling for a system where we know
+ - that snprintf's return value conforms to ISO C 99
+ (HAVE_SNPRINTF_RETVAL_C99) and
+ - that snprintf always produces NUL-terminated strings
+ (HAVE_SNPRINTF_TRUNCATION_C99).
+ And it is desirable to do so, because more and more platforms
+ no longer support %n, for "security reasons". */
+ /* On specific platforms, listed below, we *must* avoid %n.
+ In the case
+ !WIDE_CHAR_VERSION && HAVE_SNPRINTF_RETVAL_C99 && !USE_MSVC__SNPRINTF
+ we can rely on the return value of snprintf instead. Whereas
+ in the opposite case
+ WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+ we need to make room based on an estimation, computed by
+ MAX_ROOM_NEEDED. */
+ /* The following platforms forbid %n:
- 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).
- - On Mac OS X 10.13 or newer, the use of %n in format
+ - On macOS 10.13 or newer, the use of %n in format
strings in writable memory by default crashes the
program.
+ - On OpenBSD, since 2021-08-30, the use of %n in format
+ strings produces an abort (see
+ <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfprintf.c.diff?r1=1.79&r2=1.80&f=h>,
+ <https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdio/vfwprintf.c.diff?r1=1.20&r2=1.21&f=h>).
- On Android, starting on 2018-03-07, the use of %n in
format strings produces a fatal error (see
<https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
- On these platforms, HAVE_SNPRINTF_RETVAL_C99 and
- HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them
- explicitly in the condition above, in case of cross-
- compilation (just to be sure). */
- /* On native Windows systems (such as mingw), we can avoid using
- %n because:
+ - 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
+ <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+ <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
+ On the first four of these platforms, if !WIDE_CHAR_VERSION,
+ it is not a big deal to avoid %n, because on these platforms,
+ HAVE_SNPRINTF_RETVAL_C99 and HAVE_SNPRINTF_TRUNCATION_C99 are
+ 1.
+ On native Windows, if !WIDE_CHAR_VERSION, it's not a big deal
+ either 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
- <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
- <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
- So we should avoid %n in this situation. */
+ buffer size: it returns -1 in this case. */
+ /* Additionally, in the WIDE_CHAR_VERSION case, we cannot use %n
+ on musl libc because we would run into an swprintf() bug.
+ See <https://www.openwall.com/lists/musl/2023/03/19/1>. */
fbp[1] = '\0';
# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
fbp[1] = '%';
@@ -5188,6 +6230,102 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
SNPRINTF_BUF (arg);
}
break;
+ case TYPE_INT8_T:
+ {
+ int8_t arg = a.arg[dp->arg_index].a.a_int8_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT8_T:
+ {
+ uint8_t arg = a.arg[dp->arg_index].a.a_uint8_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT16_T:
+ {
+ int16_t arg = a.arg[dp->arg_index].a.a_int16_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT16_T:
+ {
+ uint16_t arg = a.arg[dp->arg_index].a.a_uint16_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT32_T:
+ {
+ int32_t arg = a.arg[dp->arg_index].a.a_int32_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT32_T:
+ {
+ uint32_t arg = a.arg[dp->arg_index].a.a_uint32_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT64_T:
+ {
+ int64_t arg = a.arg[dp->arg_index].a.a_int64_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT64_T:
+ {
+ uint64_t arg = a.arg[dp->arg_index].a.a_uint64_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT_FAST8_T:
+ {
+ int_fast8_t arg = a.arg[dp->arg_index].a.a_int_fast8_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT_FAST8_T:
+ {
+ uint_fast8_t arg = a.arg[dp->arg_index].a.a_uint_fast8_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT_FAST16_T:
+ {
+ int_fast16_t arg = a.arg[dp->arg_index].a.a_int_fast16_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT_FAST16_T:
+ {
+ uint_fast16_t arg = a.arg[dp->arg_index].a.a_uint_fast16_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT_FAST32_T:
+ {
+ int_fast32_t arg = a.arg[dp->arg_index].a.a_int_fast32_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT_FAST32_T:
+ {
+ uint_fast32_t arg = a.arg[dp->arg_index].a.a_uint_fast32_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_INT_FAST64_T:
+ {
+ int_fast64_t arg = a.arg[dp->arg_index].a.a_int_fast64_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
+ case TYPE_UINT_FAST64_T:
+ {
+ uint_fast64_t arg = a.arg[dp->arg_index].a.a_uint_fast64_t;
+ SNPRINTF_BUF (arg);
+ }
+ break;
case TYPE_DOUBLE:
{
double arg = a.arg[dp->arg_index].a.a_double;
@@ -5270,12 +6408,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* Look at the snprintf() return value. */
if (retcount < 0)
{
-# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
+# if (WIDE_CHAR_VERSION && DCHAR_IS_TCHAR) || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
/* 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.
+ Likewise, in case of
+ WIDE_CHAR_VERSION && DCHAR_IS_TCHAR, the
+ functions snwprintf()/_snwprintf() (Windows)
+ or swprintf() (Unix).
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
@@ -5311,7 +6453,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# endif
}
else
- count = retcount;
+ {
+ count = retcount;
+# if WIDE_CHAR_VERSION && defined __MINGW32__
+ if (count == 0 && dp->conversion == 'c')
+ /* snwprintf returned 0 instead of 1. But it
+ wrote a null wide character. */
+ count = 1;
+# endif
+ }
}
}
#endif
@@ -5369,7 +6519,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
}
#endif
-#if NEED_PRINTF_UNBOUNDED_PRECISION
+#if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
if (prec_ourselves)
{
/* Handle the precision. */
@@ -5429,6 +6579,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
count += insert;
}
+# if NEED_PRINTF_FLAG_ALT_PRECISION_ZERO
+ else if (precision == 0
+ && move == 1
+ && prec_ptr[prefix_count] == '0')
+ {
+ /* Replace the "0" result with an empty string. */
+ count = prefix_count;
+ }
+# endif
}
#endif
@@ -5441,11 +6600,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
#if !DCHAR_IS_TCHAR
/* Convert from TCHAR_T[] to DCHAR_T[]. */
- if (dp->conversion == 'c' || dp->conversion == 's')
+ if (dp->conversion == 'c' || dp->conversion == 's'
+# if __GLIBC__ >= 2 && !defined __UCLIBC__
+ || (flags & FLAG_LOCALIZED)
+# endif
+ )
{
- /* type = TYPE_CHAR or TYPE_WIDE_CHAR or TYPE_STRING
- TYPE_WIDE_STRING.
- The result string is not certainly ASCII. */
+ /* The result string is not guaranteed to be ASCII. */
const TCHAR_T *tmpsrc;
DCHAR_T *tmpdst;
size_t tmpdst_len;
@@ -5456,6 +6617,56 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
# else
tmpsrc = tmp;
# endif
+# if WIDE_CHAR_VERSION
+ /* Convert tmpsrc[0..count-1] to a freshly allocated
+ wide character array. */
+ mbstate_t state;
+
+ mbszero (&state);
+ tmpdst_len = 0;
+ {
+ const TCHAR_T *src = tmpsrc;
+ size_t srclen = count;
+
+ for (; srclen > 0; tmpdst_len++)
+ {
+ /* Parse the next multibyte character. */
+ size_t ret = mbrtowc (NULL, src, srclen, &state);
+ if (ret == (size_t)(-2) || ret == (size_t)(-1))
+ goto fail_with_EILSEQ;
+ if (ret == 0)
+ ret = 1;
+ src += ret;
+ srclen -= ret;
+ }
+ }
+
+ tmpdst =
+ (wchar_t *) malloc ((tmpdst_len + 1) * sizeof (wchar_t));
+ if (tmpdst == NULL)
+ goto out_of_memory;
+
+ mbszero (&state);
+ {
+ DCHAR_T *destptr = tmpdst;
+ const TCHAR_T *src = tmpsrc;
+ size_t srclen = count;
+
+ for (; srclen > 0; destptr++)
+ {
+ /* Parse the next multibyte character. */
+ size_t ret = mbrtowc (destptr, src, srclen, &state);
+ if (ret == (size_t)(-2) || ret == (size_t)(-1))
+ /* Should already have been caught in the first
+ loop, above. */
+ abort ();
+ if (ret == 0)
+ ret = 1;
+ src += ret;
+ srclen -= ret;
+ }
+ }
+# else
tmpdst =
DCHAR_CONV_FROM_ENCODING (locale_charset (),
iconveh_question_mark,
@@ -5464,6 +6675,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
NULL, &tmpdst_len);
if (tmpdst == NULL)
goto fail_with_errno;
+# endif
ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
{ free (tmpdst); goto out_of_memory; });
DCHAR_CPY (result + length, tmpdst, tmpdst_len);
@@ -5530,7 +6742,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
/* 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 (WIDE_CHAR_VERSION && MUSL_LIBC) || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_FLAG_ALT_PRECISION_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
if (pad_ourselves && has_width)
{
size_t w;
@@ -5589,6 +6801,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
if ((*pad_ptr >= 'A' && *pad_ptr <= 'Z')
|| (*pad_ptr >= 'a' && *pad_ptr <= 'z'))
pad_ptr = NULL;
+ else
+ /* Do the zero-padding after the "0x" or
+ "0b" prefix, not before. */
+ if (p - rp >= 2
+ && *rp == '0'
+ && (((dp->conversion == 'a'
+ || dp->conversion == 'x')
+ && rp[1] == 'x')
+ || ((dp->conversion == 'A'
+ || dp->conversion == 'X')
+ && rp[1] == 'X')
+ || (dp->conversion == 'b'
+ && rp[1] == 'b')
+ || (dp->conversion == 'B'
+ && rp[1] == 'B')))
+ pad_ptr += 2;
}
/* The generated string now extends from rp to p,
with the zero padding insertion point being at
@@ -5602,7 +6830,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
for (; pad > 0; pad--)
*p++ = ' ';
}
- else if ((flags & FLAG_ZERO) && pad_ptr != NULL)
+ else if ((flags & FLAG_ZERO) && pad_ptr != NULL
+ /* ISO C says: "For d, i, o, u, x, and X
+ conversions, if a precision is
+ specified, the 0 flag is ignored. */
+ && !(has_precision
+ && (dp->conversion == 'd'
+ || dp->conversion == 'i'
+ || dp->conversion == 'o'
+ || dp->conversion == 'u'
+ || dp->conversion == 'x'
+ || dp->conversion == 'X'
+ /* Although ISO C does not
+ require it, treat 'b' and 'B'
+ like 'x' and 'X'. */
+ || dp->conversion == 'b'
+ || dp->conversion == 'B')))
{
/* Pad with zeroes. */
DCHAR_T *q = end;
@@ -5696,7 +6939,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
errno = ENOMEM;
goto fail_with_errno;
-#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T)
+#if ENABLE_UNISTDIO || ((!USE_SNPRINTF || WIDE_CHAR_VERSION || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_DIRECTIVE_LS || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T) || ((NEED_PRINTF_DIRECTIVE_LC || ENABLE_WCHAR_FALLBACK) && HAVE_WINT_T && !WIDE_CHAR_VERSION) || (NEED_WPRINTF_DIRECTIVE_C && WIDE_CHAR_VERSION)
fail_with_EILSEQ:
errno = EILSEQ;
goto fail_with_errno;