/* vsprintf with automatic memory allocation.
- Copyright (C) 1999, 2002-2003 Free Software Foundation, Inc.
+ Copyright (C) 1999, 2002-2006 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
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* Tell glibc's <stdio.h> to provide a prototype for snprintf().
This must come before <config.h> because <config.h> may include
#include <stdlib.h> /* abort(), malloc(), realloc(), free() */
#include <string.h> /* memcpy(), strlen() */
#include <errno.h> /* errno */
-#include <limits.h> /* CHAR_BIT */
+#include <limits.h> /* CHAR_BIT, INT_MAX */
#include <float.h> /* DBL_MAX_EXP, LDBL_MAX_EXP */
#if WIDE_CHAR_VERSION
# include "wprintf-parse.h"
/* Checked size_t computations. */
#include "xsize.h"
-/* For those losing systems which don't have 'alloca' we have to add
- some additional code emulating it. */
-#ifdef HAVE_ALLOCA
-# define freea(p) /* nothing */
-#else
-# define alloca(n) malloc (n)
-# define freea(p) free (p)
+/* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW. */
+#ifndef EOVERFLOW
+# define EOVERFLOW E2BIG
#endif
#ifdef HAVE_WCHAR_T
}
{
- size_t buf_neededlength =
- xsum4 (7, d.max_width_length, d.max_precision_length, 6);
- CHAR_T *buf =
- (CHAR_T *) alloca (xtimes (buf_neededlength, sizeof (CHAR_T)));
+ size_t buf_neededlength;
+ CHAR_T *buf;
+ CHAR_T *buf_malloced;
const CHAR_T *cp;
size_t i;
DIRECTIVE *dp;
size_t allocated;
size_t length;
+ /* Allocate a small buffer that will hold a directive passed to
+ sprintf or snprintf. */
+ buf_neededlength =
+ xsum4 (7, d.max_width_length, d.max_precision_length, 6);
+#if HAVE_ALLOCA
+ if (buf_neededlength < 4000 / sizeof (CHAR_T))
+ {
+ buf = (CHAR_T *) alloca (buf_neededlength * sizeof (CHAR_T));
+ buf_malloced = NULL;
+ }
+ else
+#endif
+ {
+ size_t buf_memsize = xtimes (buf_neededlength, sizeof (CHAR_T));
+ if (size_overflow_p (buf_memsize))
+ goto out_of_memory_1;
+ buf = (CHAR_T *) malloc (buf_memsize);
+ if (buf == NULL)
+ goto out_of_memory_1;
+ buf_malloced = buf;
+ }
+
if (resultbuf != NULL)
{
result = resultbuf;
{
size_t augmented_length;
- if (!(dp->arg_index < 0))
+ if (!(dp->arg_index == ARG_NONE))
abort ();
augmented_length = xsum (length, 1);
ENSURE_ALLOCATION (augmented_length);
}
else
{
- if (!(dp->arg_index >= 0))
+ if (!(dp->arg_index != ARG_NONE))
abort ();
if (dp->conversion == 'n')
width = 0;
if (dp->width_start != dp->width_end)
{
- if (dp->width_arg_index >= 0)
+ if (dp->width_arg_index != ARG_NONE)
{
int arg;
precision = 6;
if (dp->precision_start != dp->precision_end)
{
- if (dp->precision_arg_index >= 0)
+ if (dp->precision_arg_index != ARG_NONE)
{
int arg;
const CHAR_T *digitp = dp->precision_start + 1;
precision = 0;
- do
+ while (digitp != dp->precision_end)
precision = xsum (xtimes (precision, 10), *digitp++ - '0');
- while (digitp != dp->precision_end);
}
}
tmp_length =
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
- * 2 /* estimate for FLAG_GROUP */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
tmp_length =
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.30103 /* binary -> decimal */
- * 2 /* estimate for FLAG_GROUP */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.30103 /* binary -> decimal */
- * 2 /* estimate for FLAG_GROUP */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Multiply by 2, as an estimate for FLAG_GROUP. */
+ tmp_length = xsum (tmp_length, tmp_length);
+ /* Add 1, to account for a leading sign. */
+ tmp_length = xsum (tmp_length, 1);
break;
case 'o':
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.333334 /* binary -> octal */
)
- + 1 /* turn floor into ceil */
- + 1; /* account for leading sign */
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 1, to account for a leading sign. */
+ tmp_length = xsum (tmp_length, 1);
break;
case 'x': case 'X':
(unsigned int) (sizeof (unsigned long long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
- + 1 /* turn floor into ceil */
- + 2; /* account for leading sign or alternate form */
+ + 1; /* turn floor into ceil */
else
# endif
if (type == TYPE_LONGINT || type == TYPE_ULONGINT)
(unsigned int) (sizeof (unsigned long) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
- + 1 /* turn floor into ceil */
- + 2; /* account for leading sign or alternate form */
+ + 1; /* turn floor into ceil */
else
tmp_length =
(unsigned int) (sizeof (unsigned int) * CHAR_BIT
* 0.25 /* binary -> hexadecimal */
)
- + 1 /* turn floor into ceil */
- + 2; /* account for leading sign or alternate form */
+ + 1; /* turn floor into ceil */
+ if (tmp_length < precision)
+ tmp_length = precision;
+ /* Add 2, to account for a leading sign or alternate form. */
+ tmp_length = xsum (tmp_length, 2);
break;
case 'f': case 'F':
/* Construct the arguments for calling snprintf or sprintf. */
prefix_count = 0;
- if (dp->width_arg_index >= 0)
+ if (dp->width_arg_index != ARG_NONE)
{
if (!(a.arg[dp->width_arg_index].type == TYPE_INT))
abort ();
prefixes[prefix_count++] = a.arg[dp->width_arg_index].a.a_int;
}
- if (dp->precision_arg_index >= 0)
+ if (dp->precision_arg_index != ARG_NONE)
{
if (!(a.arg[dp->precision_arg_index].type == TYPE_INT))
abort ();
{
if (!(result == resultbuf || result == NULL))
free (result);
- freea (buf);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
CLEANUP ();
errno = EINVAL;
return NULL;
result = memory;
}
- freea (buf);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
CLEANUP ();
*lengthp = length;
+ if (length > INT_MAX)
+ goto length_overflow;
return result;
+ length_overflow:
+ /* We could produce such a big string, but its length doesn't fit into
+ an 'int'. POSIX says that snprintf() fails with errno = EOVERFLOW in
+ this case. */
+ if (result != resultbuf)
+ free (result);
+ errno = EOVERFLOW;
+ return NULL;
+
out_of_memory:
if (!(result == resultbuf || result == NULL))
free (result);
- freea (buf);
+ if (buf_malloced != NULL)
+ free (buf_malloced);
+ out_of_memory_1:
CLEANUP ();
errno = ENOMEM;
return NULL;