summaryrefslogtreecommitdiff
path: root/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/vasprintf.c')
-rw-r--r--Build/source/libs/mpfr/mpfr-src/src/vasprintf.c787
1 files changed, 501 insertions, 286 deletions
diff --git a/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c b/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c
index 08855d10191..689fc82a690 100644
--- a/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c
+++ b/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c
@@ -1,5 +1,5 @@
-/* mpfr_vasprintf -- main function for the printf functions family
- plus helper macros & functions.
+/* mpfr_vasnprintf_aux -- helper function for the formatted output functions
+ (printf functions family).
Copyright 2007-2017 Free Software Foundation, Inc.
Contributed by the AriC and Caramba projects, INRIA.
@@ -21,12 +21,31 @@ along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+/* If the number of output characters is larger than INT_MAX, the
+ ISO C99 standard is silent, but POSIX says concerning the snprintf()
+ function:
+ "[EOVERFLOW] The value of n is greater than {INT_MAX} or the
+ number of bytes needed to hold the output excluding the
+ terminating null is greater than {INT_MAX}." See:
+ http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
+ But it doesn't say anything concerning the other printf-like functions.
+ A defect report has been submitted to austin-review-l (item 2532).
+ So, for the time being, we return a negative value and set the erange
+ flag, and set errno to EOVERFLOW in POSIX system. */
+
+/* Note: Due to limitations from the C standard and GMP, if
+ size_t < unsigned int (which is allowed by the C standard but unlikely
+ to occur on any platform), the behavior is undefined for output that
+ would reach SIZE_MAX = (size_t) -1 (if the result cannot be delivered,
+ there should be an assertion failure, but this could not be tested). */
+
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
-/* The mpfr_printf-like functions are defined only if <stdarg.h> exists */
-#ifdef HAVE_STDARG
+/* The mpfr_printf-like functions are defined only if <stdarg.h> exists.
+ Since they use mpf_t, they cannot be defined with mini-gmp. */
+#if defined(HAVE_STDARG) && !defined(MPFR_USE_MINI_GMP)
#include <stdarg.h>
@@ -47,7 +66,6 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
#if defined (__cplusplus)
#include <cstddef>
-#define __STDC_LIMIT_MACROS /* SIZE_MAX defined with <stdint.h> inclusion */
#else
#include <stddef.h> /* for ptrdiff_t */
#endif
@@ -159,9 +177,10 @@ struct printf_spec
int width; /* Width */
int prec; /* Precision */
+ size_t size; /* Wanted size (0 iff snprintf with size=0) */
enum arg_t arg_type; /* Type of argument */
- mpfr_rnd_t rnd_mode; /* Rounding mode */
+ mpfr_rnd_t rnd_mode; /* Rounding mode */
char spec; /* Conversion specifier */
char pad; /* Padding character */
@@ -177,6 +196,7 @@ specinfo_init (struct printf_spec *specinfo)
specinfo->group = 0;
specinfo->width = 0;
specinfo->prec = 0;
+ specinfo->size = 1;
specinfo->arg_type = NONE;
specinfo->rnd_mode = MPFR_RNDN;
specinfo->spec = '\0';
@@ -276,14 +296,10 @@ parse_arg_type (const char *format, struct printf_spec *specinfo)
break;
case 'h':
if (*++format == 'h')
-#ifndef NPRINTF_HH
{
++format;
specinfo->arg_type = CHAR_ARG;
}
-#else
- specinfo->arg_type = UNSUPPORTED;
-#endif
else
specinfo->arg_type = SHORT_ARG;
break;
@@ -291,7 +307,7 @@ parse_arg_type (const char *format, struct printf_spec *specinfo)
if (*++format == 'l')
{
++format;
-#if defined (HAVE_LONG_LONG) && !defined(NPRINTF_LL)
+#if defined (HAVE_LONG_LONG)
specinfo->arg_type = LONG_LONG_ARG;
#else
specinfo->arg_type = UNSUPPORTED;
@@ -305,7 +321,7 @@ parse_arg_type (const char *format, struct printf_spec *specinfo)
}
case 'j':
++format;
-#if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J)
+#if defined(_MPFR_H_HAVE_INTMAX_T)
specinfo->arg_type = INTMAX_ARG;
#else
specinfo->arg_type = UNSUPPORTED;
@@ -317,19 +333,11 @@ parse_arg_type (const char *format, struct printf_spec *specinfo)
break;
case 't':
++format;
-#ifndef NPRINTF_T
specinfo->arg_type = PTRDIFF_ARG;
-#else
- specinfo->arg_type = UNSUPPORTED;
-#endif
break;
case 'L':
++format;
-#ifndef NPRINTF_L
specinfo->arg_type = LONG_DOUBLE_ARG;
-#else
- specinfo->arg_type = UNSUPPORTED;
-#endif
break;
case 'F':
++format;
@@ -385,9 +393,9 @@ typedef wint_t mpfr_va_wint;
#endif
#define CASE_LONG_ARG(specinfo, ap) \
case LONG_ARG: \
- if (((specinfo).spec == 'd') || ((specinfo).spec == 'i') \
- || ((specinfo).spec == 'o') || ((specinfo).spec == 'u') \
- || ((specinfo).spec == 'x') || ((specinfo).spec == 'X')) \
+ if ((specinfo).spec == 'd' || (specinfo).spec == 'i' \
+ || (specinfo).spec == 'o' || (specinfo).spec == 'u' \
+ || (specinfo).spec == 'x' || (specinfo).spec == 'X') \
(void) va_arg ((ap), long); \
else if ((specinfo).spec == 'c') \
(void) va_arg ((ap), mpfr_va_wint); \
@@ -487,7 +495,10 @@ typedef wint_t mpfr_va_wint;
} while (0)
/* process the format part which does not deal with mpfr types,
- jump to external label 'error' if gmp_asprintf return -1. */
+ jump to external label 'error' if gmp_asprintf return -1.
+ Note: start and end are pointers to the format string, so that
+ size_t is the best type to express the difference.
+ */
#define FLUSH(flag, start, end, ap, buf_ptr) \
do { \
const size_t n = (end) - (start); \
@@ -495,16 +506,21 @@ typedef wint_t mpfr_va_wint;
/* previous specifiers are understood by gmp_printf */ \
{ \
MPFR_TMP_DECL (marker); \
- char *fmt_copy; \
+ char *fmt_copy, *s; \
+ int length; \
+ \
MPFR_TMP_MARK (marker); \
fmt_copy = (char*) MPFR_TMP_ALLOC (n + 1); \
strncpy (fmt_copy, (start), n); \
fmt_copy[n] = '\0'; \
- if (sprntf_gmp ((buf_ptr), (fmt_copy), (ap)) == -1) \
+ length = gmp_vasprintf (&s, fmt_copy, (ap)); \
+ if (length < 0) \
{ \
MPFR_TMP_FREE (marker); \
goto error; \
} \
+ buffer_cat ((buf_ptr), s, length); \
+ mpfr_free_str (s); \
(flag) = 0; \
MPFR_TMP_FREE (marker); \
} \
@@ -513,20 +529,56 @@ typedef wint_t mpfr_va_wint;
buffer_cat ((buf_ptr), (start), n); \
} while (0)
+/* Note: in case some form of %n is used in the format string,
+ we may need the maximum signed integer type for len. */
struct string_buffer
{
char *start; /* beginning of the buffer */
char *curr; /* null terminating character */
size_t size; /* buffer capacity */
+ mpfr_intmax_t len; /* string length or -1 if overflow */
};
static void
buffer_init (struct string_buffer *b, size_t s)
{
- b->start = (char *) (*__gmp_allocate_func) (s);
- b->start[0] = '\0';
- b->curr = b->start;
+ if (s != 0)
+ {
+ b->start = (char *) mpfr_allocate_func (s);
+ b->start[0] = '\0';
+ b->curr = b->start;
+ }
b->size = s;
+ b->len = 0;
+}
+
+/* Increase the len field of the buffer. Return non-zero iff overflow. */
+static int
+buffer_incr_len (struct string_buffer *b, size_t len)
+{
+ if (b->len == -1)
+ return 1;
+ else
+ {
+ /* We need to take mpfr_uintmax_t as the type must be as large
+ as both size_t (which is unsigned) and mpfr_intmax_t (which
+ is used for the 'n' format specifier). */
+ mpfr_uintmax_t newlen = (mpfr_uintmax_t) b->len + len;
+
+ /* mpfr_uintmax_t is unsigned, thus the above is valid, but one
+ has newlen < len in case of overflow. */
+
+ if (MPFR_UNLIKELY (newlen < len || newlen > MPFR_INTMAX_MAX))
+ {
+ b->len = -1;
+ return 1;
+ }
+ else
+ {
+ b->len = newlen;
+ return 0;
+ }
+ }
}
/* Increase buffer size by a number of character being the least multiple of
@@ -536,13 +588,19 @@ buffer_widen (struct string_buffer *b, size_t len)
{
const size_t pos = b->curr - b->start;
const size_t n = 0x1000 + (len & ~((size_t) 0xfff));
+
+ /* There are currently limitations here. We would need to switch to
+ the null-size behavior once there is an overflow in the buffer. */
+
+ MPFR_ASSERTN (n >= 0x1000 && n >= len);
+
+ MPFR_ASSERTD (*b->curr == '\0');
MPFR_ASSERTD (pos < b->size);
- MPFR_ASSERTN ((len & ~((size_t) 4095)) <= (size_t)(SIZE_MAX - 4096));
- MPFR_ASSERTN (b->size < SIZE_MAX - n);
+ MPFR_ASSERTN (b->size < ((size_t) -1) - n);
b->start =
- (char *) (*__gmp_reallocate_func) (b->start, b->size, b->size + n);
+ (char *) mpfr_reallocate_func (b->start, b->size, b->size + n);
b->size += n;
b->curr = b->start + pos;
@@ -551,121 +609,145 @@ buffer_widen (struct string_buffer *b, size_t len)
}
/* Concatenate the LEN first characters of the string S to the buffer B and
- expand it if needed. */
-static void
+ expand it if needed. Return non-zero if overflow. */
+static int
buffer_cat (struct string_buffer *b, const char *s, size_t len)
{
- MPFR_ASSERTD (len != 0);
+ MPFR_ASSERTD (len > 0);
MPFR_ASSERTD (len <= strlen (s));
- if (MPFR_UNLIKELY ((b->curr + len) >= (b->start + b->size)))
- buffer_widen (b, len);
+ if (buffer_incr_len (b, len))
+ return 1;
- strncat (b->curr, s, len);
- b->curr += len;
+ if (b->size != 0)
+ {
+ MPFR_ASSERTD (*b->curr == '\0');
+ MPFR_ASSERTN (b->size < ((size_t) -1) - len);
+ if (MPFR_UNLIKELY (b->curr + len >= b->start + b->size))
+ buffer_widen (b, len);
+
+ /* strncat is similar to strncpy here, except that strncat ensures
+ that the buffer will be null-terminated. */
+ strncat (b->curr, s, len);
+ b->curr += len;
+
+ MPFR_ASSERTD (b->curr < b->start + b->size);
+ MPFR_ASSERTD (*b->curr == '\0');
+ }
- MPFR_ASSERTD (b->curr < b->start + b->size);
- MPFR_ASSERTD (*b->curr == '\0');
+ return 0;
}
-/* Add N characters C to the end of buffer B */
-static void
+/* Add N characters C to the end of buffer B. Return non-zero if overflow. */
+static int
buffer_pad (struct string_buffer *b, const char c, const size_t n)
{
- MPFR_ASSERTD (n != 0);
+ MPFR_ASSERTD (n > 0);
- MPFR_ASSERTN (b->size < SIZE_MAX - n - 1);
- if (MPFR_UNLIKELY ((b->curr + n + 1) > (b->start + b->size)))
- buffer_widen (b, n);
+ if (buffer_incr_len (b, n))
+ return 1;
- if (n == 1)
- *b->curr = c;
- else
- memset (b->curr, c, n);
- b->curr += n;
- *b->curr = '\0';
+ if (b->size != 0)
+ {
+ MPFR_ASSERTD (*b->curr == '\0');
+ MPFR_ASSERTN (b->size < ((size_t) -1) - n);
+ if (MPFR_UNLIKELY (b->curr + n >= b->start + b->size))
+ buffer_widen (b, n);
+
+ if (n == 1)
+ *b->curr = c;
+ else
+ memset (b->curr, c, n);
+ b->curr += n;
+ *b->curr = '\0';
- MPFR_ASSERTD (b->curr < b->start + b->size);
+ MPFR_ASSERTD (b->curr < b->start + b->size);
+ }
+
+ return 0;
}
/* Form a string by concatenating the first LEN characters of STR to TZ
zero(s), insert into one character C each 3 characters starting from end
- to begining and concatenate the result to the buffer B. */
-static void
+ to beginning and concatenate the result to the buffer B. */
+static int
buffer_sandwich (struct string_buffer *b, char *str, size_t len,
const size_t tz, const char c)
{
- const size_t step = 3;
- const size_t size = len + tz;
- const size_t r = size % step == 0 ? step : size % step;
- const size_t q = size % step == 0 ? size / step - 1 : size / step;
- size_t i;
+ MPFR_ASSERTD (len <= strlen (str));
- MPFR_ASSERTD (size != 0);
if (c == '\0')
- {
- buffer_cat (b, str, len);
+ return
+ buffer_cat (b, str, len) ||
buffer_pad (b, '0', tz);
- return;
- }
+ else
+ {
+ const size_t step = 3;
+ const size_t size = len + tz;
+ const size_t r = size % step == 0 ? step : size % step;
+ const size_t q = size % step == 0 ? size / step - 1 : size / step;
+ const size_t fullsize = size + q;
+ size_t i;
- MPFR_ASSERTN (b->size < SIZE_MAX - size - 1 - q);
- MPFR_ASSERTD (len <= strlen (str));
- if (MPFR_UNLIKELY ((b->curr + size + 1 + q) > (b->start + b->size)))
- buffer_widen (b, size + q);
+ MPFR_ASSERTD (size > 0);
- /* first R significant digits */
- memcpy (b->curr, str, r);
- b->curr += r;
- str += r;
- len -= r;
+ if (buffer_incr_len (b, fullsize))
+ return 1;
- /* blocks of thousands. Warning: STR might end in the middle of a block */
- for (i = 0; i < q; ++i)
- {
- *b->curr++ = c;
- if (MPFR_LIKELY (len > 0))
+ if (b->size != 0)
{
- if (MPFR_LIKELY (len >= step))
- /* step significant digits */
- {
- memcpy (b->curr, str, step);
- len -= step;
- }
- else
- /* last digits in STR, fill up thousand block with zeros */
- {
- memcpy (b->curr, str, len);
- memset (b->curr + len, '0', step - len);
- len = 0;
- }
- }
- else
- /* trailing zeros */
- memset (b->curr, '0', step);
+ char *oldcurr;
- b->curr += step;
- str += step;
- }
+ MPFR_ASSERTD (*b->curr == '\0');
+ MPFR_ASSERTN (b->size < ((size_t) -1) - fullsize);
+ if (MPFR_UNLIKELY (b->curr + fullsize >= b->start + b->size))
+ buffer_widen (b, fullsize);
- *b->curr = '\0';
+ MPFR_DBGRES (oldcurr = b->curr);
- MPFR_ASSERTD (b->curr < b->start + b->size);
-}
+ /* first R significant digits */
+ memcpy (b->curr, str, r);
+ b->curr += r;
+ str += r;
+ len -= r;
-/* let gmp_xprintf process the part it can understand */
-static int
-sprntf_gmp (struct string_buffer *b, const char *fmt, va_list ap)
-{
- int length;
- char *s;
+ /* blocks of thousands. Warning: STR might end in the middle of a block */
+ for (i = 0; i < q; ++i)
+ {
+ *b->curr++ = c;
+ if (MPFR_LIKELY (len > 0))
+ {
+ if (MPFR_LIKELY (len >= step))
+ /* step significant digits */
+ {
+ memcpy (b->curr, str, step);
+ len -= step;
+ }
+ else
+ /* last digits in STR, fill up thousand block with zeros */
+ {
+ memcpy (b->curr, str, len);
+ memset (b->curr + len, '0', step - len);
+ len = 0;
+ }
+ }
+ else
+ /* trailing zeros */
+ memset (b->curr, '0', step);
- length = gmp_vasprintf (&s, fmt, ap);
- if (length > 0)
- buffer_cat (b, s, length);
+ b->curr += step;
+ str += step;
+ }
+
+ MPFR_ASSERTD (b->curr - oldcurr == fullsize);
+
+ *b->curr = '\0';
+
+ MPFR_ASSERTD (b->curr < b->start + b->size);
+ }
- mpfr_free_str (s);
- return length;
+ return 0;
+ }
}
/* Helper struct and functions for temporary strings management */
@@ -676,7 +758,7 @@ struct string_list
struct string_list *next; /* NULL in last node */
};
-/* initialisation */
+/* initialization */
static void
init_string_list (struct string_list *sl)
{
@@ -695,7 +777,7 @@ clear_string_list (struct string_list *sl)
if (sl->string)
mpfr_free_str (sl->string);
n = sl->next;
- (*__gmp_free_func) (sl, sizeof(struct string_list));
+ mpfr_free_func (sl, sizeof(struct string_list));
sl = n;
}
}
@@ -709,7 +791,7 @@ register_string (struct string_list *sl, char *new_string)
sl = sl->next;
sl->next = (struct string_list*)
- (*__gmp_allocate_func) (sizeof (struct string_list));
+ mpfr_allocate_func (sizeof (struct string_list));
sl = sl->next;
sl->next = NULL;
@@ -832,6 +914,52 @@ floor_log10 (mpfr_srcptr x)
return exp;
}
+#define NDIGITS 8
+
+static char*
+mpfr_get_str_aux (mpfr_exp_t *exp, int base, size_t n, const mpfr_t op,
+ const struct printf_spec spec)
+{
+ size_t ndigits;
+ char *str, *s, nine;
+ int neg;
+
+ if (spec.size != 0)
+ return mpfr_get_str (NULL, exp, base, n, op, spec.rnd_mode);
+
+ /* Special case size = 0, i.e., xxx_snprintf with size = 0: we only want
+ to compute the number of printed characters. Try to deduce it from
+ a small number of significant digits. */
+ nine = (base <= 10) ? '0' + base - 1
+ : (base <= 36) ? 'a' + base - 11
+ : 'a' + base - 37;
+ for (ndigits = NDIGITS; ; ndigits *= 2)
+ {
+ mpfr_rnd_t rnd = MPFR_RNDZ;
+ /* when ndigits > n, we reduce it to the target size n, and then we use
+ the wanted rounding mode, to avoid errors for example when n=1 and
+ x = 9.5 with spec.rnd_mode = RNDU */
+ if (ndigits >= n)
+ {
+ ndigits = n;
+ rnd = spec.rnd_mode;
+ }
+ str = mpfr_get_str (NULL, exp, base, ndigits, op, rnd);
+ if (ndigits == n)
+ break;
+ neg = str[0] == '-';
+ s = str + neg;
+ while (*s == nine)
+ s ++;
+ if (s < str + neg + ndigits) /* we don't have ndigits 'nines' */
+ break;
+ mpfr_free_str (str);
+ MPFR_ASSERTN (ndigits <= ((size_t) -1) / 2);
+ /* to make sure that the product by 2 is representable. */
+ }
+ return str;
+}
+
/* Determine the different parts of the string representation of the regular
number P when SPEC.SPEC is 'a', 'A', or 'b'.
@@ -857,7 +985,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
/* prefix part */
{
np->prefix_size = 2;
- str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
+ str = (char *) mpfr_allocate_func (1 + np->prefix_size);
str[0] = '0';
str[1] = uppercase ? 'X' : 'x';
str[2] = '\0';
@@ -875,9 +1003,11 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
/* Number of significant digits:
- if no given precision, let mpfr_get_str determine it;
- if a non-zero precision is specified, then one digit before decimal
- point plus SPEC.PREC after it. */
- nsd = spec.prec < 0 ? 0 : spec.prec + np->ip_size;
- str = mpfr_get_str (0, &exp, base, nsd, p, spec.rnd_mode);
+ point plus SPEC.PREC after it (which will give nsd > 1 below). */
+ MPFR_ASSERTD (np->ip_size == 1); /* thus no integer overflow below */
+ nsd = spec.prec < 0 ? 0 : (size_t) spec.prec + np->ip_size;
+ MPFR_ASSERTD (nsd != 1);
+ str = mpfr_get_str_aux (&exp, base, nsd, p, spec);
register_string (np->sl, str);
np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */
@@ -903,7 +1033,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
}
else if (next_base_power_p (p, base, spec.rnd_mode))
{
- str = (char *)(*__gmp_allocate_func) (2);
+ str = (char *)mpfr_allocate_func (2);
str[0] = '1';
str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
@@ -912,7 +1042,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
}
else if (base == 2)
{
- str = (char *)(*__gmp_allocate_func) (2);
+ str = (char *)mpfr_allocate_func (2);
str[0] = '1';
str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
@@ -933,9 +1063,9 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
|| (spec.rnd_mode == MPFR_RNDN
&& (msl & (MPFR_LIMB_ONE << rnd_bit))))
digit++;
- MPFR_ASSERTD ((0 <= digit) && (digit <= 15));
+ MPFR_ASSERTD (0 <= digit && digit <= 15);
- str = (char *)(*__gmp_allocate_func) (1 + np->ip_size);
+ str = (char *)mpfr_allocate_func (1 + np->ip_size);
str[0] = num_to_text [digit];
str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
@@ -988,7 +1118,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
if (spec.prec < 0)
/* remove trailing zeros, if any */
{
- while ((*ptr == '0') && (str_len != 0))
+ while (*ptr == '0' && str_len != 0)
{
--ptr;
--str_len;
@@ -1004,13 +1134,14 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
{
np->fp_ptr = str;
np->fp_size = str_len;
+ MPFR_ASSERTD (str_len > 0 && str_len <= INT_MAX);
if ((int) str_len < spec.prec)
np->fp_trailing_zeros = spec.prec - str_len;
}
}
/* decimal point */
- if ((np->fp_size != 0) || spec.alt)
+ if (np->fp_size != 0 || spec.alt)
np->point = MPFR_DECIMAL_POINT;
/* the exponent part contains the character 'p', or 'P' plus the sign
@@ -1028,7 +1159,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
x /= 10;
}
}
- str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
+ str = (char *) mpfr_allocate_func (1 + np->exp_size);
np->exp_ptr = register_string (np->sl, str);
{
char exp_fmt[8]; /* contains at most 7 characters like in "p%+.1i",
@@ -1047,7 +1178,7 @@ regular_ab (struct number_parts *np, mpfr_srcptr p,
/* Determine the different parts of the string representation of the regular
number P when spec.spec is 'e', 'E', 'g', or 'G'.
- DEC_INFO contains the previously computed exponent and string or is NULL.
+ dec_info contains the previously computed exponent and string or is NULL.
return -1 if some field > INT_MAX */
static int
@@ -1080,8 +1211,9 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
plus SPEC.PREC after it.
We use the fact here that mpfr_get_str allows us to ask for only one
significant digit when the base is not a power of 2. */
- nsd = (spec.prec < 0) ? 0 : spec.prec + np->ip_size;
- str = mpfr_get_str (0, &exp, 10, nsd, p, spec.rnd_mode);
+ MPFR_ASSERTD (np->ip_size == 1); /* thus no integer overflow below */
+ nsd = spec.prec < 0 ? 0 : (size_t) spec.prec + np->ip_size;
+ str = mpfr_get_str_aux (&exp, 10, nsd, p, spec);
register_string (np->sl, str);
}
else
@@ -1105,7 +1237,7 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
if (!keep_trailing_zeros)
/* remove trailing zeros, if any */
{
- while ((*ptr == '0') && (str_len != 0))
+ while (*ptr == '0' && str_len != 0)
{
--ptr;
--str_len;
@@ -1121,8 +1253,9 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
{
np->fp_ptr = str;
np->fp_size = str_len;
- if ((!spec_g || spec.alt) && (spec.prec > 0)
- && ((int)str_len < spec.prec))
+ MPFR_ASSERTD (str_len > 0 && str_len <= INT_MAX);
+ if ((!spec_g || spec.alt) && spec.prec > 0
+ && (int) str_len < spec.prec)
/* add missing trailing zeros */
np->fp_trailing_zeros = spec.prec - str_len;
}
@@ -1155,7 +1288,7 @@ regular_eg (struct number_parts *np, mpfr_srcptr p,
if (np->exp_size < 4)
np->exp_size = 4;
- str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
+ str = (char *) mpfr_allocate_func (1 + np->exp_size);
np->exp_ptr = register_string (np->sl, str);
{
@@ -1201,7 +1334,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
{
/* Most of the time, integral part is 0 */
np->ip_size = 1;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
+ str = (char *) mpfr_allocate_func (1 + np->ip_size);
str[0] = '0';
str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
@@ -1234,20 +1367,28 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
switch (spec.rnd_mode)
{
case MPFR_RNDA:
+ case MPFR_RNDF: /* round_away = 1 needed for spec_g */
round_away = 1;
break;
+ case MPFR_RNDZ:
+ round_away = 0;
+ break;
case MPFR_RNDD:
round_away = MPFR_IS_NEG (p);
break;
case MPFR_RNDU:
round_away = MPFR_IS_POS (p);
break;
- case MPFR_RNDN:
+ default:
{
/* compare |p| to y = 0.5*10^(-spec.prec) */
mpfr_t y;
mpfr_exp_t e = MAX (MPFR_PREC (p), 56);
+ int cmp;
+
+ MPFR_ASSERTN (spec.rnd_mode == MPFR_RNDN);
mpfr_init2 (y, e + 8);
+
do
{
/* find a lower approximation of
@@ -1257,14 +1398,14 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
mpfr_set_si (y, -spec.prec, MPFR_RNDN);
mpfr_exp10 (y, y, MPFR_RNDD);
mpfr_div_2ui (y, y, 1, MPFR_RNDN);
- } while (mpfr_cmpabs (y, p) == 0);
+ cmp = mpfr_cmpabs (y, p);
+ }
+ while (cmp == 0);
- round_away = mpfr_cmpabs (y, p) < 0;
+ round_away = cmp < 0;
mpfr_clear (y);
}
break;
- default:
- round_away = 0;
}
if (round_away)
@@ -1274,7 +1415,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
np->fp_size = 1;
str =
- (char *) (*__gmp_allocate_func) (1 + np->fp_size);
+ (char *) mpfr_allocate_func (1 + np->fp_size);
str[0] = '1';
str[1] = '\0';
np->fp_ptr = register_string (np->sl, str);
@@ -1286,21 +1427,31 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
np->fp_leading_zeros = spec.prec;
}
}
- else
+ else /* exp >= -spec.prec */
/* the most significant digits are the last
spec.prec + exp + 1 digits in fractional part */
{
char *ptr;
size_t str_len;
+
+ MPFR_ASSERTD (exp >= -spec.prec);
if (dec_info == NULL)
{
- size_t nsd = spec.prec + exp + 1;
+ size_t nsd;
+
+ /* Consequences of earlier assertions (in r11307).
+ They guarantee that the integers are representable
+ (i.e., no integer overflow), assuming size_t >= int
+ as usual. */
+ MPFR_ASSERTD (exp <= -1);
+ MPFR_ASSERTD (spec.prec + (exp + 1) >= 0);
+ nsd = spec.prec + (exp + 1);
/* WARNING: nsd may equal 1, but here we use the
fact that mpfr_get_str can return one digit with
base ten (undocumented feature, see comments in
get_str.c) */
- str = mpfr_get_str (NULL, &exp, 10, nsd, p, spec.rnd_mode);
+ str = mpfr_get_str_aux (&exp, 10, nsd, p, spec);
register_string (np->sl, str);
}
else
@@ -1331,7 +1482,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
if (!keep_trailing_zeros)
/* remove trailing zeros, if any */
{
- while ((*ptr == '0') && str_len)
+ while (*ptr == '0' && str_len != 0)
{
--ptr;
--str_len;
@@ -1373,8 +1524,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
if (dec_info == NULL)
{ /* this case occurs with mpfr_printf ("%.0RUf", x) with x=9.5 */
- str =
- mpfr_get_str (NULL, &exp, 10, spec.prec+exp+1, p, spec.rnd_mode);
+ str = mpfr_get_str_aux (&exp, 10, spec.prec+exp+1, p, spec);
register_string (np->sl, str);
}
else
@@ -1408,7 +1558,7 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
{
char *ptr = str + str_len - 1; /* pointer to the last digit of
str */
- while ((*ptr == '0') && (str_len != 0))
+ while (*ptr == '0' && str_len != 0)
{
--ptr;
--str_len;
@@ -1447,9 +1597,9 @@ regular_fg (struct number_parts *np, mpfr_srcptr p,
partition_number initializes the given structure np, so all previous
information in that variable is lost.
return the total number of characters to be written.
- return -1 if an error occured, in that case np's fields are in an undefined
+ return -1 if an error occurred, in that case np's fields are in an undefined
state but all string buffers have been freed. */
-static int
+static mpfr_intmax_t
partition_number (struct number_parts *np, mpfr_srcptr p,
struct printf_spec spec)
{
@@ -1475,7 +1625,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
np->exp_ptr = NULL;
np->exp_size = 0;
np->sl = (struct string_list *)
- (*__gmp_allocate_func) (sizeof (struct string_list));
+ mpfr_allocate_func (sizeof (struct string_list));
init_string_list (np->sl);
uppercase = spec.spec == 'A' || spec.spec == 'E' || spec.spec == 'F'
@@ -1490,20 +1640,10 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
with left spaces instead */
np->pad_type = LEFT;
- if (uppercase)
- {
- np->ip_size = MPFR_NAN_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, MPFR_NAN_STRING_UC);
- np->ip_ptr = register_string (np->sl, str);
- }
- else
- {
- np->ip_size = MPFR_NAN_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, MPFR_NAN_STRING_LC);
- np->ip_ptr = register_string (np->sl, str);
- }
+ np->ip_size = MPFR_NAN_STRING_LENGTH;
+ str = (char *) mpfr_allocate_func (1 + np->ip_size);
+ strcpy (str, uppercase ? MPFR_NAN_STRING_UC : MPFR_NAN_STRING_LC);
+ np->ip_ptr = register_string (np->sl, str);
}
else if (MPFR_IS_INF (p))
{
@@ -1515,24 +1655,14 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
if (MPFR_IS_NEG (p))
np->sign = '-';
- if (uppercase)
- {
- np->ip_size = MPFR_INF_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, MPFR_INF_STRING_UC);
- np->ip_ptr = register_string (np->sl, str);
- }
- else
- {
- np->ip_size = MPFR_INF_STRING_LENGTH;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
- strcpy (str, MPFR_INF_STRING_LC);
- np->ip_ptr = register_string (np->sl, str);
- }
+ np->ip_size = MPFR_INF_STRING_LENGTH;
+ str = (char *) mpfr_allocate_func (1 + np->ip_size);
+ strcpy (str, uppercase ? MPFR_INF_STRING_UC : MPFR_INF_STRING_LC);
+ np->ip_ptr = register_string (np->sl, str);
}
else
- /* p == 0 */
{
+ MPFR_ASSERTD (MPFR_IS_ZERO (p));
/* note: for 'g' spec, zero is always displayed with 'f'-style with
precision spec.prec - 1 and the trailing zeros are removed unless
the flag '#' is used. */
@@ -1546,7 +1676,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* prefix part */
{
np->prefix_size = 2;
- str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
+ str = (char *) mpfr_allocate_func (1 + np->prefix_size);
str[0] = '0';
str[1] = uppercase ? 'X' : 'x';
str[2] = '\0';
@@ -1555,7 +1685,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* integral part */
np->ip_size = 1;
- str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
+ str = (char *) mpfr_allocate_func (1 + np->ip_size);
str[0] = '0';
str[1] = '\0';
np->ip_ptr = register_string (np->sl, str);
@@ -1576,7 +1706,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* exponent part */
{
np->exp_size = (spec.spec == 'e' || spec.spec == 'E') ? 4 : 3;
- str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
+ str = (char *) mpfr_allocate_func (1 + np->exp_size);
if (spec.spec == 'e' || spec.spec == 'E')
strcpy (str, uppercase ? "E+00" : "e+00");
else
@@ -1585,9 +1715,27 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
}
}
}
+ else if (MPFR_UNLIKELY (MPFR_IS_UBF (p)))
+ {
+ /* mpfr_get_str does not support UBF, so that UBF numbers are regarded
+ as special cases here. This is not much a problem since UBF numbers
+ are internal to MPFR and here, they only for logging. */
+ if (np->pad_type == LEADING_ZEROS)
+ /* change to right justification padding with left spaces */
+ np->pad_type = LEFT;
+
+ if (MPFR_IS_NEG (p))
+ np->sign = '-';
+
+ np->ip_size = 3;
+ str = (char *) mpfr_allocate_func (1 + np->ip_size);
+ strcpy (str, uppercase ? "UBF" : "ubf");
+ np->ip_ptr = register_string (np->sl, str);
+ /* TODO: output more information (e.g. the exponent) if need be. */
+ }
else
- /* regular p, p != 0 */
{
+ MPFR_ASSERTD (MPFR_IS_PURE_FP (p));
if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b')
{
if (regular_ab (np, p, spec) == -1)
@@ -1616,12 +1764,38 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
where T is the threshold computed below and X is the exponent
that would be displayed with style 'e' and precision T-1. */
int threshold;
- mpfr_exp_t x;
+ mpfr_exp_t x, e, k;
struct decimal_info dec_info;
threshold = (spec.prec < 0) ? 6 : (spec.prec == 0) ? 1 : spec.prec;
- dec_info.str = mpfr_get_str (NULL, &dec_info.exp, 10, threshold,
- p, spec.rnd_mode);
+
+ /* Here we cannot call mpfr_get_str_aux since we need the full
+ significand in dec_info.str.
+ Moreover, threshold may be huge while one can know that the
+ number of digits that are not trailing zeros remains limited;
+ such a limit occurs in practical cases, e.g. with numbers
+ representable in the IEEE 754-2008 basic formats. Since the
+ trailing zeros are not necessarily output, we do not want to
+ waste time and memory by making mpfr_get_str generate them.
+ So, let us try to find a smaller threshold for mpfr_get_str.
+ |p| < 2^EXP(p) = 10^(EXP(p)*log10(2)). So, the integer part
+ takes at most ceil(EXP(p)*log10(2)) digits (unless p rounds
+ to the next power of 10, but in this case any threshold will
+ be OK). So, for the integer part, we will take:
+ max(0,floor((EXP(p)+2)/3)).
+ Let k = PREC(p) - EXP(p), so that the last bit of p has
+ weight 2^(-k). If k <= 0, then p is an integer, otherwise
+ the fractional part in base 10 may have up to k digits
+ (this bound is reached if the last bit is 1).
+ Note: The bound could be improved, but this is not critical. */
+ e = MPFR_GET_EXP (p);
+ k = MPFR_PREC (p) - e;
+ e = e <= 0 ? k : (e + 2) / 3 + (k <= 0 ? 0 : k);
+ MPFR_ASSERTD (e >= 1);
+
+ dec_info.str = mpfr_get_str (NULL, &dec_info.exp, 10,
+ e < threshold ? e : threshold,
+ p, spec.rnd_mode);
register_string (np->sl, dec_info.str);
/* mpfr_get_str corresponds to a significand between 0.1 and 1,
whereas here we want a significand between 1 and 10. */
@@ -1648,14 +1822,14 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
/* compute the number of characters to be written verifying it is not too
much */
-#define INCR_TOTAL(v) \
- do { \
- MPFR_ASSERTD ((v) >= 0); \
- if (MPFR_UNLIKELY ((v) > INT_MAX)) \
- goto error; \
- total += (v); \
- if (MPFR_UNLIKELY (total > INT_MAX)) \
- goto error; \
+#define INCR_TOTAL(v) \
+ do { \
+ MPFR_ASSERTD ((v) >= 0); \
+ if (MPFR_UNLIKELY ((v) > MPFR_INTMAX_MAX)) \
+ goto error; \
+ total += (v); \
+ if (MPFR_UNLIKELY (total > MPFR_INTMAX_MAX)) \
+ goto error; \
} while (0)
total = np->sign ? 1 : 0;
@@ -1683,7 +1857,7 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
MPFR_ASSERTD (total == spec.width);
}
- MPFR_ASSERTD (total > 0 && total <= INT_MAX);
+ MPFR_ASSERTD (total > 0 && total <= MPFR_INTMAX_MAX);
return total;
error:
@@ -1699,17 +1873,33 @@ partition_number (struct number_parts *np, mpfr_srcptr p,
return the size of the string (not counting the terminating '\0')
return -1 if the built string is too long (i.e. has more than
- INT_MAX characters). */
+ INT_MAX or MPFR_INTMAX_MAX characters).
+
+ If spec.size is 0, we only want the size of the string.
+*/
static int
sprnt_fp (struct string_buffer *buf, mpfr_srcptr p,
const struct printf_spec spec)
{
- int length;
+ mpfr_intmax_t length, start;
struct number_parts np;
length = partition_number (&np, p, spec);
if (length < 0)
- return -1;
+ {
+ buf->len = -1;
+ return -1;
+ }
+
+ if (spec.size == 0)
+ {
+ /* This is equivalent to the following code (no need to fill the buffer
+ and length is known). */
+ buffer_incr_len (buf, length);
+ goto clear_and_exit;
+ }
+
+ MPFR_DBGRES (start = buf->len);
/* right justification padding with left spaces */
if (np.pad_type == LEFT && np.pad_size != 0)
@@ -1761,19 +1951,32 @@ sprnt_fp (struct string_buffer *buf, mpfr_srcptr p,
if (np.exp_ptr)
buffer_cat (buf, np.exp_ptr, np.exp_size);
- /* left justication padding with right spaces */
+ /* left justification padding with right spaces */
if (np.pad_type == RIGHT && np.pad_size != 0)
buffer_pad (buf, ' ', np.pad_size);
+ MPFR_ASSERTD (buf->len == -1 || buf->len - start == length);
+
+ clear_and_exit:
clear_string_list (np.sl);
- return length;
+ return buf->len == -1 ? -1 : length;
}
+/* The following internal function implements both mpfr_vasprintf and
+ mpfr_vsnprintf:
+ (a) either ptr <> NULL, and then Buf and size are not used, and it
+ implements mpfr_vasprintf (ptr, fmt, ap)
+ (b) or ptr = NULL, and it implements mpfr_vsnprintf (Buf, size, fmt, ap)
+ It returns the number of characters that would have been written had 'size'
+ been sufficiently large, not counting the terminating null character, or -1
+ if this number is too large for the return type 'int' (overflow).
+*/
int
-mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
+mpfr_vasnprintf_aux (char **ptr, char *Buf, size_t size, const char *fmt,
+ va_list ap)
{
struct string_buffer buf;
- size_t nbchar;
+ int nbchar;
/* informations on the conversion specification filled by the parser */
struct printf_spec spec;
@@ -1788,15 +1991,14 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
MPFR_SAVE_EXPO_DECL (expo);
MPFR_SAVE_EXPO_MARK (expo);
- nbchar = 0;
- buffer_init (&buf, 4096);
+ buffer_init (&buf, ptr != NULL || size != 0 ? 4096 : 0);
xgmp_fmt_flag = 0;
va_copy (ap2, ap);
start = fmt;
- while (*fmt)
+ while (*fmt != '\0')
{
/* Look for the next format specification */
- while ((*fmt) && (*fmt != '%'))
+ while (*fmt != '\0' && *fmt != '%')
++fmt;
if (*fmt == '\0')
@@ -1839,10 +2041,12 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
fmt = parse_arg_type (fmt, &spec);
if (spec.arg_type == UNSUPPORTED)
- /* the current architecture doesn't support this type */
- {
- goto error;
- }
+ /* the current architecture doesn't support the type corresponding to
+ the format specifier; according to the ISO C99 standard, the
+ behavior is undefined. We choose to print the format specifier as a
+ literal string, what may be printed after this string is
+ undefined. */
+ continue;
else if (spec.arg_type == MPFR_ARG)
{
switch (*fmt)
@@ -1878,9 +2082,13 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
spec.spec = *fmt;
if (!specinfo_is_valid (spec))
- goto error;
+ /* the format specifier is invalid; according to the ISO C99 standard,
+ the behavior is undefined. We choose to print the invalid format
+ specifier as a literal string, what may be printed after this
+ string is undefined. */
+ continue;
- if (*fmt)
+ if (*fmt != '\0')
fmt++;
/* Format processing */
@@ -1894,49 +2102,47 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
so as to be able to accept the same format strings. */
{
void *p;
- size_t nchar;
p = va_arg (ap, void *);
FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
va_end (ap2);
start = fmt;
- nchar = buf.curr - buf.start;
switch (spec.arg_type)
{
case CHAR_ARG:
- *(char *) p = (char) nchar;
+ *(char *) p = (char) buf.len;
break;
case SHORT_ARG:
- *(short *) p = (short) nchar;
+ *(short *) p = (short) buf.len;
break;
case LONG_ARG:
- *(long *) p = (long) nchar;
+ *(long *) p = (long) buf.len;
break;
#ifdef HAVE_LONG_LONG
case LONG_LONG_ARG:
- *(long long *) p = (long long) nchar;
+ *(long long *) p = (long long) buf.len;
break;
#endif
#ifdef _MPFR_H_HAVE_INTMAX_T
case INTMAX_ARG:
- *(intmax_t *) p = (intmax_t) nchar;
+ *(intmax_t *) p = (intmax_t) buf.len;
break;
#endif
case SIZE_ARG:
- *(size_t *) p = nchar;
+ *(size_t *) p = buf.len;
break;
case PTRDIFF_ARG:
- *(ptrdiff_t *) p = (ptrdiff_t) nchar;
+ *(ptrdiff_t *) p = (ptrdiff_t) buf.len;
break;
case MPF_ARG:
- mpf_set_ui ((mpf_ptr) p, (unsigned long) nchar);
+ mpf_set_ui ((mpf_ptr) p, (unsigned long) buf.len);
break;
case MPQ_ARG:
- mpq_set_ui ((mpq_ptr) p, (unsigned long) nchar, 1L);
+ mpq_set_ui ((mpq_ptr) p, (unsigned long) buf.len, 1L);
break;
case MP_LIMB_ARG:
- *(mp_limb_t *) p = (mp_limb_t) nchar;
+ *(mp_limb_t *) p = (mp_limb_t) buf.len;
break;
case MP_LIMB_ARRAY_ARG:
{
@@ -1949,25 +2155,25 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
break;
/* we assume here that mp_limb_t is wider than int */
- *q = (mp_limb_t) nchar;
+ *q = (mp_limb_t) buf.len;
while (--n != 0)
{
q++;
- *q = (mp_limb_t) 0;
+ *q = MPFR_LIMB_ZERO;
}
}
break;
case MPZ_ARG:
- mpz_set_ui ((mpz_ptr) p, (unsigned long) nchar);
+ mpz_set_ui ((mpz_ptr) p, (unsigned long) buf.len);
break;
case MPFR_ARG:
- mpfr_set_ui ((mpfr_ptr) p, (unsigned long) nchar,
+ mpfr_set_ui ((mpfr_ptr) p, (unsigned long) buf.len,
spec.rnd_mode);
break;
default:
- *(int *) p = (int) nchar;
+ *(int *) p = (int) buf.len;
}
va_copy (ap2, ap); /* after the switch, due to MP_LIMB_ARRAY_ARG
case */
@@ -1979,6 +2185,7 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
char format[MPFR_PREC_FORMAT_SIZE + 6]; /* see examples below */
size_t length;
mpfr_prec_t prec;
+
prec = va_arg (ap, mpfr_prec_t);
FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
@@ -1996,22 +2203,25 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
format[4 + MPFR_PREC_FORMAT_SIZE] = spec.spec;
format[5 + MPFR_PREC_FORMAT_SIZE] = '\0';
length = gmp_asprintf (&s, format, spec.width, spec.prec, prec);
- if (buf.size <= INT_MAX - length)
- {
- buffer_cat (&buf, s, length);
- mpfr_free_str (s);
- }
- else
- {
- mpfr_free_str (s);
- goto overflow_error;
- }
+ MPFR_ASSERTN (length >= 0); /* guaranteed by GMP 6 */
+ buffer_cat (&buf, s, length);
+ mpfr_free_str (s);
}
else if (spec.arg_type == MPFR_ARG)
/* output a mpfr_t variable */
{
mpfr_srcptr p;
+ if (spec.spec != 'a' && spec.spec != 'A'
+ && spec.spec != 'b'
+ && spec.spec != 'e' && spec.spec != 'E'
+ && spec.spec != 'f' && spec.spec != 'F'
+ && spec.spec != 'g' && spec.spec != 'G')
+ /* the format specifier is invalid; skip the invalid format
+ specifier so as to print it as a literal string. What may be
+ printed after this string is undefined. */
+ continue;
+
p = va_arg (ap, mpfr_srcptr);
FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
@@ -2019,25 +2229,9 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
va_copy (ap2, ap);
start = fmt;
- switch (spec.spec)
- {
- case 'a':
- case 'A':
- case 'b':
- case 'e':
- case 'E':
- case 'f':
- case 'F':
- case 'g':
- case 'G':
- if (sprnt_fp (&buf, p, spec) < 0)
- goto overflow_error;
- break;
-
- default:
- /* unsupported specifier */
- goto error;
- }
+ if (ptr == NULL)
+ spec.size = size;
+ sprnt_fp (&buf, p, spec);
}
else
/* gmp_printf specification, step forward in the va_list */
@@ -2051,42 +2245,63 @@ mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
FLUSH (xgmp_fmt_flag, start, fmt, ap2, &buf);
va_end (ap2);
- nbchar = buf.curr - buf.start;
- MPFR_ASSERTD (nbchar == strlen (buf.start));
- buf.start =
- (char *) (*__gmp_reallocate_func) (buf.start, buf.size, nbchar + 1);
- buf.size = nbchar + 1; /* update needed for __gmp_free_func below when
- nbchar is too large (overflow_error) */
- *ptr = buf.start;
-
- /* If nbchar is larger than INT_MAX, the ISO C99 standard is silent, but
- POSIX says concerning the snprintf() function:
- "[EOVERFLOW] The value of n is greater than {INT_MAX} or the
- number of bytes needed to hold the output excluding the
- terminating null is greater than {INT_MAX}." See:
- http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
- But it doesn't say anything concerning the other printf-like functions.
- A defect report has been submitted to austin-review-l (item 2532).
- So, for the time being, we return a negative value and set the erange
- flag, and set errno to EOVERFLOW in POSIX system. */
- if (nbchar <= INT_MAX)
+
+ if (buf.len > INT_MAX) /* overflow */
+ buf.len = -1;
+
+ if (buf.len != -1)
{
+ nbchar = buf.len;
+ MPFR_ASSERTD (nbchar >= 0);
+
+ if (ptr != NULL) /* implement mpfr_vasprintf */
+ {
+ MPFR_ASSERTD (nbchar == strlen (buf.start));
+ *ptr = (char *)
+ mpfr_reallocate_func (buf.start, buf.size, nbchar + 1);
+ }
+ else if (size > 0) /* implement mpfr_vsnprintf */
+ {
+ if (nbchar < size)
+ {
+ strncpy (Buf, buf.start, nbchar);
+ Buf[nbchar] = '\0';
+ }
+ else
+ {
+ strncpy (Buf, buf.start, size - 1);
+ Buf[size-1] = '\0';
+ }
+ mpfr_free_func (buf.start, buf.size);
+ }
+
MPFR_SAVE_EXPO_FREE (expo);
- return nbchar;
+ return nbchar; /* return the number of characters that would have
+ been written had 'size' been sufficiently large,
+ not counting the terminating null character */
}
- overflow_error:
- MPFR_SAVE_EXPO_UPDATE_FLAGS(expo, MPFR_FLAGS_ERANGE);
+ error:
+ if (buf.len == -1) /* overflow */
+ {
+ MPFR_LOG_MSG (("Overflow\n", 0));
+ MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_ERANGE);
#ifdef EOVERFLOW
- errno = EOVERFLOW;
+ MPFR_LOG_MSG (("Setting errno to EOVERFLOW\n", 0));
+ errno = EOVERFLOW;
#endif
+ }
- error:
MPFR_SAVE_EXPO_FREE (expo);
*ptr = NULL;
- (*__gmp_free_func) (buf.start, buf.size);
+ mpfr_free_func (buf.start, buf.size);
return -1;
}
+#else /* HAVE_STDARG */
+
+/* Avoid an empty translation unit (see ISO C99, 6.9) */
+typedef int foo;
+
#endif /* HAVE_STDARG */