/* vsprintf with automatic memory allocation.
- Copyright (C) 1999, 2002-2013 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002-2018 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
- with this program; if not, see <http://www.gnu.org/licenses/>. */
+ with this program; if not, see <https://www.gnu.org/licenses/>. */
/* This file can be parametrized with the following macros:
VASNPRINTF The name of the function being defined.
# include "fpucw.h"
#endif
+#ifndef FALLTHROUGH
+# if __GNUC__ < 7
+# define FALLTHROUGH ((void) 0)
+# else
+# define FALLTHROUGH __attribute__ ((__fallthrough__))
+# endif
+#endif
+
/* Default parameters. */
#ifndef VASNPRINTF
# if WIDE_CHAR_VERSION
# define SNPRINTF snwprintf
# else
# define SNPRINTF _snwprintf
+# define USE_MSVC__SNPRINTF 1
# endif
# else
/* Unix. */
/* Here we need to call the native snprintf, not rpl_snprintf. */
# undef snprintf
# else
+ /* MSVC versions < 14 did not have snprintf, only _snprintf. */
# define SNPRINTF _snprintf
+# define USE_MSVC__SNPRINTF 1
# endif
# else
/* Unix. */
/* GCC >= 4.0 with -Wall emits unjustified "... may be used uninitialized"
warnings in this file. Use -Dlint to suppress them. */
-#ifdef lint
+#if defined GCC_LINT || defined lint
# define IF_LINT(Code) Code
#else
# define IF_LINT(Code) /* empty */
#undef remainder
#define remainder rem
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && !WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && !WIDE_CHAR_VERSION
# if (HAVE_STRNLEN && !defined _AIX)
# define local_strnlen strnlen
# else
# endif
#endif
-#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
+#if (((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && WIDE_CHAR_VERSION) || ((!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && !WIDE_CHAR_VERSION && DCHAR_IS_TCHAR)) && HAVE_WCHAR_T
# if HAVE_WCSLEN
# define local_wcslen wcslen
# else
# endif
#endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF) && HAVE_WCHAR_T && WIDE_CHAR_VERSION
# if HAVE_WCSNLEN
# define local_wcsnlen wcsnlen
# else
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
/* Use a different function name, to make it possible that the 'wchar_t'
parametrization and the 'char' parametrization get compiled in the same
else
{
do
- result[length++] = (unsigned char) *cp++;
+ result[length++] = *cp++;
while (--n > 0);
}
}
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
- width = (unsigned int) (-arg);
+ width = -width;
}
- else
- width = arg;
}
else
{
characters = 0;
}
- if (has_width && width > characters
- && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
}
# endif
- if (has_width && width > characters
- && (dp->flags & FLAG_LEFT))
+ if (characters < width && (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
characters = 0;
}
- if (has_width && width > characters
- && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
}
# endif
- if (has_width && width > characters
- && (dp->flags & FLAG_LEFT))
+ if (characters < width && (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
characters = 0;
}
- if (has_width && width > characters
- && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
}
# endif
- if (has_width && width > characters
- && (dp->flags & FLAG_LEFT))
+ if (characters < width && (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
}
}
#endif
-#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
+#if (!USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || (NEED_PRINTF_DIRECTIVE_LS && !defined IN_LIBINTL)) && HAVE_WCHAR_T
else if (dp->conversion == 's'
# if WIDE_CHAR_VERSION
&& a.arg[dp->arg_index].type != TYPE_WIDE_STRING
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
- width = (unsigned int) (-arg);
+ width = -width;
}
- else
- width = arg;
}
else
{
characters = 0;
}
- if (has_width && width > characters
- && !(dp->flags & FLAG_LEFT))
+ if (characters < width && !(dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
}
}
- if (has_width && width > characters
- && (dp->flags & FLAG_LEFT))
+ if (characters < width && (dp->flags & FLAG_LEFT))
{
size_t n = width - characters;
ENSURE_ALLOCATION (xsum (length, n));
/* w doesn't matter. */
w = 0;
- if (has_width && width > w
- && !(dp->flags & FLAG_LEFT))
+ if (w < width && !(dp->flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
length += tmpdst_len;
# endif
- if (has_width && width > w
- && (dp->flags & FLAG_LEFT))
+ if (w < width && (dp->flags & FLAG_LEFT))
{
size_t n = width - w;
ENSURE_ALLOCATION (xsum (length, n));
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
- int has_width;
size_t width;
int has_precision;
size_t precision;
size_t tmp_length;
+ size_t count;
DCHAR_T tmpbuf[700];
DCHAR_T *tmp;
DCHAR_T *pad_ptr;
DCHAR_T *p;
- has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
- width = (unsigned int) (-arg);
+ width = -width;
}
- else
- width = arg;
}
else
{
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
- has_width = 1;
}
has_precision = 0;
abort ();
# endif
}
+
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
- if (has_width && p - tmp < width)
+ count = p - tmp;
+
+ if (count < width)
{
- size_t pad = width - (p - tmp);
+ size_t pad = width - count;
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
p = end;
}
- {
- size_t count = p - tmp;
+ count = p - tmp;
- if (count >= tmp_length)
- /* tmp_length was incorrectly calculated - fix the
- code above! */
- abort ();
+ if (count >= tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
- /* Make room for the result. */
- if (count >= allocated - length)
- {
- size_t n = xsum (length, count);
+ /* Make room for the result. */
+ if (count >= allocated - length)
+ {
+ size_t n = xsum (length, count);
- ENSURE_ALLOCATION (n);
- }
+ ENSURE_ALLOCATION (n);
+ }
- /* Append the result. */
- memcpy (result + length, tmp, count * sizeof (DCHAR_T));
- if (tmp != tmpbuf)
- free (tmp);
- length += count;
- }
+ /* Append the result. */
+ memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+ length += count;
}
#endif
#if (NEED_PRINTF_INFINITE_DOUBLE || NEED_PRINTF_DOUBLE || NEED_PRINTF_INFINITE_LONG_DOUBLE || NEED_PRINTF_LONG_DOUBLE) && !defined IN_LIBINTL
arg_type type = a.arg[dp->arg_index].type;
# endif
int flags = dp->flags;
- int has_width;
size_t width;
+ size_t count;
int has_precision;
size_t precision;
size_t tmp_length;
DCHAR_T *pad_ptr;
DCHAR_T *p;
- has_width = 0;
width = 0;
if (dp->width_start != dp->width_end)
{
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
- width = (unsigned int) (-arg);
+ width = -width;
}
- else
- width = arg;
}
else
{
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
- has_width = 1;
}
has_precision = 0;
digits without trailing zeroes. */
if (exponent >= 0)
{
- size_t count = exponent + 1;
+ size_t ecount = exponent + 1;
/* Note: count <= precision = ndigits. */
- for (; count > 0; count--)
+ for (; ecount > 0; ecount--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
}
else
{
- size_t count = -exponent - 1;
+ size_t ecount = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
- for (; count > 0; count--)
+ for (; ecount > 0; ecount--)
*p++ = '0';
while (ndigits > nzeroes)
{
digits without trailing zeroes. */
if (exponent >= 0)
{
- size_t count = exponent + 1;
- /* Note: count <= precision = ndigits. */
- for (; count > 0; count--)
+ size_t ecount = exponent + 1;
+ /* Note: ecount <= precision = ndigits. */
+ for (; ecount > 0; ecount--)
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || ndigits > nzeroes)
{
}
else
{
- size_t count = -exponent - 1;
+ size_t ecount = -exponent - 1;
*p++ = '0';
*p++ = decimal_point_char ();
- for (; count > 0; count--)
+ for (; ecount > 0; ecount--)
*p++ = '0';
while (ndigits > nzeroes)
{
/* The generated string now extends from tmp to p, with the
zero padding insertion point being at pad_ptr. */
- if (has_width && p - tmp < width)
+ count = p - tmp;
+
+ if (count < width)
{
- size_t pad = width - (p - tmp);
+ size_t pad = width - count;
DCHAR_T *end = p + pad;
if (flags & FLAG_LEFT)
p = end;
}
- {
- size_t count = p - tmp;
+ count = p - tmp;
- if (count >= tmp_length)
- /* tmp_length was incorrectly calculated - fix the
- code above! */
- abort ();
+ if (count >= tmp_length)
+ /* tmp_length was incorrectly calculated - fix the
+ code above! */
+ abort ();
- /* Make room for the result. */
- if (count >= allocated - length)
- {
- size_t n = xsum (length, count);
+ /* Make room for the result. */
+ if (count >= allocated - length)
+ {
+ size_t n = xsum (length, count);
- ENSURE_ALLOCATION (n);
- }
+ ENSURE_ALLOCATION (n);
+ }
- /* Append the result. */
- memcpy (result + length, tmp, count * sizeof (DCHAR_T));
- if (tmp != tmpbuf)
- free (tmp);
- length += count;
- }
+ /* Append the result. */
+ memcpy (result + length, tmp, count * sizeof (DCHAR_T));
+ if (tmp != tmpbuf)
+ free (tmp);
+ length += count;
}
#endif
else
{
arg_type type = a.arg[dp->arg_index].type;
int flags = dp->flags;
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
int has_width;
+#endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
size_t width;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
int has_precision;
size_t precision;
#endif
TCHAR_T *tmp;
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 0;
+#endif
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
width = 0;
if (dp->width_start != dp->width_end)
{
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
arg = a.arg[dp->width_arg_index].a.a_int;
+ width = arg;
if (arg < 0)
{
/* "A negative field width is taken as a '-' flag
followed by a positive field width." */
flags |= FLAG_LEFT;
- width = (unsigned int) (-arg);
+ width = -width;
}
- else
- width = arg;
}
else
{
width = xsum (xtimes (width, 10), *digitp++ - '0');
while (digitp != dp->width_end);
}
+#if !DCHAR_IS_TCHAR || ENABLE_UNISTDIO || NEED_PRINTF_FLAG_LEFTADJUST || NEED_PRINTF_FLAG_ZERO || NEED_PRINTF_UNBOUNDED_PRECISION
has_width = 1;
+#endif
}
#endif
-#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || NEED_PRINTF_UNBOUNDED_PRECISION
+#if !USE_SNPRINTF || !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF || NEED_PRINTF_UNBOUNDED_PRECISION
has_precision = 0;
precision = 6;
if (dp->precision_start != dp->precision_end)
{
const FCHAR_T *mp = dp->width_start;
do
- *fbp++ = (unsigned char) *mp++;
+ *fbp++ = *mp++;
while (--n > 0);
}
}
{
const FCHAR_T *mp = dp->precision_start;
do
- *fbp++ = (unsigned char) *mp++;
+ *fbp++ = *mp++;
while (--n > 0);
}
}
break;
# else
*fbp++ = 'l';
- /*FALLTHROUGH*/
# endif
#endif
+ FALLTHROUGH;
case TYPE_LONGINT:
case TYPE_ULONGINT:
#if HAVE_WINT_T
#endif
*fbp = dp->conversion;
#if USE_SNPRINTF
-# if !(((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) && !defined __UCLIBC__) || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
+# if ! (((__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 3)) \
+ && !defined __UCLIBC__) \
+ || (defined __APPLE__ && defined __MACH__) \
+ || ((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__))
fbp[1] = '%';
fbp[2] = 'n';
fbp[3] = '\0';
in format strings in writable memory may crash the program
(if compiled with _FORTIFY_SOURCE=2), so we should avoid it
in this situation. */
+ /* On Mac OS X 10.3 or newer, we know that snprintf's return
+ value conforms to ISO C 99: the tests gl_SNPRINTF_RETVAL_C99
+ and gl_SNPRINTF_TRUNCATION_C99 pass.
+ Therefore we can avoid using %n in this situation.
+ On Mac OS X 10.13 or newer, the use of %n in format strings
+ in writable memory by default crashes the program, so we
+ should avoid it in this situation. */
/* On native Windows systems (such as mingw), we can avoid using
%n because:
- Although the gl_SNPRINTF_TRUNCATION_C99 test fails,
On native Windows systems (such as mingw) where the OS is
Windows Vista, the use of %n in format strings by default
crashes the program. See
- <http://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
- <http://msdn2.microsoft.com/en-us/library/ms175782(VS.80).aspx>
+ <https://gcc.gnu.org/ml/gcc/2007-06/msg00122.html> and
+ <https://msdn.microsoft.com/en-us/library/ms175782.aspx>
So we should avoid %n in this situation. */
fbp[1] = '\0';
# endif
/* Look at the snprintf() return value. */
if (retcount < 0)
{
-# if !HAVE_SNPRINTF_RETVAL_C99
+# if !HAVE_SNPRINTF_RETVAL_C99 || USE_MSVC__SNPRINTF
/* HP-UX 10.20 snprintf() is doubly deficient:
It doesn't understand the '%n' directive,
*and* it returns -1 (rather than the length
size_t tmp_length =
MAX_ROOM_NEEDED (&a, dp->arg_index,
dp->conversion, type, flags,
- has_width ? width : 0,
+ width,
has_precision,
precision, pad_ourselves);
/* SNPRINTF or sprintf failed. Save and use the errno
that it has set, if any. */
int saved_errno = errno;
+ if (saved_errno == 0)
+ {
+ if (dp->conversion == 'c' || dp->conversion == 's')
+ saved_errno = EILSEQ;
+ else
+ saved_errno = EINVAL;
+ }
if (!(result == resultbuf || result == NULL))
free (result);
if (buf_malloced != NULL)
free (buf_malloced);
CLEANUP ();
- errno =
- (saved_errno != 0
- ? saved_errno
- : (dp->conversion == 'c' || dp->conversion == 's'
- ? EILSEQ
- : EINVAL));
+
+ errno = saved_errno;
return NULL;
}
tmpsrc += count;
tmpdst += count;
for (n = count; n > 0; n--)
- *--tmpdst = (unsigned char) *--tmpsrc;
+ *--tmpdst = *--tmpsrc;
}
}
#endif