diff options
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-src/src/vasprintf.c')
-rw-r--r-- | Build/source/libs/mpfr/mpfr-src/src/vasprintf.c | 787 |
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 */ |