summaryrefslogtreecommitdiffstats
path: root/gl/vasnprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/vasnprintf.c')
-rw-r--r--gl/vasnprintf.c922
1 files changed, 528 insertions, 394 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
index 5267b1b..285c674 100644
--- a/gl/vasnprintf.c
+++ b/gl/vasnprintf.c
@@ -1,18 +1,18 @@
1/* vsprintf with automatic memory allocation. 1/* vsprintf with automatic memory allocation.
2 Copyright (C) 1999, 2002-2013 Free Software Foundation, Inc. 2 Copyright (C) 1999, 2002-2022 Free Software Foundation, Inc.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This file is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU Lesser General Public License as
6 the Free Software Foundation; either version 3, or (at your option) 6 published by the Free Software Foundation; either version 2.1 of the
7 any later version. 7 License, or (at your option) any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 This file is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU Lesser General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License along 14 You should have received a copy of the GNU Lesser General Public License
15 with this program; if not, see <http://www.gnu.org/licenses/>. */ 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16 16
17/* This file can be parametrized with the following macros: 17/* This file can be parametrized with the following macros:
18 VASNPRINTF The name of the function being defined. 18 VASNPRINTF The name of the function being defined.
@@ -41,7 +41,14 @@
41 DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[]. 41 DCHAR_CONV_FROM_ENCODING A function to convert from char[] to DCHAR[].
42 DCHAR_IS_UINT8_T Set to 1 if DCHAR_T is uint8_t. 42 DCHAR_IS_UINT8_T Set to 1 if DCHAR_T is uint8_t.
43 DCHAR_IS_UINT16_T Set to 1 if DCHAR_T is uint16_t. 43 DCHAR_IS_UINT16_T Set to 1 if DCHAR_T is uint16_t.
44 DCHAR_IS_UINT32_T Set to 1 if DCHAR_T is uint32_t. */ 44 DCHAR_IS_UINT32_T Set to 1 if DCHAR_T is uint32_t.
45 ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions.
46 ENABLE_WCHAR_FALLBACK Set to 1 to avoid EILSEQ during conversion of wide
47 characters (wchar_t) and wide character strings
48 (wchar_t[]) to multibyte sequences. The fallback is the
49 hexadecimal escape syntax (\unnnn or \Unnnnnnnn) or,
50 if wchar_t is not Unicode encoded, \wnnnn or \Wnnnnnnnn.
51 */
45 52
46/* Tell glibc's <stdio.h> to provide a prototype for snprintf(). 53/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
47 This must come before <config.h> because <config.h> may include 54 This must come before <config.h> because <config.h> may include
@@ -53,10 +60,16 @@
53#ifndef VASNPRINTF 60#ifndef VASNPRINTF
54# include <config.h> 61# include <config.h>
55#endif 62#endif
56#ifndef IN_LIBINTL 63
57# include <alloca.h> 64/* As of GCC 11.2.1, gcc -Wanalyzer-too-complex reports that main's
65 use of CHECK macros expands to code that is too complicated for gcc
66 -fanalyzer. Suppress the resulting bogus warnings. */
67#if 10 <= __GNUC__
68# pragma GCC diagnostic ignored "-Wanalyzer-null-argument"
58#endif 69#endif
59 70
71#include <alloca.h>
72
60/* Specification. */ 73/* Specification. */
61#ifndef VASNPRINTF 74#ifndef VASNPRINTF
62# if WIDE_CHAR_VERSION 75# if WIDE_CHAR_VERSION
@@ -87,6 +100,7 @@
87/* Checked size_t computations. */ 100/* Checked size_t computations. */
88#include "xsize.h" 101#include "xsize.h"
89 102
103#include "attribute.h"
90#include "verify.h" 104#include "verify.h"
91 105
92#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 106#if (NEED_PRINTF_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
@@ -156,6 +170,7 @@
156# define SNPRINTF snwprintf 170# define SNPRINTF snwprintf
157# else 171# else
158# define SNPRINTF _snwprintf 172# define SNPRINTF _snwprintf
173# define USE_MSVC__SNPRINTF 1
159# endif 174# endif
160# else 175# else
161 /* Unix. */ 176 /* Unix. */
@@ -181,7 +196,9 @@
181 /* Here we need to call the native snprintf, not rpl_snprintf. */ 196 /* Here we need to call the native snprintf, not rpl_snprintf. */
182# undef snprintf 197# undef snprintf
183# else 198# else
199 /* MSVC versions < 14 did not have snprintf, only _snprintf. */
184# define SNPRINTF _snprintf 200# define SNPRINTF _snprintf
201# define USE_MSVC__SNPRINTF 1
185# endif 202# endif
186# else 203# else
187 /* Unix. */ 204 /* Unix. */
@@ -195,7 +212,7 @@
195 212
196/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized" 213/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
197 warnings in this file. Use -Dlint to suppress them. */ 214 warnings in this file. Use -Dlint to suppress them. */
198#ifdef lint 215#if defined GCC_LINT || defined lint
199# define IF_LINT(Code) Code 216# define IF_LINT(Code) Code
200#else 217#else
201# define IF_LINT(Code) /* empty */ 218# define IF_LINT(Code) /* empty */
@@ -208,7 +225,7 @@
208#undef remainder 225#undef remainder
209#define remainder rem 226#define remainder rem
210 227
211#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION 228#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION
212# if (HAVE_STRNLEN && !defined _AIX) 229# if (HAVE_STRNLEN && !defined _AIX)
213# define local_strnlen strnlen 230# define local_strnlen strnlen
214# else 231# else
@@ -224,7 +241,7 @@ local_strnlen (const char *string, size_t maxlen)
224# endif 241# endif
225#endif 242#endif
226 243
227#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 244#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
228# if HAVE_WCSLEN 245# if HAVE_WCSLEN
229# define local_wcslen wcslen 246# define local_wcslen wcslen
230# else 247# else
@@ -247,7 +264,7 @@ local_wcslen (const wchar_t *s)
247# endif 264# endif
248#endif 265#endif
249 266
250#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION 267#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
251# if HAVE_WCSNLEN 268# if HAVE_WCSNLEN
252# define local_wcsnlen wcsnlen 269# define local_wcsnlen wcsnlen
253# else 270# else
@@ -266,6 +283,74 @@ local_wcsnlen (const wchar_t *s, size_t maxlen)
266# endif 283# endif
267#endif 284#endif
268 285
286#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
287# if ENABLE_WCHAR_FALLBACK
288static size_t
289wctomb_fallback (char *s, wchar_t wc)
290{
291 static char hex[16] = "0123456789ABCDEF";
292
293 s[0] = '\\';
294 if (sizeof (wchar_t) > 2 && wc > 0xffff)
295 {
296# if __STDC_ISO_10646__ || (__GLIBC__ >= 2) || (defined _WIN32 || defined __CYGWIN__)
297 s[1] = 'U';
298# else
299 s[1] = 'W';
300# endif
301 s[2] = hex[(wc & 0xf0000000U) >> 28];
302 s[3] = hex[(wc & 0xf000000U) >> 24];
303 s[4] = hex[(wc & 0xf00000U) >> 20];
304 s[5] = hex[(wc & 0xf0000U) >> 16];
305 s[6] = hex[(wc & 0xf000U) >> 12];
306 s[7] = hex[(wc & 0xf00U) >> 8];
307 s[8] = hex[(wc & 0xf0U) >> 4];
308 s[9] = hex[wc & 0xfU];
309 return 10;
310 }
311 else
312 {
313# if __STDC_ISO_10646__ || (__GLIBC__ >= 2) || (defined _WIN32 || defined __CYGWIN__)
314 s[1] = 'u';
315# else
316 s[1] = 'w';
317# endif
318 s[2] = hex[(wc & 0xf000U) >> 12];
319 s[3] = hex[(wc & 0xf00U) >> 8];
320 s[4] = hex[(wc & 0xf0U) >> 4];
321 s[5] = hex[wc & 0xfU];
322 return 6;
323 }
324}
325# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
326static size_t
327local_wcrtomb (char *s, wchar_t wc, mbstate_t *ps)
328{
329 size_t count = wcrtomb (s, wc, ps);
330 if (count == (size_t)(-1))
331 count = wctomb_fallback (s, wc);
332 return count;
333}
334# else
335static int
336local_wctomb (char *s, wchar_t wc)
337{
338 int count = wctomb (s, wc);
339 if (count < 0)
340 count = wctomb_fallback (s, wc);
341 return count;
342}
343# define local_wcrtomb(S, WC, PS) local_wctomb ((S), (WC))
344# endif
345# else
346# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
347# define local_wcrtomb(S, WC, PS) wcrtomb ((S), (WC), (PS))
348# else
349# define local_wcrtomb(S, WC, PS) wctomb ((S), (WC))
350# endif
351# endif
352#endif
353
269#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL 354#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_DOUBLE) && !defined IN_LIBINTL
270/* Determine the decimal-point character according to the current locale. */ 355/* Determine the decimal-point character according to the current locale. */
271# ifndef decimal_point_char_defined 356# ifndef decimal_point_char_defined
@@ -554,7 +639,8 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
554 mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */ 639 mp_limb_t msd = b_ptr[b_len - 1]; /* = b[n-1], > 0 */
555 /* Determine s = GMP_LIMB_BITS - integer_length (msd). 640 /* Determine s = GMP_LIMB_BITS - integer_length (msd).
556 Code copied from gnulib's integer_length.c. */ 641 Code copied from gnulib's integer_length.c. */
557# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) 642# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) \
643 || (__clang_major__ >= 4)
558 s = __builtin_clz (msd); 644 s = __builtin_clz (msd);
559# else 645# else
560# if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT 646# if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT
@@ -829,8 +915,7 @@ divide (mpn_t a, mpn_t b, mpn_t *q)
829 q_ptr[q_len++] = 1; 915 q_ptr[q_len++] = 1;
830 } 916 }
831 keep_q: 917 keep_q:
832 if (tmp_roomptr != NULL) 918 free (tmp_roomptr);
833 free (tmp_roomptr);
834 q->limbs = q_ptr; 919 q->limbs = q_ptr;
835 q->nlimbs = q_len; 920 q->nlimbs = q_len;
836 return roomptr; 921 return roomptr;
@@ -849,7 +934,9 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
849 size_t a_len = a.nlimbs; 934 size_t a_len = a.nlimbs;
850 /* 0.03345 is slightly larger than log(2)/(9*log(10)). */ 935 /* 0.03345 is slightly larger than log(2)/(9*log(10)). */
851 size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1); 936 size_t c_len = 9 * ((size_t)(a_len * (GMP_LIMB_BITS * 0.03345f)) + 1);
852 char *c_ptr = (char *) malloc (xsum (c_len, extra_zeroes)); 937 /* We need extra_zeroes bytes for zeroes, followed by c_len bytes for the
938 digits of a, followed by 1 byte for the terminating NUL. */
939 char *c_ptr = (char *) malloc (xsum (xsum (extra_zeroes, c_len), 1));
853 if (c_ptr != NULL) 940 if (c_ptr != NULL)
854 { 941 {
855 char *d_ptr = c_ptr; 942 char *d_ptr = c_ptr;
@@ -1517,7 +1604,7 @@ is_borderline (const char *digits, size_t precision)
1517 1604
1518#endif 1605#endif
1519 1606
1520#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 1607#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
1521 1608
1522/* Use a different function name, to make it possible that the 'wchar_t' 1609/* Use a different function name, to make it possible that the 'wchar_t'
1523 parametrization and the 'char' parametrization get compiled in the same 1610 parametrization and the 'char' parametrization get compiled in the same
@@ -1540,16 +1627,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1540 switch (conversion) 1627 switch (conversion)
1541 { 1628 {
1542 case 'd': case 'i': case 'u': 1629 case 'd': case 'i': case 'u':
1543# if HAVE_LONG_LONG_INT
1544 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1630 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1545 tmp_length = 1631 tmp_length =
1546 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1632 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1547 * 0.30103 /* binary -> decimal */ 1633 * 0.30103 /* binary -> decimal */
1548 ) 1634 )
1549 + 1; /* turn floor into ceil */ 1635 + 1; /* turn floor into ceil */
1550 else 1636 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1551# endif
1552 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1553 tmp_length = 1637 tmp_length =
1554 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1638 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1555 * 0.30103 /* binary -> decimal */ 1639 * 0.30103 /* binary -> decimal */
@@ -1570,16 +1654,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1570 break; 1654 break;
1571 1655
1572 case 'o': 1656 case 'o':
1573# if HAVE_LONG_LONG_INT
1574 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1657 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1575 tmp_length = 1658 tmp_length =
1576 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1659 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1577 * 0.333334 /* binary -> octal */ 1660 * 0.333334 /* binary -> octal */
1578 ) 1661 )
1579 + 1; /* turn floor into ceil */ 1662 + 1; /* turn floor into ceil */
1580 else 1663 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1581# endif
1582 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1583 tmp_length = 1664 tmp_length =
1584 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1665 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1585 * 0.333334 /* binary -> octal */ 1666 * 0.333334 /* binary -> octal */
@@ -1598,16 +1679,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1598 break; 1679 break;
1599 1680
1600 case 'x': case 'X': 1681 case 'x': case 'X':
1601# if HAVE_LONG_LONG_INT
1602 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1682 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1603 tmp_length = 1683 tmp_length =
1604 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1684 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1605 * 0.25 /* binary -> hexadecimal */ 1685 * 0.25 /* binary -> hexadecimal */
1606 ) 1686 )
1607 + 1; /* turn floor into ceil */ 1687 + 1; /* turn floor into ceil */
1608 else 1688 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1609# endif
1610 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1611 tmp_length = 1689 tmp_length =
1612 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1690 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1613 * 0.25 /* binary -> hexadecimal */ 1691 * 0.25 /* binary -> hexadecimal */
@@ -1673,7 +1751,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1673 case 'c': 1751 case 'c':
1674# if HAVE_WINT_T && !WIDE_CHAR_VERSION 1752# if HAVE_WINT_T && !WIDE_CHAR_VERSION
1675 if (type == TYPE_WIDE_CHAR) 1753 if (type == TYPE_WIDE_CHAR)
1676 tmp_length = MB_CUR_MAX; 1754 {
1755 tmp_length = MB_CUR_MAX;
1756# if ENABLE_WCHAR_FALLBACK
1757 if (tmp_length < (sizeof (wchar_t) > 2 ? 10 : 6))
1758 tmp_length = (sizeof (wchar_t) > 2 ? 10 : 6);
1759# endif
1760 }
1677 else 1761 else
1678# endif 1762# endif
1679 tmp_length = 1; 1763 tmp_length = 1;
@@ -1780,6 +1864,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1780 /* errno is already set. */ 1864 /* errno is already set. */
1781 return NULL; 1865 return NULL;
1782 1866
1867 /* Frees the memory allocated by this function. Preserves errno. */
1783#define CLEANUP() \ 1868#define CLEANUP() \
1784 if (d.dir != d.direct_alloc_dir) \ 1869 if (d.dir != d.direct_alloc_dir) \
1785 free (d.dir); \ 1870 free (d.dir); \
@@ -1787,11 +1872,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1787 free (a.arg); 1872 free (a.arg);
1788 1873
1789 if (PRINTF_FETCHARGS (args, &a) < 0) 1874 if (PRINTF_FETCHARGS (args, &a) < 0)
1790 { 1875 goto fail_1_with_EINVAL;
1791 CLEANUP ();
1792 errno = EINVAL;
1793 return NULL;
1794 }
1795 1876
1796 { 1877 {
1797 size_t buf_neededlength; 1878 size_t buf_neededlength;
@@ -1827,24 +1908,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1827 buf_malloced = buf; 1908 buf_malloced = buf;
1828 } 1909 }
1829 1910
1830 if (resultbuf != NULL) 1911 result = resultbuf;
1831 { 1912 allocated = (resultbuf != NULL ? *lengthp : 0);
1832 result = resultbuf;
1833 allocated = *lengthp;
1834 }
1835 else
1836 {
1837 result = NULL;
1838 allocated = 0;
1839 }
1840 length = 0; 1913 length = 0;
1841 /* Invariants: 1914 /* Invariants:
1842 result is either == resultbuf or == NULL or malloc-allocated. 1915 result is either == resultbuf or malloc-allocated.
1916 If result == NULL, resultbuf is == NULL as well.
1843 If length > 0, then result != NULL. */ 1917 If length > 0, then result != NULL. */
1844 1918
1845 /* Ensures that allocated >= needed. Aborts through a jump to 1919 /* Ensures that allocated >= needed. Aborts through a jump to
1846 out_of_memory if needed is SIZE_MAX or otherwise too big. */ 1920 out_of_memory if needed is SIZE_MAX or otherwise too big. */
1847#define ENSURE_ALLOCATION(needed) \ 1921#define ENSURE_ALLOCATION_ELSE(needed, oom_statement) \
1848 if ((needed) > allocated) \ 1922 if ((needed) > allocated) \
1849 { \ 1923 { \
1850 size_t memory_size; \ 1924 size_t memory_size; \
@@ -1855,17 +1929,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1855 allocated = (needed); \ 1929 allocated = (needed); \
1856 memory_size = xtimes (allocated, sizeof (DCHAR_T)); \ 1930 memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
1857 if (size_overflow_p (memory_size)) \ 1931 if (size_overflow_p (memory_size)) \
1858 goto out_of_memory; \ 1932 oom_statement \
1859 if (result == resultbuf || result == NULL) \ 1933 if (result == resultbuf) \
1860 memory = (DCHAR_T *) malloc (memory_size); \ 1934 memory = (DCHAR_T *) malloc (memory_size); \
1861 else \ 1935 else \
1862 memory = (DCHAR_T *) realloc (result, memory_size); \ 1936 memory = (DCHAR_T *) realloc (result, memory_size); \
1863 if (memory == NULL) \ 1937 if (memory == NULL) \
1864 goto out_of_memory; \ 1938 oom_statement \
1865 if (result == resultbuf && length > 0) \ 1939 if (result == resultbuf && length > 0) \
1866 DCHAR_CPY (memory, result, length); \ 1940 DCHAR_CPY (memory, result, length); \
1867 result = memory; \ 1941 result = memory; \
1868 } 1942 }
1943#define ENSURE_ALLOCATION(needed) \
1944 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; )
1869 1945
1870 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) 1946 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
1871 { 1947 {
@@ -1886,7 +1962,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1886 else 1962 else
1887 { 1963 {
1888 do 1964 do
1889 result[length++] = (unsigned char) *cp++; 1965 result[length++] = *cp++;
1890 while (--n > 0); 1966 while (--n > 0);
1891 } 1967 }
1892 } 1968 }
@@ -1926,11 +2002,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1926 case TYPE_COUNT_LONGINT_POINTER: 2002 case TYPE_COUNT_LONGINT_POINTER:
1927 *a.arg[dp->arg_index].a.a_count_longint_pointer = length; 2003 *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
1928 break; 2004 break;
1929#if HAVE_LONG_LONG_INT
1930 case TYPE_COUNT_LONGLONGINT_POINTER: 2005 case TYPE_COUNT_LONGLONGINT_POINTER:
1931 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; 2006 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
1932 break; 2007 break;
1933#endif
1934 default: 2008 default:
1935 abort (); 2009 abort ();
1936 } 2010 }
@@ -1957,15 +2031,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1957 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 2031 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
1958 abort (); 2032 abort ();
1959 arg = a.arg[dp->width_arg_index].a.a_int; 2033 arg = a.arg[dp->width_arg_index].a.a_int;
2034 width = arg;
1960 if (arg < 0) 2035 if (arg < 0)
1961 { 2036 {
1962 /* "A negative field width is taken as a '-' flag 2037 /* "A negative field width is taken as a '-' flag
1963 followed by a positive field width." */ 2038 followed by a positive field width." */
1964 flags |= FLAG_LEFT; 2039 flags |= FLAG_LEFT;
1965 width = (unsigned int) (-arg); 2040 width = -width;
1966 } 2041 }
1967 else
1968 width = arg;
1969 } 2042 }
1970 else 2043 else
1971 { 2044 {
@@ -2027,15 +2100,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2027 if (count == 0) 2100 if (count == 0)
2028 break; 2101 break;
2029 if (count < 0) 2102 if (count < 0)
2030 { 2103 goto fail_with_EILSEQ;
2031 if (!(result == resultbuf || result == NULL))
2032 free (result);
2033 if (buf_malloced != NULL)
2034 free (buf_malloced);
2035 CLEANUP ();
2036 errno = EILSEQ;
2037 return NULL;
2038 }
2039 arg_end += count; 2104 arg_end += count;
2040 characters++; 2105 characters++;
2041 } 2106 }
@@ -2052,15 +2117,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2052 if (count == 0) 2117 if (count == 0)
2053 break; 2118 break;
2054 if (count < 0) 2119 if (count < 0)
2055 { 2120 goto fail_with_EILSEQ;
2056 if (!(result == resultbuf || result == NULL))
2057 free (result);
2058 if (buf_malloced != NULL)
2059 free (buf_malloced);
2060 CLEANUP ();
2061 errno = EILSEQ;
2062 return NULL;
2063 }
2064 arg_end += count; 2121 arg_end += count;
2065 characters++; 2122 characters++;
2066 } 2123 }
@@ -2073,8 +2130,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2073 characters = 0; 2130 characters = 0;
2074 } 2131 }
2075 2132
2076 if (has_width && width > characters 2133 if (characters < width && !(dp->flags & FLAG_LEFT))
2077 && !(dp->flags & FLAG_LEFT))
2078 { 2134 {
2079 size_t n = width - characters; 2135 size_t n = width - characters;
2080 ENSURE_ALLOCATION (xsum (length, n)); 2136 ENSURE_ALLOCATION (xsum (length, n));
@@ -2107,19 +2163,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2107 converted, &converted_len); 2163 converted, &converted_len);
2108# endif 2164# endif
2109 if (converted == NULL) 2165 if (converted == NULL)
2110 { 2166 goto fail_with_errno;
2111 int saved_errno = errno;
2112 if (!(result == resultbuf || result == NULL))
2113 free (result);
2114 if (buf_malloced != NULL)
2115 free (buf_malloced);
2116 CLEANUP ();
2117 errno = saved_errno;
2118 return NULL;
2119 }
2120 if (converted != result + length) 2167 if (converted != result + length)
2121 { 2168 {
2122 ENSURE_ALLOCATION (xsum (length, converted_len)); 2169 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2170 { free (converted); goto out_of_memory; });
2123 DCHAR_CPY (result + length, converted, converted_len); 2171 DCHAR_CPY (result + length, converted, converted_len);
2124 free (converted); 2172 free (converted);
2125 } 2173 }
@@ -2127,8 +2175,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2127 } 2175 }
2128# endif 2176# endif
2129 2177
2130 if (has_width && width > characters 2178 if (characters < width && (dp->flags & FLAG_LEFT))
2131 && (dp->flags & FLAG_LEFT))
2132 { 2179 {
2133 size_t n = width - characters; 2180 size_t n = width - characters;
2134 ENSURE_ALLOCATION (xsum (length, n)); 2181 ENSURE_ALLOCATION (xsum (length, n));
@@ -2155,15 +2202,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2155 if (count == 0) 2202 if (count == 0)
2156 break; 2203 break;
2157 if (count < 0) 2204 if (count < 0)
2158 { 2205 goto fail_with_EILSEQ;
2159 if (!(result == resultbuf || result == NULL))
2160 free (result);
2161 if (buf_malloced != NULL)
2162 free (buf_malloced);
2163 CLEANUP ();
2164 errno = EILSEQ;
2165 return NULL;
2166 }
2167 arg_end += count; 2206 arg_end += count;
2168 characters++; 2207 characters++;
2169 } 2208 }
@@ -2180,15 +2219,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2180 if (count == 0) 2219 if (count == 0)
2181 break; 2220 break;
2182 if (count < 0) 2221 if (count < 0)
2183 { 2222 goto fail_with_EILSEQ;
2184 if (!(result == resultbuf || result == NULL))
2185 free (result);
2186 if (buf_malloced != NULL)
2187 free (buf_malloced);
2188 CLEANUP ();
2189 errno = EILSEQ;
2190 return NULL;
2191 }
2192 arg_end += count; 2223 arg_end += count;
2193 characters++; 2224 characters++;
2194 } 2225 }
@@ -2201,8 +2232,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2201 characters = 0; 2232 characters = 0;
2202 } 2233 }
2203 2234
2204 if (has_width && width > characters 2235 if (characters < width && !(dp->flags & FLAG_LEFT))
2205 && !(dp->flags & FLAG_LEFT))
2206 { 2236 {
2207 size_t n = width - characters; 2237 size_t n = width - characters;
2208 ENSURE_ALLOCATION (xsum (length, n)); 2238 ENSURE_ALLOCATION (xsum (length, n));
@@ -2235,19 +2265,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2235 converted, &converted_len); 2265 converted, &converted_len);
2236# endif 2266# endif
2237 if (converted == NULL) 2267 if (converted == NULL)
2238 { 2268 goto fail_with_errno;
2239 int saved_errno = errno;
2240 if (!(result == resultbuf || result == NULL))
2241 free (result);
2242 if (buf_malloced != NULL)
2243 free (buf_malloced);
2244 CLEANUP ();
2245 errno = saved_errno;
2246 return NULL;
2247 }
2248 if (converted != result + length) 2269 if (converted != result + length)
2249 { 2270 {
2250 ENSURE_ALLOCATION (xsum (length, converted_len)); 2271 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2272 { free (converted); goto out_of_memory; });
2251 DCHAR_CPY (result + length, converted, converted_len); 2273 DCHAR_CPY (result + length, converted, converted_len);
2252 free (converted); 2274 free (converted);
2253 } 2275 }
@@ -2255,8 +2277,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2255 } 2277 }
2256# endif 2278# endif
2257 2279
2258 if (has_width && width > characters 2280 if (characters < width && (dp->flags & FLAG_LEFT))
2259 && (dp->flags & FLAG_LEFT))
2260 { 2281 {
2261 size_t n = width - characters; 2282 size_t n = width - characters;
2262 ENSURE_ALLOCATION (xsum (length, n)); 2283 ENSURE_ALLOCATION (xsum (length, n));
@@ -2283,15 +2304,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2283 if (count == 0) 2304 if (count == 0)
2284 break; 2305 break;
2285 if (count < 0) 2306 if (count < 0)
2286 { 2307 goto fail_with_EILSEQ;
2287 if (!(result == resultbuf || result == NULL))
2288 free (result);
2289 if (buf_malloced != NULL)
2290 free (buf_malloced);
2291 CLEANUP ();
2292 errno = EILSEQ;
2293 return NULL;
2294 }
2295 arg_end += count; 2308 arg_end += count;
2296 characters++; 2309 characters++;
2297 } 2310 }
@@ -2308,15 +2321,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2308 if (count == 0) 2321 if (count == 0)
2309 break; 2322 break;
2310 if (count < 0) 2323 if (count < 0)
2311 { 2324 goto fail_with_EILSEQ;
2312 if (!(result == resultbuf || result == NULL))
2313 free (result);
2314 if (buf_malloced != NULL)
2315 free (buf_malloced);
2316 CLEANUP ();
2317 errno = EILSEQ;
2318 return NULL;
2319 }
2320 arg_end += count; 2325 arg_end += count;
2321 characters++; 2326 characters++;
2322 } 2327 }
@@ -2329,8 +2334,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2329 characters = 0; 2334 characters = 0;
2330 } 2335 }
2331 2336
2332 if (has_width && width > characters 2337 if (characters < width && !(dp->flags & FLAG_LEFT))
2333 && !(dp->flags & FLAG_LEFT))
2334 { 2338 {
2335 size_t n = width - characters; 2339 size_t n = width - characters;
2336 ENSURE_ALLOCATION (xsum (length, n)); 2340 ENSURE_ALLOCATION (xsum (length, n));
@@ -2363,19 +2367,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2363 converted, &converted_len); 2367 converted, &converted_len);
2364# endif 2368# endif
2365 if (converted == NULL) 2369 if (converted == NULL)
2366 { 2370 goto fail_with_errno;
2367 int saved_errno = errno;
2368 if (!(result == resultbuf || result == NULL))
2369 free (result);
2370 if (buf_malloced != NULL)
2371 free (buf_malloced);
2372 CLEANUP ();
2373 errno = saved_errno;
2374 return NULL;
2375 }
2376 if (converted != result + length) 2371 if (converted != result + length)
2377 { 2372 {
2378 ENSURE_ALLOCATION (xsum (length, converted_len)); 2373 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2374 { free (converted); goto out_of_memory; });
2379 DCHAR_CPY (result + length, converted, converted_len); 2375 DCHAR_CPY (result + length, converted, converted_len);
2380 free (converted); 2376 free (converted);
2381 } 2377 }
@@ -2383,8 +2379,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2383 } 2379 }
2384# endif 2380# endif
2385 2381
2386 if (has_width && width > characters 2382 if (characters < width && (dp->flags & FLAG_LEFT))
2387 && (dp->flags & FLAG_LEFT))
2388 { 2383 {
2389 size_t n = width - characters; 2384 size_t n = width - characters;
2390 ENSURE_ALLOCATION (xsum (length, n)); 2385 ENSURE_ALLOCATION (xsum (length, n));
@@ -2399,7 +2394,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2399 } 2394 }
2400 } 2395 }
2401#endif 2396#endif
2402#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T 2397#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL) || ENABLE_WCHAR_FALLBACK) && HAVE_WCHAR_T
2403 else if (dp->conversion == 's' 2398 else if (dp->conversion == 's'
2404# if WIDE_CHAR_VERSION 2399# if WIDE_CHAR_VERSION
2405 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING 2400 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2435,15 +2430,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2435 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 2430 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2436 abort (); 2431 abort ();
2437 arg = a.arg[dp->width_arg_index].a.a_int; 2432 arg = a.arg[dp->width_arg_index].a.a_int;
2433 width = arg;
2438 if (arg < 0) 2434 if (arg < 0)
2439 { 2435 {
2440 /* "A negative field width is taken as a '-' flag 2436 /* "A negative field width is taken as a '-' flag
2441 followed by a positive field width." */ 2437 followed by a positive field width." */
2442 flags |= FLAG_LEFT; 2438 flags |= FLAG_LEFT;
2443 width = (unsigned int) (-arg); 2439 width = -width;
2444 } 2440 }
2445 else
2446 width = arg;
2447 } 2441 }
2448 else 2442 else
2449 { 2443 {
@@ -2515,16 +2509,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2515 /* Found the terminating NUL. */ 2509 /* Found the terminating NUL. */
2516 break; 2510 break;
2517 if (count < 0) 2511 if (count < 0)
2518 { 2512 /* Invalid or incomplete multibyte character. */
2519 /* Invalid or incomplete multibyte character. */ 2513 goto fail_with_EILSEQ;
2520 if (!(result == resultbuf || result == NULL))
2521 free (result);
2522 if (buf_malloced != NULL)
2523 free (buf_malloced);
2524 CLEANUP ();
2525 errno = EILSEQ;
2526 return NULL;
2527 }
2528 arg_end += count; 2514 arg_end += count;
2529 characters++; 2515 characters++;
2530 } 2516 }
@@ -2551,16 +2537,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2551 /* Found the terminating NUL. */ 2537 /* Found the terminating NUL. */
2552 break; 2538 break;
2553 if (count < 0) 2539 if (count < 0)
2554 { 2540 /* Invalid or incomplete multibyte character. */
2555 /* Invalid or incomplete multibyte character. */ 2541 goto fail_with_EILSEQ;
2556 if (!(result == resultbuf || result == NULL))
2557 free (result);
2558 if (buf_malloced != NULL)
2559 free (buf_malloced);
2560 CLEANUP ();
2561 errno = EILSEQ;
2562 return NULL;
2563 }
2564 arg_end += count; 2542 arg_end += count;
2565 characters++; 2543 characters++;
2566 } 2544 }
@@ -2573,8 +2551,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2573 characters = 0; 2551 characters = 0;
2574 } 2552 }
2575 2553
2576 if (has_width && width > characters 2554 if (characters < width && !(dp->flags & FLAG_LEFT))
2577 && !(dp->flags & FLAG_LEFT))
2578 { 2555 {
2579 size_t n = width - characters; 2556 size_t n = width - characters;
2580 ENSURE_ALLOCATION (xsum (length, n)); 2557 ENSURE_ALLOCATION (xsum (length, n));
@@ -2635,8 +2612,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2635 } 2612 }
2636 } 2613 }
2637 2614
2638 if (has_width && width > characters 2615 if (characters < width && (dp->flags & FLAG_LEFT))
2639 && (dp->flags & FLAG_LEFT))
2640 { 2616 {
2641 size_t n = width - characters; 2617 size_t n = width - characters;
2642 ENSURE_ALLOCATION (xsum (length, n)); 2618 ENSURE_ALLOCATION (xsum (length, n));
@@ -2677,23 +2653,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2677 if (*arg_end == 0) 2653 if (*arg_end == 0)
2678 /* Found the terminating null wide character. */ 2654 /* Found the terminating null wide character. */
2679 break; 2655 break;
2680# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2656 count = local_wcrtomb (cbuf, *arg_end, &state);
2681 count = wcrtomb (cbuf, *arg_end, &state);
2682# else
2683 count = wctomb (cbuf, *arg_end);
2684# endif
2685 if (count < 0) 2657 if (count < 0)
2686 { 2658 /* Cannot convert. */
2687 /* Cannot convert. */ 2659 goto fail_with_EILSEQ;
2688 if (!(result == resultbuf || result == NULL)) 2660 if (precision < (unsigned int) count)
2689 free (result);
2690 if (buf_malloced != NULL)
2691 free (buf_malloced);
2692 CLEANUP ();
2693 errno = EILSEQ;
2694 return NULL;
2695 }
2696 if (precision < count)
2697 break; 2661 break;
2698 arg_end++; 2662 arg_end++;
2699 characters += count; 2663 characters += count;
@@ -2722,22 +2686,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2722 if (*arg_end == 0) 2686 if (*arg_end == 0)
2723 /* Found the terminating null wide character. */ 2687 /* Found the terminating null wide character. */
2724 break; 2688 break;
2725# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2689 count = local_wcrtomb (cbuf, *arg_end, &state);
2726 count = wcrtomb (cbuf, *arg_end, &state);
2727# else
2728 count = wctomb (cbuf, *arg_end);
2729# endif
2730 if (count < 0) 2690 if (count < 0)
2731 { 2691 /* Cannot convert. */
2732 /* Cannot convert. */ 2692 goto fail_with_EILSEQ;
2733 if (!(result == resultbuf || result == NULL))
2734 free (result);
2735 if (buf_malloced != NULL)
2736 free (buf_malloced);
2737 CLEANUP ();
2738 errno = EILSEQ;
2739 return NULL;
2740 }
2741 arg_end++; 2693 arg_end++;
2742 characters += count; 2694 characters += count;
2743 } 2695 }
@@ -2771,11 +2723,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2771 2723
2772 if (*arg == 0) 2724 if (*arg == 0)
2773 abort (); 2725 abort ();
2774# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2726 count = local_wcrtomb (cbuf, *arg, &state);
2775 count = wcrtomb (cbuf, *arg, &state);
2776# else
2777 count = wctomb (cbuf, *arg);
2778# endif
2779 if (count <= 0) 2727 if (count <= 0)
2780 /* Inconsistency. */ 2728 /* Inconsistency. */
2781 abort (); 2729 abort ();
@@ -2797,15 +2745,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2797 NULL, &tmpdst_len); 2745 NULL, &tmpdst_len);
2798 if (tmpdst == NULL) 2746 if (tmpdst == NULL)
2799 { 2747 {
2800 int saved_errno = errno;
2801 free (tmpsrc); 2748 free (tmpsrc);
2802 if (!(result == resultbuf || result == NULL)) 2749 goto fail_with_errno;
2803 free (result);
2804 if (buf_malloced != NULL)
2805 free (buf_malloced);
2806 CLEANUP ();
2807 errno = saved_errno;
2808 return NULL;
2809 } 2750 }
2810 free (tmpsrc); 2751 free (tmpsrc);
2811# endif 2752# endif
@@ -2827,8 +2768,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2827 /* w doesn't matter. */ 2768 /* w doesn't matter. */
2828 w = 0; 2769 w = 0;
2829 2770
2830 if (has_width && width > w 2771 if (w < width && !(dp->flags & FLAG_LEFT))
2831 && !(dp->flags & FLAG_LEFT))
2832 { 2772 {
2833 size_t n = width - w; 2773 size_t n = width - w;
2834 ENSURE_ALLOCATION (xsum (length, n)); 2774 ENSURE_ALLOCATION (xsum (length, n));
@@ -2853,11 +2793,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2853 2793
2854 if (*arg == 0) 2794 if (*arg == 0)
2855 abort (); 2795 abort ();
2856# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2796 count = local_wcrtomb (cbuf, *arg, &state);
2857 count = wcrtomb (cbuf, *arg, &state);
2858# else
2859 count = wctomb (cbuf, *arg);
2860# endif
2861 if (count <= 0) 2797 if (count <= 0)
2862 /* Inconsistency. */ 2798 /* Inconsistency. */
2863 abort (); 2799 abort ();
@@ -2882,22 +2818,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2882 2818
2883 if (*arg == 0) 2819 if (*arg == 0)
2884 abort (); 2820 abort ();
2885# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2821 count = local_wcrtomb (cbuf, *arg, &state);
2886 count = wcrtomb (cbuf, *arg, &state);
2887# else
2888 count = wctomb (cbuf, *arg);
2889# endif
2890 if (count <= 0) 2822 if (count <= 0)
2891 { 2823 /* Cannot convert. */
2892 /* Cannot convert. */ 2824 goto fail_with_EILSEQ;
2893 if (!(result == resultbuf || result == NULL))
2894 free (result);
2895 if (buf_malloced != NULL)
2896 free (buf_malloced);
2897 CLEANUP ();
2898 errno = EILSEQ;
2899 return NULL;
2900 }
2901 ENSURE_ALLOCATION (xsum (length, count)); 2825 ENSURE_ALLOCATION (xsum (length, count));
2902 memcpy (result + length, cbuf, count); 2826 memcpy (result + length, cbuf, count);
2903 length += count; 2827 length += count;
@@ -2905,14 +2829,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2905 } 2829 }
2906 } 2830 }
2907# else 2831# else
2908 ENSURE_ALLOCATION (xsum (length, tmpdst_len)); 2832 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
2833 { free (tmpdst); goto out_of_memory; });
2909 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 2834 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
2910 free (tmpdst); 2835 free (tmpdst);
2911 length += tmpdst_len; 2836 length += tmpdst_len;
2912# endif 2837# endif
2913 2838
2914 if (has_width && width > w 2839 if (w < width && (dp->flags & FLAG_LEFT))
2915 && (dp->flags & FLAG_LEFT))
2916 { 2840 {
2917 size_t n = width - w; 2841 size_t n = width - w;
2918 ENSURE_ALLOCATION (xsum (length, n)); 2842 ENSURE_ALLOCATION (xsum (length, n));
@@ -2923,6 +2847,202 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2923# endif 2847# endif
2924 } 2848 }
2925#endif 2849#endif
2850#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION
2851 else if (dp->conversion == 'c'
2852 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)
2853 {
2854 /* Implement the 'lc' directive ourselves, in order to provide
2855 the fallback that avoids EILSEQ. */
2856 int flags = dp->flags;
2857 int has_width;
2858 size_t width;
2859
2860 has_width = 0;
2861 width = 0;
2862 if (dp->width_start != dp->width_end)
2863 {
2864 if (dp->width_arg_index != ARG_NONE)
2865 {
2866 int arg;
2867
2868 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2869 abort ();
2870 arg = a.arg[dp->width_arg_index].a.a_int;
2871 width = arg;
2872 if (arg < 0)
2873 {
2874 /* "A negative field width is taken as a '-' flag
2875 followed by a positive field width." */
2876 flags |= FLAG_LEFT;
2877 width = -width;
2878 }
2879 }
2880 else
2881 {
2882 const FCHAR_T *digitp = dp->width_start;
2883
2884 do
2885 width = xsum (xtimes (width, 10), *digitp++ - '0');
2886 while (digitp != dp->width_end);
2887 }
2888 has_width = 1;
2889 }
2890
2891 /* %lc in vasnprintf. See the specification of fprintf. */
2892 {
2893 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
2894 size_t characters;
2895# if !DCHAR_IS_TCHAR
2896 /* This code assumes that TCHAR_T is 'char'. */
2897 verify (sizeof (TCHAR_T) == 1);
2898 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
2899 DCHAR_T *tmpdst;
2900 size_t tmpdst_len;
2901# endif
2902 size_t w;
2903
2904# if DCHAR_IS_TCHAR
2905 if (has_width)
2906# endif
2907 {
2908 /* Count the number of bytes. */
2909 characters = 0;
2910 if (arg != 0)
2911 {
2912 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2913 int count;
2914# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2915 mbstate_t state;
2916 memset (&state, '\0', sizeof (mbstate_t));
2917# endif
2918
2919 count = local_wcrtomb (cbuf, arg, &state);
2920 if (count < 0)
2921 /* Inconsistency. */
2922 abort ();
2923 characters = count;
2924 }
2925 }
2926# if DCHAR_IS_TCHAR
2927 else
2928 {
2929 /* The number of bytes doesn't matter. */
2930 characters = 0;
2931 }
2932# endif
2933
2934# if !DCHAR_IS_TCHAR
2935 /* Convert the string into a piece of temporary memory. */
2936 if (characters > 0) /* implies arg != 0 */
2937 {
2938 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
2939 int count;
2940# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2941 mbstate_t state;
2942 memset (&state, '\0', sizeof (mbstate_t));
2943# endif
2944
2945 count = local_wcrtomb (cbuf, arg, &state);
2946 if (count <= 0)
2947 /* Inconsistency. */
2948 abort ();
2949 memcpy (tmpsrc, cbuf, count);
2950 }
2951
2952 /* Convert from TCHAR_T[] to DCHAR_T[]. */
2953 tmpdst =
2954 DCHAR_CONV_FROM_ENCODING (locale_charset (),
2955 iconveh_question_mark,
2956 tmpsrc, characters,
2957 NULL,
2958 NULL, &tmpdst_len);
2959 if (tmpdst == NULL)
2960 goto fail_with_errno;
2961# endif
2962
2963 if (has_width)
2964 {
2965# if ENABLE_UNISTDIO
2966 /* Outside POSIX, it's preferable to compare the width
2967 against the number of _characters_ of the converted
2968 value. */
2969 w = DCHAR_MBSNLEN (result + length, characters);
2970# else
2971 /* The width is compared against the number of _bytes_
2972 of the converted value, says POSIX. */
2973 w = characters;
2974# endif
2975 }
2976 else
2977 /* w doesn't matter. */
2978 w = 0;
2979
2980 if (w < width && !(dp->flags & FLAG_LEFT))
2981 {
2982 size_t n = width - w;
2983 ENSURE_ALLOCATION (xsum (length, n));
2984 DCHAR_SET (result + length, ' ', n);
2985 length += n;
2986 }
2987
2988# if DCHAR_IS_TCHAR
2989 if (has_width)
2990 {
2991 /* We know the number of bytes in advance. */
2992 ENSURE_ALLOCATION (xsum (length, characters));
2993 if (characters > 0) /* implies arg != 0 */
2994 {
2995 int count;
2996# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
2997 mbstate_t state;
2998 memset (&state, '\0', sizeof (mbstate_t));
2999# endif
3000
3001 count = local_wcrtomb (result + length, arg, &state);
3002 if (count <= 0)
3003 /* Inconsistency. */
3004 abort ();
3005 length += count;
3006 }
3007 }
3008 else
3009 {
3010 if (arg != 0)
3011 {
3012 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3013 int count;
3014# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3015 mbstate_t state;
3016 memset (&state, '\0', sizeof (mbstate_t));
3017# endif
3018
3019 count = local_wcrtomb (cbuf, arg, &state);
3020 if (count <= 0)
3021 /* Inconsistency. */
3022 abort ();
3023 ENSURE_ALLOCATION (xsum (length, count));
3024 memcpy (result + length, cbuf, count);
3025 length += count;
3026 }
3027 }
3028# else
3029 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
3030 { free (tmpdst); goto out_of_memory; });
3031 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3032 free (tmpdst);
3033 length += tmpdst_len;
3034# endif
3035
3036 if (w < width && (dp->flags & FLAG_LEFT))
3037 {
3038 size_t n = width - w;
3039 ENSURE_ALLOCATION (xsum (length, n));
3040 DCHAR_SET (result + length, ' ', n);
3041 length += n;
3042 }
3043 }
3044 }
3045#endif
2926#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 3046#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
2927 else if ((dp->conversion == 'a' || dp->conversion == 'A') 3047 else if ((dp->conversion == 'a' || dp->conversion == 'A')
2928# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) 3048# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
@@ -2939,17 +3059,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2939 { 3059 {
2940 arg_type type = a.arg[dp->arg_index].type; 3060 arg_type type = a.arg[dp->arg_index].type;
2941 int flags = dp->flags; 3061 int flags = dp->flags;
2942 int has_width;
2943 size_t width; 3062 size_t width;
2944 int has_precision; 3063 int has_precision;
2945 size_t precision; 3064 size_t precision;
2946 size_t tmp_length; 3065 size_t tmp_length;
3066 size_t count;
2947 DCHAR_T tmpbuf[700]; 3067 DCHAR_T tmpbuf[700];
2948 DCHAR_T *tmp; 3068 DCHAR_T *tmp;
2949 DCHAR_T *pad_ptr; 3069 DCHAR_T *pad_ptr;
2950 DCHAR_T *p; 3070 DCHAR_T *p;
2951 3071
2952 has_width = 0;
2953 width = 0; 3072 width = 0;
2954 if (dp->width_start != dp->width_end) 3073 if (dp->width_start != dp->width_end)
2955 { 3074 {
@@ -2960,15 +3079,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2960 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 3079 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2961 abort (); 3080 abort ();
2962 arg = a.arg[dp->width_arg_index].a.a_int; 3081 arg = a.arg[dp->width_arg_index].a.a_int;
3082 width = arg;
2963 if (arg < 0) 3083 if (arg < 0)
2964 { 3084 {
2965 /* "A negative field width is taken as a '-' flag 3085 /* "A negative field width is taken as a '-' flag
2966 followed by a positive field width." */ 3086 followed by a positive field width." */
2967 flags |= FLAG_LEFT; 3087 flags |= FLAG_LEFT;
2968 width = (unsigned int) (-arg); 3088 width = -width;
2969 } 3089 }
2970 else
2971 width = arg;
2972 } 3090 }
2973 else 3091 else
2974 { 3092 {
@@ -2978,7 +3096,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2978 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3096 width = xsum (xtimes (width, 10), *digitp++ - '0');
2979 while (digitp != dp->width_end); 3097 while (digitp != dp->width_end);
2980 } 3098 }
2981 has_width = 1;
2982 } 3099 }
2983 3100
2984 has_precision = 0; 3101 has_precision = 0;
@@ -3354,11 +3471,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3354 abort (); 3471 abort ();
3355# endif 3472# endif
3356 } 3473 }
3474
3357 /* The generated string now extends from tmp to p, with the 3475 /* The generated string now extends from tmp to p, with the
3358 zero padding insertion point being at pad_ptr. */ 3476 zero padding insertion point being at pad_ptr. */
3359 if (has_width && p - tmp < width) 3477 count = p - tmp;
3478
3479 if (count < width)
3360 { 3480 {
3361 size_t pad = width - (p - tmp); 3481 size_t pad = width - count;
3362 DCHAR_T *end = p + pad; 3482 DCHAR_T *end = p + pad;
3363 3483
3364 if (flags & FLAG_LEFT) 3484 if (flags & FLAG_LEFT)
@@ -3391,28 +3511,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3391 p = end; 3511 p = end;
3392 } 3512 }
3393 3513
3394 { 3514 count = p - tmp;
3395 size_t count = p - tmp;
3396 3515
3397 if (count >= tmp_length) 3516 if (count >= tmp_length)
3398 /* tmp_length was incorrectly calculated - fix the 3517 /* tmp_length was incorrectly calculated - fix the
3399 code above! */ 3518 code above! */
3400 abort (); 3519 abort ();
3401 3520
3402 /* Make room for the result. */ 3521 /* Make room for the result. */
3403 if (count >= allocated - length) 3522 if (count >= allocated - length)
3404 { 3523 {
3405 size_t n = xsum (length, count); 3524 size_t n = xsum (length, count);
3406 3525
3407 ENSURE_ALLOCATION (n); 3526 ENSURE_ALLOCATION (n);
3408 } 3527 }
3409 3528
3410 /* Append the result. */ 3529 /* Append the result. */
3411 memcpy (result + length, tmp, count * sizeof (DCHAR_T)); 3530 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
3412 if (tmp != tmpbuf) 3531 if (tmp != tmpbuf)
3413 free (tmp); 3532 free (tmp);
3414 length += count; 3533 length += count;
3415 }
3416 } 3534 }
3417#endif 3535#endif
3418#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 3536#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
@@ -3446,8 +3564,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3446 arg_type type = a.arg[dp->arg_index].type; 3564 arg_type type = a.arg[dp->arg_index].type;
3447# endif 3565# endif
3448 int flags = dp->flags; 3566 int flags = dp->flags;
3449 int has_width;
3450 size_t width; 3567 size_t width;
3568 size_t count;
3451 int has_precision; 3569 int has_precision;
3452 size_t precision; 3570 size_t precision;
3453 size_t tmp_length; 3571 size_t tmp_length;
@@ -3456,7 +3574,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3456 DCHAR_T *pad_ptr; 3574 DCHAR_T *pad_ptr;
3457 DCHAR_T *p; 3575 DCHAR_T *p;
3458 3576
3459 has_width = 0;
3460 width = 0; 3577 width = 0;
3461 if (dp->width_start != dp->width_end) 3578 if (dp->width_start != dp->width_end)
3462 { 3579 {
@@ -3467,15 +3584,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3467 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 3584 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3468 abort (); 3585 abort ();
3469 arg = a.arg[dp->width_arg_index].a.a_int; 3586 arg = a.arg[dp->width_arg_index].a.a_int;
3587 width = arg;
3470 if (arg < 0) 3588 if (arg < 0)
3471 { 3589 {
3472 /* "A negative field width is taken as a '-' flag 3590 /* "A negative field width is taken as a '-' flag
3473 followed by a positive field width." */ 3591 followed by a positive field width." */
3474 flags |= FLAG_LEFT; 3592 flags |= FLAG_LEFT;
3475 width = (unsigned int) (-arg); 3593 width = -width;
3476 } 3594 }
3477 else
3478 width = arg;
3479 } 3595 }
3480 else 3596 else
3481 { 3597 {
@@ -3485,7 +3601,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3485 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3601 width = xsum (xtimes (width, 10), *digitp++ - '0');
3486 while (digitp != dp->width_end); 3602 while (digitp != dp->width_end);
3487 } 3603 }
3488 has_width = 1;
3489 } 3604 }
3490 3605
3491 has_precision = 0; 3606 has_precision = 0;
@@ -3925,9 +4040,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3925 digits without trailing zeroes. */ 4040 digits without trailing zeroes. */
3926 if (exponent >= 0) 4041 if (exponent >= 0)
3927 { 4042 {
3928 size_t count = exponent + 1; 4043 size_t ecount = exponent + 1;
3929 /* Note: count <= precision = ndigits. */ 4044 /* Note: count <= precision = ndigits. */
3930 for (; count > 0; count--) 4045 for (; ecount > 0; ecount--)
3931 *p++ = digits[--ndigits]; 4046 *p++ = digits[--ndigits];
3932 if ((flags & FLAG_ALT) || ndigits > nzeroes) 4047 if ((flags & FLAG_ALT) || ndigits > nzeroes)
3933 { 4048 {
@@ -3941,10 +4056,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3941 } 4056 }
3942 else 4057 else
3943 { 4058 {
3944 size_t count = -exponent - 1; 4059 size_t ecount = -exponent - 1;
3945 *p++ = '0'; 4060 *p++ = '0';
3946 *p++ = decimal_point_char (); 4061 *p++ = decimal_point_char ();
3947 for (; count > 0; count--) 4062 for (; ecount > 0; ecount--)
3948 *p++ = '0'; 4063 *p++ = '0';
3949 while (ndigits > nzeroes) 4064 while (ndigits > nzeroes)
3950 { 4065 {
@@ -4249,7 +4364,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4249 static const wchar_t decimal_format[] = 4364 static const wchar_t decimal_format[] =
4250 /* Produce the same number of exponent digits 4365 /* Produce the same number of exponent digits
4251 as the native printf implementation. */ 4366 as the native printf implementation. */
4252# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4367# if defined _WIN32 && ! defined __CYGWIN__
4253 { '%', '+', '.', '3', 'd', '\0' }; 4368 { '%', '+', '.', '3', 'd', '\0' };
4254# else 4369# else
4255 { '%', '+', '.', '2', 'd', '\0' }; 4370 { '%', '+', '.', '2', 'd', '\0' };
@@ -4263,7 +4378,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4263 static const char decimal_format[] = 4378 static const char decimal_format[] =
4264 /* Produce the same number of exponent digits 4379 /* Produce the same number of exponent digits
4265 as the native printf implementation. */ 4380 as the native printf implementation. */
4266# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4381# if defined _WIN32 && ! defined __CYGWIN__
4267 "%+.3d"; 4382 "%+.3d";
4268# else 4383# else
4269 "%+.2d"; 4384 "%+.2d";
@@ -4395,9 +4510,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4395 digits without trailing zeroes. */ 4510 digits without trailing zeroes. */
4396 if (exponent >= 0) 4511 if (exponent >= 0)
4397 { 4512 {
4398 size_t count = exponent + 1; 4513 size_t ecount = exponent + 1;
4399 /* Note: count <= precision = ndigits. */ 4514 /* Note: ecount <= precision = ndigits. */
4400 for (; count > 0; count--) 4515 for (; ecount > 0; ecount--)
4401 *p++ = digits[--ndigits]; 4516 *p++ = digits[--ndigits];
4402 if ((flags & FLAG_ALT) || ndigits > nzeroes) 4517 if ((flags & FLAG_ALT) || ndigits > nzeroes)
4403 { 4518 {
@@ -4411,10 +4526,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4411 } 4526 }
4412 else 4527 else
4413 { 4528 {
4414 size_t count = -exponent - 1; 4529 size_t ecount = -exponent - 1;
4415 *p++ = '0'; 4530 *p++ = '0';
4416 *p++ = decimal_point_char (); 4531 *p++ = decimal_point_char ();
4417 for (; count > 0; count--) 4532 for (; ecount > 0; ecount--)
4418 *p++ = '0'; 4533 *p++ = '0';
4419 while (ndigits > nzeroes) 4534 while (ndigits > nzeroes)
4420 { 4535 {
@@ -4442,7 +4557,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4442 static const wchar_t decimal_format[] = 4557 static const wchar_t decimal_format[] =
4443 /* Produce the same number of exponent digits 4558 /* Produce the same number of exponent digits
4444 as the native printf implementation. */ 4559 as the native printf implementation. */
4445# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4560# if defined _WIN32 && ! defined __CYGWIN__
4446 { '%', '+', '.', '3', 'd', '\0' }; 4561 { '%', '+', '.', '3', 'd', '\0' };
4447# else 4562# else
4448 { '%', '+', '.', '2', 'd', '\0' }; 4563 { '%', '+', '.', '2', 'd', '\0' };
@@ -4456,7 +4571,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4456 static const char decimal_format[] = 4571 static const char decimal_format[] =
4457 /* Produce the same number of exponent digits 4572 /* Produce the same number of exponent digits
4458 as the native printf implementation. */ 4573 as the native printf implementation. */
4459# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4574# if defined _WIN32 && ! defined __CYGWIN__
4460 "%+.3d"; 4575 "%+.3d";
4461# else 4576# else
4462 "%+.2d"; 4577 "%+.2d";
@@ -4514,7 +4629,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4514 *p++ = '+'; 4629 *p++ = '+';
4515 /* Produce the same number of exponent digits as 4630 /* Produce the same number of exponent digits as
4516 the native printf implementation. */ 4631 the native printf implementation. */
4517# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4632# if defined _WIN32 && ! defined __CYGWIN__
4518 *p++ = '0'; 4633 *p++ = '0';
4519# endif 4634# endif
4520 *p++ = '0'; 4635 *p++ = '0';
@@ -4542,9 +4657,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4542 4657
4543 /* The generated string now extends from tmp to p, with the 4658 /* The generated string now extends from tmp to p, with the
4544 zero padding insertion point being at pad_ptr. */ 4659 zero padding insertion point being at pad_ptr. */
4545 if (has_width && p - tmp < width) 4660 count = p - tmp;
4661
4662 if (count < width)
4546 { 4663 {
4547 size_t pad = width - (p - tmp); 4664 size_t pad = width - count;
4548 DCHAR_T *end = p + pad; 4665 DCHAR_T *end = p + pad;
4549 4666
4550 if (flags & FLAG_LEFT) 4667 if (flags & FLAG_LEFT)
@@ -4577,39 +4694,39 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4577 p = end; 4694 p = end;
4578 } 4695 }
4579 4696
4580 { 4697 count = p - tmp;
4581 size_t count = p - tmp;
4582 4698
4583 if (count >= tmp_length) 4699 if (count >= tmp_length)
4584 /* tmp_length was incorrectly calculated - fix the 4700 /* tmp_length was incorrectly calculated - fix the
4585 code above! */ 4701 code above! */
4586 abort (); 4702 abort ();
4587 4703
4588 /* Make room for the result. */ 4704 /* Make room for the result. */
4589 if (count >= allocated - length) 4705 if (count >= allocated - length)
4590 { 4706 {
4591 size_t n = xsum (length, count); 4707 size_t n = xsum (length, count);
4592 4708
4593 ENSURE_ALLOCATION (n); 4709 ENSURE_ALLOCATION (n);
4594 } 4710 }
4595 4711
4596 /* Append the result. */ 4712 /* Append the result. */
4597 memcpy (result + length, tmp, count * sizeof (DCHAR_T)); 4713 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
4598 if (tmp != tmpbuf) 4714 if (tmp != tmpbuf)
4599 free (tmp); 4715 free (tmp);
4600 length += count; 4716 length += count;
4601 }
4602 } 4717 }
4603#endif 4718#endif
4604 else 4719 else
4605 { 4720 {
4606 arg_type type = a.arg[dp->arg_index].type; 4721 arg_type type = a.arg[dp->arg_index].type;
4607 int flags = dp->flags; 4722 int flags = dp->flags;
4608#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 4723#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4609 int has_width; 4724 int has_width;
4725#endif
4726#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
4610 size_t width; 4727 size_t width;
4611#endif 4728#endif
4612#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION 4729#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
4613 int has_precision; 4730 int has_precision;
4614 size_t precision; 4731 size_t precision;
4615#endif 4732#endif
@@ -4635,8 +4752,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4635 TCHAR_T *tmp; 4752 TCHAR_T *tmp;
4636#endif 4753#endif
4637 4754
4638#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION 4755#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4639 has_width = 0; 4756 has_width = 0;
4757#endif
4758#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
4640 width = 0; 4759 width = 0;
4641 if (dp->width_start != dp->width_end) 4760 if (dp->width_start != dp->width_end)
4642 { 4761 {
@@ -4647,15 +4766,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4647 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 4766 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
4648 abort (); 4767 abort ();
4649 arg = a.arg[dp->width_arg_index].a.a_int; 4768 arg = a.arg[dp->width_arg_index].a.a_int;
4769 width = arg;
4650 if (arg < 0) 4770 if (arg < 0)
4651 { 4771 {
4652 /* "A negative field width is taken as a '-' flag 4772 /* "A negative field width is taken as a '-' flag
4653 followed by a positive field width." */ 4773 followed by a positive field width." */
4654 flags |= FLAG_LEFT; 4774 flags |= FLAG_LEFT;
4655 width = (unsigned int) (-arg); 4775 width = -width;
4656 } 4776 }
4657 else
4658 width = arg;
4659 } 4777 }
4660 else 4778 else
4661 { 4779 {
@@ -4665,11 +4783,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4665 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4783 width = xsum (xtimes (width, 10), *digitp++ - '0');
4666 while (digitp != dp->width_end); 4784 while (digitp != dp->width_end);
4667 } 4785 }
4786#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4668 has_width = 1; 4787 has_width = 1;
4788#endif
4669 } 4789 }
4670#endif 4790#endif
4671 4791
4672#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION 4792#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
4673 has_precision = 0; 4793 has_precision = 0;
4674 precision = 6; 4794 precision = 6;
4675 if (dp->precision_start != dp->precision_end) 4795 if (dp->precision_start != dp->precision_end)
@@ -4805,7 +4925,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4805 { 4925 {
4806 const FCHAR_T *mp = dp->width_start; 4926 const FCHAR_T *mp = dp->width_start;
4807 do 4927 do
4808 *fbp++ = (unsigned char) *mp++; 4928 *fbp++ = *mp++;
4809 while (--n > 0); 4929 while (--n > 0);
4810 } 4930 }
4811 } 4931 }
@@ -4826,7 +4946,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4826 { 4946 {
4827 const FCHAR_T *mp = dp->precision_start; 4947 const FCHAR_T *mp = dp->precision_start;
4828 do 4948 do
4829 *fbp++ = (unsigned char) *mp++; 4949 *fbp++ = *mp++;
4830 while (--n > 0); 4950 while (--n > 0);
4831 } 4951 }
4832 } 4952 }
@@ -4834,19 +4954,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4834 4954
4835 switch (type) 4955 switch (type)
4836 { 4956 {
4837#if HAVE_LONG_LONG_INT
4838 case TYPE_LONGLONGINT: 4957 case TYPE_LONGLONGINT:
4839 case TYPE_ULONGLONGINT: 4958 case TYPE_ULONGLONGINT:
4840# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4959#if defined _WIN32 && ! defined __CYGWIN__
4841 *fbp++ = 'I'; 4960 *fbp++ = 'I';
4842 *fbp++ = '6'; 4961 *fbp++ = '6';
4843 *fbp++ = '4'; 4962 *fbp++ = '4';
4844 break; 4963 break;
4845# else 4964#else
4846 *fbp++ = 'l'; 4965 *fbp++ = 'l';
4847 /*FALLTHROUGH*/
4848# endif
4849#endif 4966#endif
4967 FALLTHROUGH;
4850 case TYPE_LONGINT: 4968 case TYPE_LONGINT:
4851 case TYPE_ULONGINT: 4969 case TYPE_ULONGINT:
4852#if HAVE_WINT_T 4970#if HAVE_WINT_T
@@ -4870,20 +4988,32 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4870#endif 4988#endif
4871 *fbp = dp->conversion; 4989 *fbp = dp->conversion;
4872#if USE_SNPRINTF 4990#if USE_SNPRINTF
4873# if !(((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined __UCLIBC__) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)) 4991# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \
4874 fbp[1] = '%'; 4992 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
4875 fbp[2] = 'n'; 4993 && !defined __UCLIBC__) \
4876 fbp[3] = '\0'; 4994 || (defined __APPLE__ && defined __MACH__) \
4877# else 4995 || defined __ANDROID__ \
4878 /* On glibc2 systems from glibc >= 2.3 - probably also older 4996 || (defined _WIN32 && ! defined __CYGWIN__))
4879 ones - we know that snprintf's return value conforms to 4997 /* On systems where we know that snprintf's return value
4880 ISO C 99: the tests gl_SNPRINTF_RETVAL_C99 and 4998 conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that
4881 gl_SNPRINTF_TRUNCATION_C99 pass. 4999 snprintf always produces NUL-terminated strings
4882 Therefore we can avoid using %n in this situation. 5000 (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid
4883 On glibc2 systems from 2004-10-18 or newer, the use of %n 5001 using %n. And it is desirable to do so, because more and
4884 in format strings in writable memory may crash the program 5002 more platforms no longer support %n, for "security reasons".
4885 (if compiled with _FORTIFY_SOURCE=2), so we should avoid it 5003 In particular, the following platforms:
4886 in this situation. */ 5004 - On glibc2 systems from 2004-10-18 or newer, the use of
5005 %n in format strings in writable memory may crash the
5006 program (if compiled with _FORTIFY_SOURCE=2).
5007 - On Mac OS X 10.13 or newer, the use of %n in format
5008 strings in writable memory by default crashes the
5009 program.
5010 - On Android, starting on 2018-03-07, the use of %n in
5011 format strings produces a fatal error (see
5012 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
5013 On these platforms, HAVE_SNPRINTF_RETVAL_C99 and
5014 HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them
5015 explicitly in the condition above, in case of cross-
5016 compilation (just to be sure). */
4887 /* On native Windows systems (such as mingw), we can avoid using 5017 /* On native Windows systems (such as mingw), we can avoid using
4888 %n because: 5018 %n because:
4889 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, 5019 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
@@ -4896,10 +5026,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4896 On native Windows systems (such as mingw) where the OS is 5026 On native Windows systems (such as mingw) where the OS is
4897 Windows Vista, the use of %n in format strings by default 5027 Windows Vista, the use of %n in format strings by default
4898 crashes the program. See 5028 crashes the program. See
4899 <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and 5029 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
4900 <http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx> 5030 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
4901 So we should avoid %n in this situation. */ 5031 So we should avoid %n in this situation. */
4902 fbp[1] = '\0'; 5032 fbp[1] = '\0';
5033# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
5034 fbp[1] = '%';
5035 fbp[2] = 'n';
5036 fbp[3] = '\0';
4903# endif 5037# endif
4904#else 5038#else
4905 fbp[1] = '\0'; 5039 fbp[1] = '\0';
@@ -5043,7 +5177,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5043 SNPRINTF_BUF (arg); 5177 SNPRINTF_BUF (arg);
5044 } 5178 }
5045 break; 5179 break;
5046#if HAVE_LONG_LONG_INT
5047 case TYPE_LONGLONGINT: 5180 case TYPE_LONGLONGINT:
5048 { 5181 {
5049 long long int arg = a.arg[dp->arg_index].a.a_longlongint; 5182 long long int arg = a.arg[dp->arg_index].a.a_longlongint;
@@ -5056,7 +5189,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5056 SNPRINTF_BUF (arg); 5189 SNPRINTF_BUF (arg);
5057 } 5190 }
5058 break; 5191 break;
5059#endif
5060 case TYPE_DOUBLE: 5192 case TYPE_DOUBLE:
5061 { 5193 {
5062 double arg = a.arg[dp->arg_index].a.a_double; 5194 double arg = a.arg[dp->arg_index].a.a_double;
@@ -5116,7 +5248,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5116 { 5248 {
5117 /* Verify that snprintf() has NUL-terminated its 5249 /* Verify that snprintf() has NUL-terminated its
5118 result. */ 5250 result. */
5119 if (count < maxlen 5251 if ((unsigned int) count < maxlen
5120 && ((TCHAR_T *) (result + length)) [count] != '\0') 5252 && ((TCHAR_T *) (result + length)) [count] != '\0')
5121 abort (); 5253 abort ();
5122 /* Portability hack. */ 5254 /* Portability hack. */
@@ -5139,7 +5271,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5139 /* Look at the snprintf() return value. */ 5271 /* Look at the snprintf() return value. */
5140 if (retcount < 0) 5272 if (retcount < 0)
5141 { 5273 {
5142# if !HAVE_SNPRINTF_RETVAL_C99 5274# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
5143 /* HP-UX 10.20 snprintf() is doubly deficient: 5275 /* HP-UX 10.20 snprintf() is doubly deficient:
5144 It doesn't understand the '%n' directive, 5276 It doesn't understand the '%n' directive,
5145 *and* it returns -1 (rather than the length 5277 *and* it returns -1 (rather than the length
@@ -5153,7 +5285,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5153 size_t tmp_length = 5285 size_t tmp_length =
5154 MAX_ROOM_NEEDED (&a, dp->arg_index, 5286 MAX_ROOM_NEEDED (&a, dp->arg_index,
5155 dp->conversion, type, flags, 5287 dp->conversion, type, flags,
5156 has_width ? width : 0, 5288 width,
5157 has_precision, 5289 has_precision,
5158 precision, pad_ourselves); 5290 precision, pad_ourselves);
5159 5291
@@ -5188,22 +5320,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5188 /* Attempt to handle failure. */ 5320 /* Attempt to handle failure. */
5189 if (count < 0) 5321 if (count < 0)
5190 { 5322 {
5191 /* SNPRINTF or sprintf failed. Save and use the errno 5323 /* SNPRINTF or sprintf failed. Use the errno that it
5192 that it has set, if any. */ 5324 has set, if any. */
5193 int saved_errno = errno; 5325 if (errno == 0)
5194 5326 {
5195 if (!(result == resultbuf || result == NULL)) 5327 if (dp->conversion == 'c' || dp->conversion == 's')
5196 free (result); 5328 errno = EILSEQ;
5197 if (buf_malloced != NULL) 5329 else
5198 free (buf_malloced); 5330 errno = EINVAL;
5199 CLEANUP (); 5331 }
5200 errno = 5332
5201 (saved_errno != 0 5333 goto fail_with_errno;
5202 ? saved_errno
5203 : (dp->conversion == 'c' || dp->conversion == 's'
5204 ? EILSEQ
5205 : EINVAL));
5206 return NULL;
5207 } 5334 }
5208 5335
5209#if USE_SNPRINTF 5336#if USE_SNPRINTF
@@ -5337,17 +5464,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5337 NULL, 5464 NULL,
5338 NULL, &tmpdst_len); 5465 NULL, &tmpdst_len);
5339 if (tmpdst == NULL) 5466 if (tmpdst == NULL)
5340 { 5467 goto fail_with_errno;
5341 int saved_errno = errno; 5468 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
5342 if (!(result == resultbuf || result == NULL)) 5469 { free (tmpdst); goto out_of_memory; });
5343 free (result);
5344 if (buf_malloced != NULL)
5345 free (buf_malloced);
5346 CLEANUP ();
5347 errno = saved_errno;
5348 return NULL;
5349 }
5350 ENSURE_ALLOCATION (xsum (length, tmpdst_len));
5351 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 5470 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
5352 free (tmpdst); 5471 free (tmpdst);
5353 count = tmpdst_len; 5472 count = tmpdst_len;
@@ -5391,7 +5510,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5391 tmpsrc += count; 5510 tmpsrc += count;
5392 tmpdst += count; 5511 tmpdst += count;
5393 for (n = count; n > 0; n--) 5512 for (n = count; n > 0; n--)
5394 *--tmpdst = (unsigned char) *--tmpsrc; 5513 *--tmpdst = *--tmpsrc;
5395 } 5514 }
5396 } 5515 }
5397#endif 5516#endif
@@ -5570,25 +5689,40 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5570 5689
5571#if USE_SNPRINTF 5690#if USE_SNPRINTF
5572 overflow: 5691 overflow:
5573 if (!(result == resultbuf || result == NULL))
5574 free (result);
5575 if (buf_malloced != NULL)
5576 free (buf_malloced);
5577 CLEANUP ();
5578 errno = EOVERFLOW; 5692 errno = EOVERFLOW;
5579 return NULL; 5693 goto fail_with_errno;
5580#endif 5694#endif
5581 5695
5582 out_of_memory: 5696 out_of_memory:
5583 if (!(result == resultbuf || result == NULL)) 5697 errno = ENOMEM;
5698 goto fail_with_errno;
5699
5700#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)
5701 fail_with_EILSEQ:
5702 errno = EILSEQ;
5703 goto fail_with_errno;
5704#endif
5705
5706 fail_with_errno:
5707 if (result != resultbuf)
5584 free (result); 5708 free (result);
5585 if (buf_malloced != NULL) 5709 if (buf_malloced != NULL)
5586 free (buf_malloced); 5710 free (buf_malloced);
5587 out_of_memory_1:
5588 CLEANUP (); 5711 CLEANUP ();
5589 errno = ENOMEM;
5590 return NULL; 5712 return NULL;
5591 } 5713 }
5714
5715 out_of_memory_1:
5716 errno = ENOMEM;
5717 goto fail_1_with_errno;
5718
5719 fail_1_with_EINVAL:
5720 errno = EINVAL;
5721 goto fail_1_with_errno;
5722
5723 fail_1_with_errno:
5724 CLEANUP ();
5725 return NULL;
5592} 5726}
5593 5727
5594#undef MAX_ROOM_NEEDED 5728#undef MAX_ROOM_NEEDED