summaryrefslogtreecommitdiffstats
path: root/gl/vasnprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'gl/vasnprintf.c')
-rw-r--r--gl/vasnprintf.c699
1 files changed, 482 insertions, 217 deletions
diff --git a/gl/vasnprintf.c b/gl/vasnprintf.c
index 5267b1b..d9b669d 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-2021 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
@@ -849,7 +935,9 @@ convert_to_decimal (mpn_t a, size_t extra_zeroes)
849 size_t a_len = a.nlimbs; 935 size_t a_len = a.nlimbs;
850 /* 0.03345 is slightly larger than log(2)/(9*log(10)). */ 936 /* 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); 937 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)); 938 /* We need extra_zeroes bytes for zeroes, followed by c_len bytes for the
939 digits of a, followed by 1 byte for the terminating NUL. */
940 char *c_ptr = (char *) malloc (xsum (xsum (extra_zeroes, c_len), 1));
853 if (c_ptr != NULL) 941 if (c_ptr != NULL)
854 { 942 {
855 char *d_ptr = c_ptr; 943 char *d_ptr = c_ptr;
@@ -1517,7 +1605,7 @@ is_borderline (const char *digits, size_t precision)
1517 1605
1518#endif 1606#endif
1519 1607
1520#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 1608#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
1521 1609
1522/* Use a different function name, to make it possible that the 'wchar_t' 1610/* Use a different function name, to make it possible that the 'wchar_t'
1523 parametrization and the 'char' parametrization get compiled in the same 1611 parametrization and the 'char' parametrization get compiled in the same
@@ -1540,16 +1628,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1540 switch (conversion) 1628 switch (conversion)
1541 { 1629 {
1542 case 'd': case 'i': case 'u': 1630 case 'd': case 'i': case 'u':
1543# if HAVE_LONG_LONG_INT
1544 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1631 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1545 tmp_length = 1632 tmp_length =
1546 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1633 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1547 * 0.30103 /* binary -> decimal */ 1634 * 0.30103 /* binary -> decimal */
1548 ) 1635 )
1549 + 1; /* turn floor into ceil */ 1636 + 1; /* turn floor into ceil */
1550 else 1637 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1551# endif
1552 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1553 tmp_length = 1638 tmp_length =
1554 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1639 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1555 * 0.30103 /* binary -> decimal */ 1640 * 0.30103 /* binary -> decimal */
@@ -1570,16 +1655,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1570 break; 1655 break;
1571 1656
1572 case 'o': 1657 case 'o':
1573# if HAVE_LONG_LONG_INT
1574 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1658 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1575 tmp_length = 1659 tmp_length =
1576 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1660 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1577 * 0.333334 /* binary -> octal */ 1661 * 0.333334 /* binary -> octal */
1578 ) 1662 )
1579 + 1; /* turn floor into ceil */ 1663 + 1; /* turn floor into ceil */
1580 else 1664 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1581# endif
1582 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1583 tmp_length = 1665 tmp_length =
1584 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1666 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1585 * 0.333334 /* binary -> octal */ 1667 * 0.333334 /* binary -> octal */
@@ -1598,16 +1680,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1598 break; 1680 break;
1599 1681
1600 case 'x': case 'X': 1682 case 'x': case 'X':
1601# if HAVE_LONG_LONG_INT
1602 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT) 1683 if (type == TYPE_LONGLONGINT || type == TYPE_ULONGLONGINT)
1603 tmp_length = 1684 tmp_length =
1604 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT 1685 (unsigned int) (sizeof (unsigned long long) * CHAR_BIT
1605 * 0.25 /* binary -> hexadecimal */ 1686 * 0.25 /* binary -> hexadecimal */
1606 ) 1687 )
1607 + 1; /* turn floor into ceil */ 1688 + 1; /* turn floor into ceil */
1608 else 1689 else if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1609# endif
1610 if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
1611 tmp_length = 1690 tmp_length =
1612 (unsigned int) (sizeof (unsigned long) * CHAR_BIT 1691 (unsigned int) (sizeof (unsigned long) * CHAR_BIT
1613 * 0.25 /* binary -> hexadecimal */ 1692 * 0.25 /* binary -> hexadecimal */
@@ -1673,7 +1752,13 @@ MAX_ROOM_NEEDED (const arguments *ap, size_t arg_index, FCHAR_T conversion,
1673 case 'c': 1752 case 'c':
1674# if HAVE_WINT_T && !WIDE_CHAR_VERSION 1753# if HAVE_WINT_T && !WIDE_CHAR_VERSION
1675 if (type == TYPE_WIDE_CHAR) 1754 if (type == TYPE_WIDE_CHAR)
1676 tmp_length = MB_CUR_MAX; 1755 {
1756 tmp_length = MB_CUR_MAX;
1757# if ENABLE_WCHAR_FALLBACK
1758 if (tmp_length < (sizeof (wchar_t) > 2 ? 10 : 6))
1759 tmp_length = (sizeof (wchar_t) > 2 ? 10 : 6);
1760# endif
1761 }
1677 else 1762 else
1678# endif 1763# endif
1679 tmp_length = 1; 1764 tmp_length = 1;
@@ -1780,6 +1865,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1780 /* errno is already set. */ 1865 /* errno is already set. */
1781 return NULL; 1866 return NULL;
1782 1867
1868 /* Frees the memory allocated by this function. Preserves errno. */
1783#define CLEANUP() \ 1869#define CLEANUP() \
1784 if (d.dir != d.direct_alloc_dir) \ 1870 if (d.dir != d.direct_alloc_dir) \
1785 free (d.dir); \ 1871 free (d.dir); \
@@ -1844,7 +1930,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1844 1930
1845 /* Ensures that allocated >= needed. Aborts through a jump to 1931 /* Ensures that allocated >= needed. Aborts through a jump to
1846 out_of_memory if needed is SIZE_MAX or otherwise too big. */ 1932 out_of_memory if needed is SIZE_MAX or otherwise too big. */
1847#define ENSURE_ALLOCATION(needed) \ 1933#define ENSURE_ALLOCATION_ELSE(needed, oom_statement) \
1848 if ((needed) > allocated) \ 1934 if ((needed) > allocated) \
1849 { \ 1935 { \
1850 size_t memory_size; \ 1936 size_t memory_size; \
@@ -1855,17 +1941,19 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1855 allocated = (needed); \ 1941 allocated = (needed); \
1856 memory_size = xtimes (allocated, sizeof (DCHAR_T)); \ 1942 memory_size = xtimes (allocated, sizeof (DCHAR_T)); \
1857 if (size_overflow_p (memory_size)) \ 1943 if (size_overflow_p (memory_size)) \
1858 goto out_of_memory; \ 1944 oom_statement \
1859 if (result == resultbuf || result == NULL) \ 1945 if (result == resultbuf || result == NULL) \
1860 memory = (DCHAR_T *) malloc (memory_size); \ 1946 memory = (DCHAR_T *) malloc (memory_size); \
1861 else \ 1947 else \
1862 memory = (DCHAR_T *) realloc (result, memory_size); \ 1948 memory = (DCHAR_T *) realloc (result, memory_size); \
1863 if (memory == NULL) \ 1949 if (memory == NULL) \
1864 goto out_of_memory; \ 1950 oom_statement \
1865 if (result == resultbuf && length > 0) \ 1951 if (result == resultbuf && length > 0) \
1866 DCHAR_CPY (memory, result, length); \ 1952 DCHAR_CPY (memory, result, length); \
1867 result = memory; \ 1953 result = memory; \
1868 } 1954 }
1955#define ENSURE_ALLOCATION(needed) \
1956 ENSURE_ALLOCATION_ELSE((needed), goto out_of_memory; )
1869 1957
1870 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++) 1958 for (cp = format, i = 0, dp = &d.dir[0]; ; cp = dp->dir_end, i++, dp++)
1871 { 1959 {
@@ -1886,7 +1974,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1886 else 1974 else
1887 { 1975 {
1888 do 1976 do
1889 result[length++] = (unsigned char) *cp++; 1977 result[length++] = *cp++;
1890 while (--n > 0); 1978 while (--n > 0);
1891 } 1979 }
1892 } 1980 }
@@ -1926,11 +2014,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1926 case TYPE_COUNT_LONGINT_POINTER: 2014 case TYPE_COUNT_LONGINT_POINTER:
1927 *a.arg[dp->arg_index].a.a_count_longint_pointer = length; 2015 *a.arg[dp->arg_index].a.a_count_longint_pointer = length;
1928 break; 2016 break;
1929#if HAVE_LONG_LONG_INT
1930 case TYPE_COUNT_LONGLONGINT_POINTER: 2017 case TYPE_COUNT_LONGLONGINT_POINTER:
1931 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length; 2018 *a.arg[dp->arg_index].a.a_count_longlongint_pointer = length;
1932 break; 2019 break;
1933#endif
1934 default: 2020 default:
1935 abort (); 2021 abort ();
1936 } 2022 }
@@ -1957,15 +2043,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
1957 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 2043 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
1958 abort (); 2044 abort ();
1959 arg = a.arg[dp->width_arg_index].a.a_int; 2045 arg = a.arg[dp->width_arg_index].a.a_int;
2046 width = arg;
1960 if (arg < 0) 2047 if (arg < 0)
1961 { 2048 {
1962 /* "A negative field width is taken as a '-' flag 2049 /* "A negative field width is taken as a '-' flag
1963 followed by a positive field width." */ 2050 followed by a positive field width." */
1964 flags |= FLAG_LEFT; 2051 flags |= FLAG_LEFT;
1965 width = (unsigned int) (-arg); 2052 width = -width;
1966 } 2053 }
1967 else
1968 width = arg;
1969 } 2054 }
1970 else 2055 else
1971 { 2056 {
@@ -2073,8 +2158,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2073 characters = 0; 2158 characters = 0;
2074 } 2159 }
2075 2160
2076 if (has_width && width > characters 2161 if (characters < width && !(dp->flags & FLAG_LEFT))
2077 && !(dp->flags & FLAG_LEFT))
2078 { 2162 {
2079 size_t n = width - characters; 2163 size_t n = width - characters;
2080 ENSURE_ALLOCATION (xsum (length, n)); 2164 ENSURE_ALLOCATION (xsum (length, n));
@@ -2108,18 +2192,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2108# endif 2192# endif
2109 if (converted == NULL) 2193 if (converted == NULL)
2110 { 2194 {
2111 int saved_errno = errno;
2112 if (!(result == resultbuf || result == NULL)) 2195 if (!(result == resultbuf || result == NULL))
2113 free (result); 2196 free (result);
2114 if (buf_malloced != NULL) 2197 if (buf_malloced != NULL)
2115 free (buf_malloced); 2198 free (buf_malloced);
2116 CLEANUP (); 2199 CLEANUP ();
2117 errno = saved_errno;
2118 return NULL; 2200 return NULL;
2119 } 2201 }
2120 if (converted != result + length) 2202 if (converted != result + length)
2121 { 2203 {
2122 ENSURE_ALLOCATION (xsum (length, converted_len)); 2204 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2205 { free (converted); goto out_of_memory; });
2123 DCHAR_CPY (result + length, converted, converted_len); 2206 DCHAR_CPY (result + length, converted, converted_len);
2124 free (converted); 2207 free (converted);
2125 } 2208 }
@@ -2127,8 +2210,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2127 } 2210 }
2128# endif 2211# endif
2129 2212
2130 if (has_width && width > characters 2213 if (characters < width && (dp->flags & FLAG_LEFT))
2131 && (dp->flags & FLAG_LEFT))
2132 { 2214 {
2133 size_t n = width - characters; 2215 size_t n = width - characters;
2134 ENSURE_ALLOCATION (xsum (length, n)); 2216 ENSURE_ALLOCATION (xsum (length, n));
@@ -2201,8 +2283,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2201 characters = 0; 2283 characters = 0;
2202 } 2284 }
2203 2285
2204 if (has_width && width > characters 2286 if (characters < width && !(dp->flags & FLAG_LEFT))
2205 && !(dp->flags & FLAG_LEFT))
2206 { 2287 {
2207 size_t n = width - characters; 2288 size_t n = width - characters;
2208 ENSURE_ALLOCATION (xsum (length, n)); 2289 ENSURE_ALLOCATION (xsum (length, n));
@@ -2236,18 +2317,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2236# endif 2317# endif
2237 if (converted == NULL) 2318 if (converted == NULL)
2238 { 2319 {
2239 int saved_errno = errno;
2240 if (!(result == resultbuf || result == NULL)) 2320 if (!(result == resultbuf || result == NULL))
2241 free (result); 2321 free (result);
2242 if (buf_malloced != NULL) 2322 if (buf_malloced != NULL)
2243 free (buf_malloced); 2323 free (buf_malloced);
2244 CLEANUP (); 2324 CLEANUP ();
2245 errno = saved_errno;
2246 return NULL; 2325 return NULL;
2247 } 2326 }
2248 if (converted != result + length) 2327 if (converted != result + length)
2249 { 2328 {
2250 ENSURE_ALLOCATION (xsum (length, converted_len)); 2329 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2330 { free (converted); goto out_of_memory; });
2251 DCHAR_CPY (result + length, converted, converted_len); 2331 DCHAR_CPY (result + length, converted, converted_len);
2252 free (converted); 2332 free (converted);
2253 } 2333 }
@@ -2255,8 +2335,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2255 } 2335 }
2256# endif 2336# endif
2257 2337
2258 if (has_width && width > characters 2338 if (characters < width && (dp->flags & FLAG_LEFT))
2259 && (dp->flags & FLAG_LEFT))
2260 { 2339 {
2261 size_t n = width - characters; 2340 size_t n = width - characters;
2262 ENSURE_ALLOCATION (xsum (length, n)); 2341 ENSURE_ALLOCATION (xsum (length, n));
@@ -2329,8 +2408,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2329 characters = 0; 2408 characters = 0;
2330 } 2409 }
2331 2410
2332 if (has_width && width > characters 2411 if (characters < width && !(dp->flags & FLAG_LEFT))
2333 && !(dp->flags & FLAG_LEFT))
2334 { 2412 {
2335 size_t n = width - characters; 2413 size_t n = width - characters;
2336 ENSURE_ALLOCATION (xsum (length, n)); 2414 ENSURE_ALLOCATION (xsum (length, n));
@@ -2364,18 +2442,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2364# endif 2442# endif
2365 if (converted == NULL) 2443 if (converted == NULL)
2366 { 2444 {
2367 int saved_errno = errno;
2368 if (!(result == resultbuf || result == NULL)) 2445 if (!(result == resultbuf || result == NULL))
2369 free (result); 2446 free (result);
2370 if (buf_malloced != NULL) 2447 if (buf_malloced != NULL)
2371 free (buf_malloced); 2448 free (buf_malloced);
2372 CLEANUP (); 2449 CLEANUP ();
2373 errno = saved_errno;
2374 return NULL; 2450 return NULL;
2375 } 2451 }
2376 if (converted != result + length) 2452 if (converted != result + length)
2377 { 2453 {
2378 ENSURE_ALLOCATION (xsum (length, converted_len)); 2454 ENSURE_ALLOCATION_ELSE (xsum (length, converted_len),
2455 { free (converted); goto out_of_memory; });
2379 DCHAR_CPY (result + length, converted, converted_len); 2456 DCHAR_CPY (result + length, converted, converted_len);
2380 free (converted); 2457 free (converted);
2381 } 2458 }
@@ -2383,8 +2460,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2383 } 2460 }
2384# endif 2461# endif
2385 2462
2386 if (has_width && width > characters 2463 if (characters < width && (dp->flags & FLAG_LEFT))
2387 && (dp->flags & FLAG_LEFT))
2388 { 2464 {
2389 size_t n = width - characters; 2465 size_t n = width - characters;
2390 ENSURE_ALLOCATION (xsum (length, n)); 2466 ENSURE_ALLOCATION (xsum (length, n));
@@ -2399,7 +2475,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2399 } 2475 }
2400 } 2476 }
2401#endif 2477#endif
2402#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T 2478#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' 2479 else if (dp->conversion == 's'
2404# if WIDE_CHAR_VERSION 2480# if WIDE_CHAR_VERSION
2405 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING 2481 && a.arg[dp->arg_index].type != TYPE_WIDE_STRING
@@ -2435,15 +2511,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2435 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 2511 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2436 abort (); 2512 abort ();
2437 arg = a.arg[dp->width_arg_index].a.a_int; 2513 arg = a.arg[dp->width_arg_index].a.a_int;
2514 width = arg;
2438 if (arg < 0) 2515 if (arg < 0)
2439 { 2516 {
2440 /* "A negative field width is taken as a '-' flag 2517 /* "A negative field width is taken as a '-' flag
2441 followed by a positive field width." */ 2518 followed by a positive field width." */
2442 flags |= FLAG_LEFT; 2519 flags |= FLAG_LEFT;
2443 width = (unsigned int) (-arg); 2520 width = -width;
2444 } 2521 }
2445 else
2446 width = arg;
2447 } 2522 }
2448 else 2523 else
2449 { 2524 {
@@ -2573,8 +2648,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2573 characters = 0; 2648 characters = 0;
2574 } 2649 }
2575 2650
2576 if (has_width && width > characters 2651 if (characters < width && !(dp->flags & FLAG_LEFT))
2577 && !(dp->flags & FLAG_LEFT))
2578 { 2652 {
2579 size_t n = width - characters; 2653 size_t n = width - characters;
2580 ENSURE_ALLOCATION (xsum (length, n)); 2654 ENSURE_ALLOCATION (xsum (length, n));
@@ -2635,8 +2709,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2635 } 2709 }
2636 } 2710 }
2637 2711
2638 if (has_width && width > characters 2712 if (characters < width && (dp->flags & FLAG_LEFT))
2639 && (dp->flags & FLAG_LEFT))
2640 { 2713 {
2641 size_t n = width - characters; 2714 size_t n = width - characters;
2642 ENSURE_ALLOCATION (xsum (length, n)); 2715 ENSURE_ALLOCATION (xsum (length, n));
@@ -2677,11 +2750,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2677 if (*arg_end == 0) 2750 if (*arg_end == 0)
2678 /* Found the terminating null wide character. */ 2751 /* Found the terminating null wide character. */
2679 break; 2752 break;
2680# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2753 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) 2754 if (count < 0)
2686 { 2755 {
2687 /* Cannot convert. */ 2756 /* Cannot convert. */
@@ -2693,7 +2762,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2693 errno = EILSEQ; 2762 errno = EILSEQ;
2694 return NULL; 2763 return NULL;
2695 } 2764 }
2696 if (precision < count) 2765 if (precision < (unsigned int) count)
2697 break; 2766 break;
2698 arg_end++; 2767 arg_end++;
2699 characters += count; 2768 characters += count;
@@ -2722,11 +2791,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2722 if (*arg_end == 0) 2791 if (*arg_end == 0)
2723 /* Found the terminating null wide character. */ 2792 /* Found the terminating null wide character. */
2724 break; 2793 break;
2725# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2794 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) 2795 if (count < 0)
2731 { 2796 {
2732 /* Cannot convert. */ 2797 /* Cannot convert. */
@@ -2771,11 +2836,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2771 2836
2772 if (*arg == 0) 2837 if (*arg == 0)
2773 abort (); 2838 abort ();
2774# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2839 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) 2840 if (count <= 0)
2780 /* Inconsistency. */ 2841 /* Inconsistency. */
2781 abort (); 2842 abort ();
@@ -2797,14 +2858,12 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2797 NULL, &tmpdst_len); 2858 NULL, &tmpdst_len);
2798 if (tmpdst == NULL) 2859 if (tmpdst == NULL)
2799 { 2860 {
2800 int saved_errno = errno;
2801 free (tmpsrc); 2861 free (tmpsrc);
2802 if (!(result == resultbuf || result == NULL)) 2862 if (!(result == resultbuf || result == NULL))
2803 free (result); 2863 free (result);
2804 if (buf_malloced != NULL) 2864 if (buf_malloced != NULL)
2805 free (buf_malloced); 2865 free (buf_malloced);
2806 CLEANUP (); 2866 CLEANUP ();
2807 errno = saved_errno;
2808 return NULL; 2867 return NULL;
2809 } 2868 }
2810 free (tmpsrc); 2869 free (tmpsrc);
@@ -2827,8 +2886,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2827 /* w doesn't matter. */ 2886 /* w doesn't matter. */
2828 w = 0; 2887 w = 0;
2829 2888
2830 if (has_width && width > w 2889 if (w < width && !(dp->flags & FLAG_LEFT))
2831 && !(dp->flags & FLAG_LEFT))
2832 { 2890 {
2833 size_t n = width - w; 2891 size_t n = width - w;
2834 ENSURE_ALLOCATION (xsum (length, n)); 2892 ENSURE_ALLOCATION (xsum (length, n));
@@ -2853,11 +2911,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2853 2911
2854 if (*arg == 0) 2912 if (*arg == 0)
2855 abort (); 2913 abort ();
2856# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2914 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) 2915 if (count <= 0)
2862 /* Inconsistency. */ 2916 /* Inconsistency. */
2863 abort (); 2917 abort ();
@@ -2882,11 +2936,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2882 2936
2883 if (*arg == 0) 2937 if (*arg == 0)
2884 abort (); 2938 abort ();
2885# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t 2939 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) 2940 if (count <= 0)
2891 { 2941 {
2892 /* Cannot convert. */ 2942 /* Cannot convert. */
@@ -2905,14 +2955,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2905 } 2955 }
2906 } 2956 }
2907# else 2957# else
2908 ENSURE_ALLOCATION (xsum (length, tmpdst_len)); 2958 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
2959 { free (tmpdst); goto out_of_memory; });
2909 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 2960 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
2910 free (tmpdst); 2961 free (tmpdst);
2911 length += tmpdst_len; 2962 length += tmpdst_len;
2912# endif 2963# endif
2913 2964
2914 if (has_width && width > w 2965 if (w < width && (dp->flags & FLAG_LEFT))
2915 && (dp->flags & FLAG_LEFT))
2916 { 2966 {
2917 size_t n = width - w; 2967 size_t n = width - w;
2918 ENSURE_ALLOCATION (xsum (length, n)); 2968 ENSURE_ALLOCATION (xsum (length, n));
@@ -2923,6 +2973,209 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2923# endif 2973# endif
2924 } 2974 }
2925#endif 2975#endif
2976#if ENABLE_WCHAR_FALLBACK && HAVE_WINT_T && !WIDE_CHAR_VERSION
2977 else if (dp->conversion == 'c'
2978 && a.arg[dp->arg_index].type == TYPE_WIDE_CHAR)
2979 {
2980 /* Implement the 'lc' directive ourselves, in order to provide
2981 the fallback that avoids EILSEQ. */
2982 int flags = dp->flags;
2983 int has_width;
2984 size_t width;
2985
2986 has_width = 0;
2987 width = 0;
2988 if (dp->width_start != dp->width_end)
2989 {
2990 if (dp->width_arg_index != ARG_NONE)
2991 {
2992 int arg;
2993
2994 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2995 abort ();
2996 arg = a.arg[dp->width_arg_index].a.a_int;
2997 width = arg;
2998 if (arg < 0)
2999 {
3000 /* "A negative field width is taken as a '-' flag
3001 followed by a positive field width." */
3002 flags |= FLAG_LEFT;
3003 width = -width;
3004 }
3005 }
3006 else
3007 {
3008 const FCHAR_T *digitp = dp->width_start;
3009
3010 do
3011 width = xsum (xtimes (width, 10), *digitp++ - '0');
3012 while (digitp != dp->width_end);
3013 }
3014 has_width = 1;
3015 }
3016
3017 /* %lc in vasnprintf. See the specification of fprintf. */
3018 {
3019 wchar_t arg = (wchar_t) a.arg[dp->arg_index].a.a_wide_char;
3020 size_t characters;
3021# if !DCHAR_IS_TCHAR
3022 /* This code assumes that TCHAR_T is 'char'. */
3023 verify (sizeof (TCHAR_T) == 1);
3024 TCHAR_T tmpsrc[64]; /* Assume MB_CUR_MAX <= 64. */
3025 DCHAR_T *tmpdst;
3026 size_t tmpdst_len;
3027# endif
3028 size_t w;
3029
3030# if DCHAR_IS_TCHAR
3031 if (has_width)
3032# endif
3033 {
3034 /* Count the number of bytes. */
3035 characters = 0;
3036 if (arg != 0)
3037 {
3038 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3039 int count;
3040# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3041 mbstate_t state;
3042 memset (&state, '\0', sizeof (mbstate_t));
3043# endif
3044
3045 count = local_wcrtomb (cbuf, arg, &state);
3046 if (count < 0)
3047 /* Inconsistency. */
3048 abort ();
3049 characters = count;
3050 }
3051 }
3052# if DCHAR_IS_TCHAR
3053 else
3054 {
3055 /* The number of bytes doesn't matter. */
3056 characters = 0;
3057 }
3058# endif
3059
3060# if !DCHAR_IS_TCHAR
3061 /* Convert the string into a piece of temporary memory. */
3062 if (characters > 0) /* implies arg != 0 */
3063 {
3064 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3065 int count;
3066# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3067 mbstate_t state;
3068 memset (&state, '\0', sizeof (mbstate_t));
3069# endif
3070
3071 count = local_wcrtomb (cbuf, arg, &state);
3072 if (count <= 0)
3073 /* Inconsistency. */
3074 abort ();
3075 memcpy (tmpsrc, cbuf, count);
3076 }
3077
3078 /* Convert from TCHAR_T[] to DCHAR_T[]. */
3079 tmpdst =
3080 DCHAR_CONV_FROM_ENCODING (locale_charset (),
3081 iconveh_question_mark,
3082 tmpsrc, characters,
3083 NULL,
3084 NULL, &tmpdst_len);
3085 if (tmpdst == NULL)
3086 {
3087 if (!(result == resultbuf || result == NULL))
3088 free (result);
3089 if (buf_malloced != NULL)
3090 free (buf_malloced);
3091 CLEANUP ();
3092 return NULL;
3093 }
3094# endif
3095
3096 if (has_width)
3097 {
3098# if ENABLE_UNISTDIO
3099 /* Outside POSIX, it's preferable to compare the width
3100 against the number of _characters_ of the converted
3101 value. */
3102 w = DCHAR_MBSNLEN (result + length, characters);
3103# else
3104 /* The width is compared against the number of _bytes_
3105 of the converted value, says POSIX. */
3106 w = characters;
3107# endif
3108 }
3109 else
3110 /* w doesn't matter. */
3111 w = 0;
3112
3113 if (w < width && !(dp->flags & FLAG_LEFT))
3114 {
3115 size_t n = width - w;
3116 ENSURE_ALLOCATION (xsum (length, n));
3117 DCHAR_SET (result + length, ' ', n);
3118 length += n;
3119 }
3120
3121# if DCHAR_IS_TCHAR
3122 if (has_width)
3123 {
3124 /* We know the number of bytes in advance. */
3125 ENSURE_ALLOCATION (xsum (length, characters));
3126 if (characters > 0) /* implies arg != 0 */
3127 {
3128 int count;
3129# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3130 mbstate_t state;
3131 memset (&state, '\0', sizeof (mbstate_t));
3132# endif
3133
3134 count = local_wcrtomb (result + length, arg, &state);
3135 if (count <= 0)
3136 /* Inconsistency. */
3137 abort ();
3138 length += count;
3139 }
3140 }
3141 else
3142 {
3143 if (arg != 0)
3144 {
3145 char cbuf[64]; /* Assume MB_CUR_MAX <= 64. */
3146 int count;
3147# if HAVE_WCRTOMB && !defined GNULIB_defined_mbstate_t
3148 mbstate_t state;
3149 memset (&state, '\0', sizeof (mbstate_t));
3150# endif
3151
3152 count = local_wcrtomb (cbuf, arg, &state);
3153 if (count <= 0)
3154 /* Inconsistency. */
3155 abort ();
3156 ENSURE_ALLOCATION (xsum (length, count));
3157 memcpy (result + length, cbuf, count);
3158 length += count;
3159 }
3160 }
3161# else
3162 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
3163 { free (tmpdst); goto out_of_memory; });
3164 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
3165 free (tmpdst);
3166 length += tmpdst_len;
3167# endif
3168
3169 if (w < width && (dp->flags & FLAG_LEFT))
3170 {
3171 size_t n = width - w;
3172 ENSURE_ALLOCATION (xsum (length, n));
3173 DCHAR_SET (result + length, ' ', n);
3174 length += n;
3175 }
3176 }
3177 }
3178#endif
2926#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL 3179#if (NEED_PRINTF_DIRECTIVE_A || NEED_PRINTF_LONG_DOUBLE || NEED_PRINTF_DOUBLE) && !defined IN_LIBINTL
2927 else if ((dp->conversion == 'a' || dp->conversion == 'A') 3180 else if ((dp->conversion == 'a' || dp->conversion == 'A')
2928# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE)) 3181# if !(NEED_PRINTF_DIRECTIVE_A || (NEED_PRINTF_LONG_DOUBLE && NEED_PRINTF_DOUBLE))
@@ -2939,17 +3192,16 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2939 { 3192 {
2940 arg_type type = a.arg[dp->arg_index].type; 3193 arg_type type = a.arg[dp->arg_index].type;
2941 int flags = dp->flags; 3194 int flags = dp->flags;
2942 int has_width;
2943 size_t width; 3195 size_t width;
2944 int has_precision; 3196 int has_precision;
2945 size_t precision; 3197 size_t precision;
2946 size_t tmp_length; 3198 size_t tmp_length;
3199 size_t count;
2947 DCHAR_T tmpbuf[700]; 3200 DCHAR_T tmpbuf[700];
2948 DCHAR_T *tmp; 3201 DCHAR_T *tmp;
2949 DCHAR_T *pad_ptr; 3202 DCHAR_T *pad_ptr;
2950 DCHAR_T *p; 3203 DCHAR_T *p;
2951 3204
2952 has_width = 0;
2953 width = 0; 3205 width = 0;
2954 if (dp->width_start != dp->width_end) 3206 if (dp->width_start != dp->width_end)
2955 { 3207 {
@@ -2960,15 +3212,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2960 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 3212 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
2961 abort (); 3213 abort ();
2962 arg = a.arg[dp->width_arg_index].a.a_int; 3214 arg = a.arg[dp->width_arg_index].a.a_int;
3215 width = arg;
2963 if (arg < 0) 3216 if (arg < 0)
2964 { 3217 {
2965 /* "A negative field width is taken as a '-' flag 3218 /* "A negative field width is taken as a '-' flag
2966 followed by a positive field width." */ 3219 followed by a positive field width." */
2967 flags |= FLAG_LEFT; 3220 flags |= FLAG_LEFT;
2968 width = (unsigned int) (-arg); 3221 width = -width;
2969 } 3222 }
2970 else
2971 width = arg;
2972 } 3223 }
2973 else 3224 else
2974 { 3225 {
@@ -2978,7 +3229,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
2978 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3229 width = xsum (xtimes (width, 10), *digitp++ - '0');
2979 while (digitp != dp->width_end); 3230 while (digitp != dp->width_end);
2980 } 3231 }
2981 has_width = 1;
2982 } 3232 }
2983 3233
2984 has_precision = 0; 3234 has_precision = 0;
@@ -3354,11 +3604,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3354 abort (); 3604 abort ();
3355# endif 3605# endif
3356 } 3606 }
3607
3357 /* The generated string now extends from tmp to p, with the 3608 /* The generated string now extends from tmp to p, with the
3358 zero padding insertion point being at pad_ptr. */ 3609 zero padding insertion point being at pad_ptr. */
3359 if (has_width && p - tmp < width) 3610 count = p - tmp;
3611
3612 if (count < width)
3360 { 3613 {
3361 size_t pad = width - (p - tmp); 3614 size_t pad = width - count;
3362 DCHAR_T *end = p + pad; 3615 DCHAR_T *end = p + pad;
3363 3616
3364 if (flags & FLAG_LEFT) 3617 if (flags & FLAG_LEFT)
@@ -3391,28 +3644,26 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3391 p = end; 3644 p = end;
3392 } 3645 }
3393 3646
3394 { 3647 count = p - tmp;
3395 size_t count = p - tmp;
3396 3648
3397 if (count >= tmp_length) 3649 if (count >= tmp_length)
3398 /* tmp_length was incorrectly calculated - fix the 3650 /* tmp_length was incorrectly calculated - fix the
3399 code above! */ 3651 code above! */
3400 abort (); 3652 abort ();
3401 3653
3402 /* Make room for the result. */ 3654 /* Make room for the result. */
3403 if (count >= allocated - length) 3655 if (count >= allocated - length)
3404 { 3656 {
3405 size_t n = xsum (length, count); 3657 size_t n = xsum (length, count);
3406 3658
3407 ENSURE_ALLOCATION (n); 3659 ENSURE_ALLOCATION (n);
3408 } 3660 }
3409 3661
3410 /* Append the result. */ 3662 /* Append the result. */
3411 memcpy (result + length, tmp, count * sizeof (DCHAR_T)); 3663 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
3412 if (tmp != tmpbuf) 3664 if (tmp != tmpbuf)
3413 free (tmp); 3665 free (tmp);
3414 length += count; 3666 length += count;
3415 }
3416 } 3667 }
3417#endif 3668#endif
3418#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL 3669#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
@@ -3446,8 +3697,8 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3446 arg_type type = a.arg[dp->arg_index].type; 3697 arg_type type = a.arg[dp->arg_index].type;
3447# endif 3698# endif
3448 int flags = dp->flags; 3699 int flags = dp->flags;
3449 int has_width;
3450 size_t width; 3700 size_t width;
3701 size_t count;
3451 int has_precision; 3702 int has_precision;
3452 size_t precision; 3703 size_t precision;
3453 size_t tmp_length; 3704 size_t tmp_length;
@@ -3456,7 +3707,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3456 DCHAR_T *pad_ptr; 3707 DCHAR_T *pad_ptr;
3457 DCHAR_T *p; 3708 DCHAR_T *p;
3458 3709
3459 has_width = 0;
3460 width = 0; 3710 width = 0;
3461 if (dp->width_start != dp->width_end) 3711 if (dp->width_start != dp->width_end)
3462 { 3712 {
@@ -3467,15 +3717,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3467 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 3717 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
3468 abort (); 3718 abort ();
3469 arg = a.arg[dp->width_arg_index].a.a_int; 3719 arg = a.arg[dp->width_arg_index].a.a_int;
3720 width = arg;
3470 if (arg < 0) 3721 if (arg < 0)
3471 { 3722 {
3472 /* "A negative field width is taken as a '-' flag 3723 /* "A negative field width is taken as a '-' flag
3473 followed by a positive field width." */ 3724 followed by a positive field width." */
3474 flags |= FLAG_LEFT; 3725 flags |= FLAG_LEFT;
3475 width = (unsigned int) (-arg); 3726 width = -width;
3476 } 3727 }
3477 else
3478 width = arg;
3479 } 3728 }
3480 else 3729 else
3481 { 3730 {
@@ -3485,7 +3734,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3485 width = xsum (xtimes (width, 10), *digitp++ - '0'); 3734 width = xsum (xtimes (width, 10), *digitp++ - '0');
3486 while (digitp != dp->width_end); 3735 while (digitp != dp->width_end);
3487 } 3736 }
3488 has_width = 1;
3489 } 3737 }
3490 3738
3491 has_precision = 0; 3739 has_precision = 0;
@@ -3925,9 +4173,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3925 digits without trailing zeroes. */ 4173 digits without trailing zeroes. */
3926 if (exponent >= 0) 4174 if (exponent >= 0)
3927 { 4175 {
3928 size_t count = exponent + 1; 4176 size_t ecount = exponent + 1;
3929 /* Note: count <= precision = ndigits. */ 4177 /* Note: count <= precision = ndigits. */
3930 for (; count > 0; count--) 4178 for (; ecount > 0; ecount--)
3931 *p++ = digits[--ndigits]; 4179 *p++ = digits[--ndigits];
3932 if ((flags & FLAG_ALT) || ndigits > nzeroes) 4180 if ((flags & FLAG_ALT) || ndigits > nzeroes)
3933 { 4181 {
@@ -3941,10 +4189,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
3941 } 4189 }
3942 else 4190 else
3943 { 4191 {
3944 size_t count = -exponent - 1; 4192 size_t ecount = -exponent - 1;
3945 *p++ = '0'; 4193 *p++ = '0';
3946 *p++ = decimal_point_char (); 4194 *p++ = decimal_point_char ();
3947 for (; count > 0; count--) 4195 for (; ecount > 0; ecount--)
3948 *p++ = '0'; 4196 *p++ = '0';
3949 while (ndigits > nzeroes) 4197 while (ndigits > nzeroes)
3950 { 4198 {
@@ -4249,7 +4497,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4249 static const wchar_t decimal_format[] = 4497 static const wchar_t decimal_format[] =
4250 /* Produce the same number of exponent digits 4498 /* Produce the same number of exponent digits
4251 as the native printf implementation. */ 4499 as the native printf implementation. */
4252# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4500# if defined _WIN32 && ! defined __CYGWIN__
4253 { '%', '+', '.', '3', 'd', '\0' }; 4501 { '%', '+', '.', '3', 'd', '\0' };
4254# else 4502# else
4255 { '%', '+', '.', '2', 'd', '\0' }; 4503 { '%', '+', '.', '2', 'd', '\0' };
@@ -4263,7 +4511,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4263 static const char decimal_format[] = 4511 static const char decimal_format[] =
4264 /* Produce the same number of exponent digits 4512 /* Produce the same number of exponent digits
4265 as the native printf implementation. */ 4513 as the native printf implementation. */
4266# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4514# if defined _WIN32 && ! defined __CYGWIN__
4267 "%+.3d"; 4515 "%+.3d";
4268# else 4516# else
4269 "%+.2d"; 4517 "%+.2d";
@@ -4395,9 +4643,9 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4395 digits without trailing zeroes. */ 4643 digits without trailing zeroes. */
4396 if (exponent >= 0) 4644 if (exponent >= 0)
4397 { 4645 {
4398 size_t count = exponent + 1; 4646 size_t ecount = exponent + 1;
4399 /* Note: count <= precision = ndigits. */ 4647 /* Note: ecount <= precision = ndigits. */
4400 for (; count > 0; count--) 4648 for (; ecount > 0; ecount--)
4401 *p++ = digits[--ndigits]; 4649 *p++ = digits[--ndigits];
4402 if ((flags & FLAG_ALT) || ndigits > nzeroes) 4650 if ((flags & FLAG_ALT) || ndigits > nzeroes)
4403 { 4651 {
@@ -4411,10 +4659,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4411 } 4659 }
4412 else 4660 else
4413 { 4661 {
4414 size_t count = -exponent - 1; 4662 size_t ecount = -exponent - 1;
4415 *p++ = '0'; 4663 *p++ = '0';
4416 *p++ = decimal_point_char (); 4664 *p++ = decimal_point_char ();
4417 for (; count > 0; count--) 4665 for (; ecount > 0; ecount--)
4418 *p++ = '0'; 4666 *p++ = '0';
4419 while (ndigits > nzeroes) 4667 while (ndigits > nzeroes)
4420 { 4668 {
@@ -4442,7 +4690,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4442 static const wchar_t decimal_format[] = 4690 static const wchar_t decimal_format[] =
4443 /* Produce the same number of exponent digits 4691 /* Produce the same number of exponent digits
4444 as the native printf implementation. */ 4692 as the native printf implementation. */
4445# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4693# if defined _WIN32 && ! defined __CYGWIN__
4446 { '%', '+', '.', '3', 'd', '\0' }; 4694 { '%', '+', '.', '3', 'd', '\0' };
4447# else 4695# else
4448 { '%', '+', '.', '2', 'd', '\0' }; 4696 { '%', '+', '.', '2', 'd', '\0' };
@@ -4456,7 +4704,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4456 static const char decimal_format[] = 4704 static const char decimal_format[] =
4457 /* Produce the same number of exponent digits 4705 /* Produce the same number of exponent digits
4458 as the native printf implementation. */ 4706 as the native printf implementation. */
4459# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4707# if defined _WIN32 && ! defined __CYGWIN__
4460 "%+.3d"; 4708 "%+.3d";
4461# else 4709# else
4462 "%+.2d"; 4710 "%+.2d";
@@ -4514,7 +4762,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4514 *p++ = '+'; 4762 *p++ = '+';
4515 /* Produce the same number of exponent digits as 4763 /* Produce the same number of exponent digits as
4516 the native printf implementation. */ 4764 the native printf implementation. */
4517# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 4765# if defined _WIN32 && ! defined __CYGWIN__
4518 *p++ = '0'; 4766 *p++ = '0';
4519# endif 4767# endif
4520 *p++ = '0'; 4768 *p++ = '0';
@@ -4542,9 +4790,11 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4542 4790
4543 /* The generated string now extends from tmp to p, with the 4791 /* The generated string now extends from tmp to p, with the
4544 zero padding insertion point being at pad_ptr. */ 4792 zero padding insertion point being at pad_ptr. */
4545 if (has_width && p - tmp < width) 4793 count = p - tmp;
4794
4795 if (count < width)
4546 { 4796 {
4547 size_t pad = width - (p - tmp); 4797 size_t pad = width - count;
4548 DCHAR_T *end = p + pad; 4798 DCHAR_T *end = p + pad;
4549 4799
4550 if (flags & FLAG_LEFT) 4800 if (flags & FLAG_LEFT)
@@ -4577,39 +4827,39 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4577 p = end; 4827 p = end;
4578 } 4828 }
4579 4829
4580 { 4830 count = p - tmp;
4581 size_t count = p - tmp;
4582 4831
4583 if (count >= tmp_length) 4832 if (count >= tmp_length)
4584 /* tmp_length was incorrectly calculated - fix the 4833 /* tmp_length was incorrectly calculated - fix the
4585 code above! */ 4834 code above! */
4586 abort (); 4835 abort ();
4587 4836
4588 /* Make room for the result. */ 4837 /* Make room for the result. */
4589 if (count >= allocated - length) 4838 if (count >= allocated - length)
4590 { 4839 {
4591 size_t n = xsum (length, count); 4840 size_t n = xsum (length, count);
4592 4841
4593 ENSURE_ALLOCATION (n); 4842 ENSURE_ALLOCATION (n);
4594 } 4843 }
4595 4844
4596 /* Append the result. */ 4845 /* Append the result. */
4597 memcpy (result + length, tmp, count * sizeof (DCHAR_T)); 4846 memcpy (result + length, tmp, count * sizeof (DCHAR_T));
4598 if (tmp != tmpbuf) 4847 if (tmp != tmpbuf)
4599 free (tmp); 4848 free (tmp);
4600 length += count; 4849 length += count;
4601 }
4602 } 4850 }
4603#endif 4851#endif
4604 else 4852 else
4605 { 4853 {
4606 arg_type type = a.arg[dp->arg_index].type; 4854 arg_type type = a.arg[dp->arg_index].type;
4607 int flags = dp->flags; 4855 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 4856#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4609 int has_width; 4857 int has_width;
4858#endif
4859#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; 4860 size_t width;
4611#endif 4861#endif
4612#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION 4862#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
4613 int has_precision; 4863 int has_precision;
4614 size_t precision; 4864 size_t precision;
4615#endif 4865#endif
@@ -4635,8 +4885,10 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4635 TCHAR_T *tmp; 4885 TCHAR_T *tmp;
4636#endif 4886#endif
4637 4887
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 4888#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4639 has_width = 0; 4889 has_width = 0;
4890#endif
4891#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; 4892 width = 0;
4641 if (dp->width_start != dp->width_end) 4893 if (dp->width_start != dp->width_end)
4642 { 4894 {
@@ -4647,15 +4899,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4647 if (!(a.arg[dp->width_arg_index].type == TYPE_INT)) 4899 if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
4648 abort (); 4900 abort ();
4649 arg = a.arg[dp->width_arg_index].a.a_int; 4901 arg = a.arg[dp->width_arg_index].a.a_int;
4902 width = arg;
4650 if (arg < 0) 4903 if (arg < 0)
4651 { 4904 {
4652 /* "A negative field width is taken as a '-' flag 4905 /* "A negative field width is taken as a '-' flag
4653 followed by a positive field width." */ 4906 followed by a positive field width." */
4654 flags |= FLAG_LEFT; 4907 flags |= FLAG_LEFT;
4655 width = (unsigned int) (-arg); 4908 width = -width;
4656 } 4909 }
4657 else
4658 width = arg;
4659 } 4910 }
4660 else 4911 else
4661 { 4912 {
@@ -4665,11 +4916,13 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4665 width = xsum (xtimes (width, 10), *digitp++ - '0'); 4916 width = xsum (xtimes (width, 10), *digitp++ - '0');
4666 while (digitp != dp->width_end); 4917 while (digitp != dp->width_end);
4667 } 4918 }
4919#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
4668 has_width = 1; 4920 has_width = 1;
4921#endif
4669 } 4922 }
4670#endif 4923#endif
4671 4924
4672#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION 4925#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
4673 has_precision = 0; 4926 has_precision = 0;
4674 precision = 6; 4927 precision = 6;
4675 if (dp->precision_start != dp->precision_end) 4928 if (dp->precision_start != dp->precision_end)
@@ -4805,7 +5058,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4805 { 5058 {
4806 const FCHAR_T *mp = dp->width_start; 5059 const FCHAR_T *mp = dp->width_start;
4807 do 5060 do
4808 *fbp++ = (unsigned char) *mp++; 5061 *fbp++ = *mp++;
4809 while (--n > 0); 5062 while (--n > 0);
4810 } 5063 }
4811 } 5064 }
@@ -4826,7 +5079,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4826 { 5079 {
4827 const FCHAR_T *mp = dp->precision_start; 5080 const FCHAR_T *mp = dp->precision_start;
4828 do 5081 do
4829 *fbp++ = (unsigned char) *mp++; 5082 *fbp++ = *mp++;
4830 while (--n > 0); 5083 while (--n > 0);
4831 } 5084 }
4832 } 5085 }
@@ -4834,19 +5087,17 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4834 5087
4835 switch (type) 5088 switch (type)
4836 { 5089 {
4837#if HAVE_LONG_LONG_INT
4838 case TYPE_LONGLONGINT: 5090 case TYPE_LONGLONGINT:
4839 case TYPE_ULONGLONGINT: 5091 case TYPE_ULONGLONGINT:
4840# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ 5092#if defined _WIN32 && ! defined __CYGWIN__
4841 *fbp++ = 'I'; 5093 *fbp++ = 'I';
4842 *fbp++ = '6'; 5094 *fbp++ = '6';
4843 *fbp++ = '4'; 5095 *fbp++ = '4';
4844 break; 5096 break;
4845# else 5097#else
4846 *fbp++ = 'l'; 5098 *fbp++ = 'l';
4847 /*FALLTHROUGH*/
4848# endif
4849#endif 5099#endif
5100 FALLTHROUGH;
4850 case TYPE_LONGINT: 5101 case TYPE_LONGINT:
4851 case TYPE_ULONGINT: 5102 case TYPE_ULONGINT:
4852#if HAVE_WINT_T 5103#if HAVE_WINT_T
@@ -4870,20 +5121,32 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4870#endif 5121#endif
4871 *fbp = dp->conversion; 5122 *fbp = dp->conversion;
4872#if USE_SNPRINTF 5123#if USE_SNPRINTF
4873# if !(((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined __UCLIBC__) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)) 5124# if ((HAVE_SNPRINTF_RETVAL_C99 && HAVE_SNPRINTF_TRUNCATION_C99) \
4874 fbp[1] = '%'; 5125 || ((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
4875 fbp[2] = 'n'; 5126 && !defined __UCLIBC__) \
4876 fbp[3] = '\0'; 5127 || (defined __APPLE__ && defined __MACH__) \
4877# else 5128 || defined __ANDROID__ \
4878 /* On glibc2 systems from glibc >= 2.3 - probably also older 5129 || (defined _WIN32 && ! defined __CYGWIN__))
4879 ones - we know that snprintf's return value conforms to 5130 /* On systems where we know that snprintf's return value
4880 ISO C 99: the tests gl_SNPRINTF_RETVAL_C99 and 5131 conforms to ISO C 99 (HAVE_SNPRINTF_RETVAL_C99) and that
4881 gl_SNPRINTF_TRUNCATION_C99 pass. 5132 snprintf always produces NUL-terminated strings
4882 Therefore we can avoid using %n in this situation. 5133 (HAVE_SNPRINTF_TRUNCATION_C99), it is possible to avoid
4883 On glibc2 systems from 2004-10-18 or newer, the use of %n 5134 using %n. And it is desirable to do so, because more and
4884 in format strings in writable memory may crash the program 5135 more platforms no longer support %n, for "security reasons".
4885 (if compiled with _FORTIFY_SOURCE=2), so we should avoid it 5136 In particular, the following platforms:
4886 in this situation. */ 5137 - On glibc2 systems from 2004-10-18 or newer, the use of
5138 %n in format strings in writable memory may crash the
5139 program (if compiled with _FORTIFY_SOURCE=2).
5140 - On Mac OS X 10.13 or newer, the use of %n in format
5141 strings in writable memory by default crashes the
5142 program.
5143 - On Android, starting on 2018-03-07, the use of %n in
5144 format strings produces a fatal error (see
5145 <https://android.googlesource.com/platform/bionic/+/41398d03b7e8e0dfb951660ae713e682e9fc0336>).
5146 On these platforms, HAVE_SNPRINTF_RETVAL_C99 and
5147 HAVE_SNPRINTF_TRUNCATION_C99 are 1. We have listed them
5148 explicitly in the condition above, in case of cross-
5149 compilation (just to be sure). */
4887 /* On native Windows systems (such as mingw), we can avoid using 5150 /* On native Windows systems (such as mingw), we can avoid using
4888 %n because: 5151 %n because:
4889 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails, 5152 - Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
@@ -4896,10 +5159,14 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
4896 On native Windows systems (such as mingw) where the OS is 5159 On native Windows systems (such as mingw) where the OS is
4897 Windows Vista, the use of %n in format strings by default 5160 Windows Vista, the use of %n in format strings by default
4898 crashes the program. See 5161 crashes the program. See
4899 <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and 5162 <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
4900 <http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx> 5163 <https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/set-printf-count-output>
4901 So we should avoid %n in this situation. */ 5164 So we should avoid %n in this situation. */
4902 fbp[1] = '\0'; 5165 fbp[1] = '\0';
5166# else /* AIX <= 5.1, HP-UX, IRIX, OSF/1, Solaris <= 9, BeOS */
5167 fbp[1] = '%';
5168 fbp[2] = 'n';
5169 fbp[3] = '\0';
4903# endif 5170# endif
4904#else 5171#else
4905 fbp[1] = '\0'; 5172 fbp[1] = '\0';
@@ -5043,7 +5310,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5043 SNPRINTF_BUF (arg); 5310 SNPRINTF_BUF (arg);
5044 } 5311 }
5045 break; 5312 break;
5046#if HAVE_LONG_LONG_INT
5047 case TYPE_LONGLONGINT: 5313 case TYPE_LONGLONGINT:
5048 { 5314 {
5049 long long int arg = a.arg[dp->arg_index].a.a_longlongint; 5315 long long int arg = a.arg[dp->arg_index].a.a_longlongint;
@@ -5056,7 +5322,6 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5056 SNPRINTF_BUF (arg); 5322 SNPRINTF_BUF (arg);
5057 } 5323 }
5058 break; 5324 break;
5059#endif
5060 case TYPE_DOUBLE: 5325 case TYPE_DOUBLE:
5061 { 5326 {
5062 double arg = a.arg[dp->arg_index].a.a_double; 5327 double arg = a.arg[dp->arg_index].a.a_double;
@@ -5116,7 +5381,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5116 { 5381 {
5117 /* Verify that snprintf() has NUL-terminated its 5382 /* Verify that snprintf() has NUL-terminated its
5118 result. */ 5383 result. */
5119 if (count < maxlen 5384 if ((unsigned int) count < maxlen
5120 && ((TCHAR_T *) (result + length)) [count] != '\0') 5385 && ((TCHAR_T *) (result + length)) [count] != '\0')
5121 abort (); 5386 abort ();
5122 /* Portability hack. */ 5387 /* Portability hack. */
@@ -5139,7 +5404,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5139 /* Look at the snprintf() return value. */ 5404 /* Look at the snprintf() return value. */
5140 if (retcount < 0) 5405 if (retcount < 0)
5141 { 5406 {
5142# if !HAVE_SNPRINTF_RETVAL_C99 5407# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
5143 /* HP-UX 10.20 snprintf() is doubly deficient: 5408 /* HP-UX 10.20 snprintf() is doubly deficient:
5144 It doesn't understand the '%n' directive, 5409 It doesn't understand the '%n' directive,
5145 *and* it returns -1 (rather than the length 5410 *and* it returns -1 (rather than the length
@@ -5153,7 +5418,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5153 size_t tmp_length = 5418 size_t tmp_length =
5154 MAX_ROOM_NEEDED (&a, dp->arg_index, 5419 MAX_ROOM_NEEDED (&a, dp->arg_index,
5155 dp->conversion, type, flags, 5420 dp->conversion, type, flags,
5156 has_width ? width : 0, 5421 width,
5157 has_precision, 5422 has_precision,
5158 precision, pad_ourselves); 5423 precision, pad_ourselves);
5159 5424
@@ -5188,21 +5453,22 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5188 /* Attempt to handle failure. */ 5453 /* Attempt to handle failure. */
5189 if (count < 0) 5454 if (count < 0)
5190 { 5455 {
5191 /* SNPRINTF or sprintf failed. Save and use the errno 5456 /* SNPRINTF or sprintf failed. Use the errno that it
5192 that it has set, if any. */ 5457 has set, if any. */
5193 int saved_errno = errno; 5458 if (errno == 0)
5459 {
5460 if (dp->conversion == 'c' || dp->conversion == 's')
5461 errno = EILSEQ;
5462 else
5463 errno = EINVAL;
5464 }
5194 5465
5195 if (!(result == resultbuf || result == NULL)) 5466 if (!(result == resultbuf || result == NULL))
5196 free (result); 5467 free (result);
5197 if (buf_malloced != NULL) 5468 if (buf_malloced != NULL)
5198 free (buf_malloced); 5469 free (buf_malloced);
5199 CLEANUP (); 5470 CLEANUP ();
5200 errno = 5471
5201 (saved_errno != 0
5202 ? saved_errno
5203 : (dp->conversion == 'c' || dp->conversion == 's'
5204 ? EILSEQ
5205 : EINVAL));
5206 return NULL; 5472 return NULL;
5207 } 5473 }
5208 5474
@@ -5338,16 +5604,15 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5338 NULL, &tmpdst_len); 5604 NULL, &tmpdst_len);
5339 if (tmpdst == NULL) 5605 if (tmpdst == NULL)
5340 { 5606 {
5341 int saved_errno = errno;
5342 if (!(result == resultbuf || result == NULL)) 5607 if (!(result == resultbuf || result == NULL))
5343 free (result); 5608 free (result);
5344 if (buf_malloced != NULL) 5609 if (buf_malloced != NULL)
5345 free (buf_malloced); 5610 free (buf_malloced);
5346 CLEANUP (); 5611 CLEANUP ();
5347 errno = saved_errno;
5348 return NULL; 5612 return NULL;
5349 } 5613 }
5350 ENSURE_ALLOCATION (xsum (length, tmpdst_len)); 5614 ENSURE_ALLOCATION_ELSE (xsum (length, tmpdst_len),
5615 { free (tmpdst); goto out_of_memory; });
5351 DCHAR_CPY (result + length, tmpdst, tmpdst_len); 5616 DCHAR_CPY (result + length, tmpdst, tmpdst_len);
5352 free (tmpdst); 5617 free (tmpdst);
5353 count = tmpdst_len; 5618 count = tmpdst_len;
@@ -5391,7 +5656,7 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
5391 tmpsrc += count; 5656 tmpsrc += count;
5392 tmpdst += count; 5657 tmpdst += count;
5393 for (n = count; n > 0; n--) 5658 for (n = count; n > 0; n--)
5394 *--tmpdst = (unsigned char) *--tmpsrc; 5659 *--tmpdst = *--tmpsrc;
5395 } 5660 }
5396 } 5661 }
5397#endif 5662#endif