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 | 2456 |
1 files changed, 0 insertions, 2456 deletions
diff --git a/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c b/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c deleted file mode 100644 index 6173f149c97..00000000000 --- a/Build/source/libs/mpfr/mpfr-src/src/vasprintf.c +++ /dev/null @@ -1,2456 +0,0 @@ -/* mpfr_vasnprintf_aux -- helper function for the formatted output functions - (printf functions family). - -Copyright 2007-2020 Free Software Foundation, Inc. -Contributed by the AriC and Caramba projects, INRIA. - -This file is part of the GNU MPFR Library. - -The GNU MPFR Library is free software; you can redistribute it and/or modify -it under the terms of the GNU Lesser General Public License as published by -the Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -The GNU MPFR Library is distributed in the hope that it will be useful, but -WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY -or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public -License for more details. - -You should have received a copy of the GNU Lesser General Public License -along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see -https://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 / C11 standards are silent, but POSIX[*] requires the - function to return a negative value and set errno to EOVERFLOW. - [*] The Open Group Base Specifications Issue 7, 2018 edition - IEEE Std 1003.1-2017 (Revision of IEEE Std 1003.1-2008) - http://pubs.opengroup.org/onlinepubs/9699919799/functions/fprintf.html - This follows a defect report submitted in 2007 to austin-review-l. - Even in case of such a failure (just because of the limitation on int), - we try to support %n, %ln, %jn when possible. That's why the sizes (or - lengths) are expressed using mpfr_intmax_t in the code below. */ - -/* Notes about limitations on some platforms: - - 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). - - The stdarg(3) Linux man page says: - On some systems, va_end contains a closing '}' matching a '{' in - va_start, so that both macros must occur in the same function, - and in a way that allows this. - However, the only requirement from ISO C is that both macros must be - invoked in the same function (MPFR uses va_copy instead of va_start, - but the requirement is the same). Here, MPFR just follows ISO C. -*/ - -/* Needed due to the tests on HAVE_STDARG and MPFR_USE_MINI_GMP */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -/* 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> - -#ifndef HAVE_VA_COPY -# ifdef HAVE___VA_COPY -# define va_copy(dst,src) __va_copy(dst, src) -# else -/* autoconf manual advocates this fallback. - This is also the solution chosen by gmp */ -# define va_copy(dst,src) \ - do { memcpy(&(dst), &(src), sizeof(va_list)); } while (0) -# endif /* HAVE___VA_COPY */ -#endif /* HAVE_VA_COPY */ - -#ifdef HAVE_WCHAR_H -#include <wchar.h> -#endif - -#if defined (__cplusplus) -#include <cstddef> -#else -#include <stddef.h> /* for ptrdiff_t */ -#endif - -#include <errno.h> - -#define MPFR_NEED_LONGLONG_H -#define MPFR_NEED_INTMAX_H -#include "mpfr-impl.h" - -/* Define a length modifier corresponding to mpfr_prec_t. - We use literal string instead of literal character so as to permit future - extension to long long int ("ll"). */ -#if _MPFR_PREC_FORMAT == 1 -#define MPFR_PREC_FORMAT_TYPE "h" -#define MPFR_PREC_FORMAT_SIZE 1 -#elif _MPFR_PREC_FORMAT == 2 -#define MPFR_PREC_FORMAT_TYPE "" -#define MPFR_PREC_FORMAT_SIZE 0 -#elif _MPFR_PREC_FORMAT == 3 -#define MPFR_PREC_FORMAT_TYPE "l" -#define MPFR_PREC_FORMAT_SIZE 1 -#else -#error "mpfr_prec_t size not supported" -#endif - -/* Output for special values defined in the C99 standard */ -#define MPFR_NAN_STRING_LC "nan" -#define MPFR_NAN_STRING_UC "NAN" -#define MPFR_NAN_STRING_LENGTH 3 -#define MPFR_INF_STRING_LC "inf" -#define MPFR_INF_STRING_UC "INF" -#define MPFR_INF_STRING_LENGTH 3 - -#define DEFAULT_DECIMAL_PREC 6 - -/* The implicit \0 is useless, but we do not write num_to_text[16] - otherwise g++ complains. */ -static const char num_to_text[] = "0123456789abcdef"; - -/* some macro and functions for parsing format string */ - -/* Read an integer var of type mpfr_intmax_t. In case of overflow, set - overflow to 1. - Note: Since mpfr_intmax_t = int is theoretically possible, all values - of var are potentially valid values (via '*'). Hence the need of an - overflow flag instead of a special value that would indicate overflow. - Saturating would not be OK either as the maximum value could be - meaningful with %jn and/or in the case mpfr_intmax_t = int, for - MPFR_PREC_ARG. -*/ -#define READ_INT(ap, format, var) \ - do { \ - MPFR_ASSERTD ((var) == 0); \ - if (*(format) == '*') \ - { \ - (var) = va_arg ((ap), int); \ - ++(format); \ - } \ - else \ - for ( ; *(format) >= '0' && *(format) <= '9' ; ++(format)) \ - if (!(overflow)) \ - { \ - if ((var) > MPFR_INTMAX_MAX / 10) \ - (overflow) = 1; \ - else \ - { \ - int _i; \ - (var) *= 10; \ - _i = *(format) - '0'; \ - MPFR_ASSERTN (_i >= 0 && _i <= 9); \ - if ((var) > MPFR_INTMAX_MAX - _i) \ - (overflow) = 1; \ - else \ - (var) += _i; \ - } \ - } \ - } while (0) - -/* arg_t contains all the types described by the 'type' field of the - format string */ -enum arg_t - { - NONE, - CHAR_ARG, - SHORT_ARG, - LONG_ARG, - LONG_LONG_ARG, - INTMAX_ARG, - SIZE_ARG, - PTRDIFF_ARG, - LONG_DOUBLE_ARG, - MPF_ARG, - MPQ_ARG, - MP_LIMB_ARG, - MP_LIMB_ARRAY_ARG, - MPZ_ARG, - MPFR_PREC_ARG, - MPFR_ARG, - UNSUPPORTED - }; - -/* Each conversion specification of the format string will be translated in a - printf_spec structure by the parser. - This structure is adapted from the GNU libc one. */ -struct printf_spec -{ - unsigned int alt:1; /* # flag */ - unsigned int space:1; /* Space flag */ - unsigned int left:1; /* - flag */ - unsigned int showsign:1; /* + flag */ - unsigned int group:1; /* ' flag */ - - mpfr_intmax_t width; /* Width */ - mpfr_intmax_t prec; /* Precision, or negative if omitted */ - 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 */ - char spec; /* Conversion specifier */ - - char pad; /* Padding character */ -}; - -static void -specinfo_init (struct printf_spec *specinfo) -{ - specinfo->alt = 0; - specinfo->space = 0; - specinfo->left = 0; - specinfo->showsign = 0; - specinfo->group = 0; - specinfo->width = 0; - specinfo->prec = 0; - specinfo->size = 1; - specinfo->arg_type = NONE; - specinfo->rnd_mode = MPFR_RNDN; - specinfo->spec = '\0'; - specinfo->pad = ' '; -} - -#define FLOATING_POINT_ARG_TYPE(at) \ - ((at) == MPFR_ARG || (at) == MPF_ARG || (at) == LONG_DOUBLE_ARG) - -#define INTEGER_LIKE_ARG_TYPE(at) \ - ((at) == SHORT_ARG || (at) == LONG_ARG || (at) == LONG_LONG_ARG \ - || (at) == INTMAX_ARG || (at) == MPFR_PREC_ARG || (at) == MPZ_ARG \ - || (at) == MPQ_ARG || (at) == MP_LIMB_ARG || (at) == MP_LIMB_ARRAY_ARG \ - || (at) == CHAR_ARG || (at) == SIZE_ARG || (at) == PTRDIFF_ARG) - -static int -specinfo_is_valid (struct printf_spec spec) -{ - switch (spec.spec) - { - case 'n': - return -1; - - case 'a': case 'A': - case 'e': case 'E': - case 'f': case 'F': - case 'g': case 'G': - return (spec.arg_type == NONE - || FLOATING_POINT_ARG_TYPE (spec.arg_type)); - - case 'b': - return spec.arg_type == MPFR_ARG; - - case 'd': case 'i': - case 'u': case 'o': - case 'x': case 'X': - return (spec.arg_type == NONE - || INTEGER_LIKE_ARG_TYPE (spec.arg_type)); - - case 'c': - case 's': - return (spec.arg_type == NONE || spec.arg_type == LONG_ARG); - - case 'p': - return spec.arg_type == NONE; - - default: - return 0; - } -} - -/* Note: additional flags should be added to the MPFR_PREC_ARG code - for gmp_asprintf (when supported). */ -MPFR_RETURNS_NONNULL static const char * -parse_flags (const char *format, struct printf_spec *specinfo) -{ - while (*format) - { - switch (*format) - { - case '0': - specinfo->pad = '0'; - ++format; - break; - case '#': - specinfo->alt = 1; - ++format; - break; - case '+': - specinfo->showsign = 1; - ++format; - break; - case ' ': - specinfo->space = 1; - ++format; - break; - case '-': - specinfo->left = 1; - ++format; - break; - case '\'': - /* Single UNIX Specification for thousand separator */ - specinfo->group = 1; - ++format; - break; - default: - return format; - } - } - return format; -} - -MPFR_RETURNS_NONNULL static const char * -parse_arg_type (const char *format, struct printf_spec *specinfo) -{ - switch (*format) - { - case '\0': - break; - case 'h': - if (*++format == 'h') - { - ++format; - specinfo->arg_type = CHAR_ARG; - } - else - specinfo->arg_type = SHORT_ARG; - break; - case 'l': - if (*++format == 'l') - { - ++format; -#if defined (HAVE_LONG_LONG) - specinfo->arg_type = LONG_LONG_ARG; -#else - specinfo->arg_type = UNSUPPORTED; -#endif - break; - } - else - { - specinfo->arg_type = LONG_ARG; - break; - } - case 'j': - ++format; -#if defined(_MPFR_H_HAVE_INTMAX_T) - specinfo->arg_type = INTMAX_ARG; -#else - specinfo->arg_type = UNSUPPORTED; -#endif - break; - case 'z': - ++format; - specinfo->arg_type = SIZE_ARG; - break; - case 't': - ++format; - specinfo->arg_type = PTRDIFF_ARG; - break; - case 'L': - ++format; - specinfo->arg_type = LONG_DOUBLE_ARG; - break; - case 'F': - ++format; - specinfo->arg_type = MPF_ARG; - break; - case 'Q': - ++format; - specinfo->arg_type = MPQ_ARG; - break; - case 'M': - ++format; - /* The 'M' specifier was added in gmp 4.2.0 */ - specinfo->arg_type = MP_LIMB_ARG; - break; - case 'N': - ++format; - specinfo->arg_type = MP_LIMB_ARRAY_ARG; - break; - case 'Z': - ++format; - specinfo->arg_type = MPZ_ARG; - break; - - /* mpfr specific specifiers */ - case 'P': - ++format; - specinfo->arg_type = MPFR_PREC_ARG; - break; - case 'R': - ++format; - specinfo->arg_type = MPFR_ARG; - } - return format; -} - - -/* some macros and functions filling the buffer */ - -/* CONSUME_VA_ARG removes from va_list AP the type expected by SPECINFO */ - -/* With a C++ compiler wchar_t and enumeration in va_list are converted to - integer type : int, unsigned int, long or unsigned long (unfortunately, - this is implementation dependent). - We follow gmp which assumes in print/doprnt.c that wchar_t is converted - to int (because wchar_t <= int). - For wint_t, we assume that the case WINT_MAX < INT_MAX yields an - integer promotion. */ -#ifdef HAVE_WCHAR_H -#if defined(WINT_MAX) && WINT_MAX < INT_MAX -typedef int mpfr_va_wint; /* integer promotion */ -#else -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') \ - (void) va_arg ((ap), long); \ - else if ((specinfo).spec == 'c') \ - (void) va_arg ((ap), mpfr_va_wint); \ - else if ((specinfo).spec == 's') \ - (void) va_arg ((ap), int); /* we assume integer promotion */ \ - break; -#else -#define CASE_LONG_ARG(specinfo, ap) \ - case LONG_ARG: \ - (void) va_arg ((ap), long); \ - break; -#endif - -#if defined(_MPFR_H_HAVE_INTMAX_T) -#define CASE_INTMAX_ARG(specinfo, ap) \ - case INTMAX_ARG: \ - (void) va_arg ((ap), intmax_t); \ - break; -#else -#define CASE_INTMAX_ARG(specinfo, ap) -#endif - -#ifdef HAVE_LONG_LONG -#define CASE_LONG_LONG_ARG(specinfo, ap) \ - case LONG_LONG_ARG: \ - (void) va_arg ((ap), long long); \ - break; -#else -#define CASE_LONG_LONG_ARG(specinfo, ap) -#endif - -/* Note: (specinfo).width may be incorrect in case of overflow, - but it is not used by CONSUME_VA_ARG. */ -#define CONSUME_VA_ARG(specinfo, ap) \ - do { \ - switch ((specinfo).arg_type) \ - { \ - case CHAR_ARG: \ - case SHORT_ARG: \ - (void) va_arg ((ap), int); \ - break; \ - CASE_LONG_ARG (specinfo, ap) \ - CASE_LONG_LONG_ARG (specinfo, ap) \ - CASE_INTMAX_ARG (specinfo, ap) \ - case SIZE_ARG: \ - (void) va_arg ((ap), size_t); \ - break; \ - case PTRDIFF_ARG: \ - (void) va_arg ((ap), ptrdiff_t); \ - break; \ - case LONG_DOUBLE_ARG: \ - (void) va_arg ((ap), long double); \ - break; \ - case MPF_ARG: \ - (void) va_arg ((ap), mpf_srcptr); \ - break; \ - case MPQ_ARG: \ - (void) va_arg ((ap), mpq_srcptr); \ - break; \ - case MP_LIMB_ARG: \ - (void) va_arg ((ap), mp_limb_t); \ - break; \ - case MP_LIMB_ARRAY_ARG: \ - (void) va_arg ((ap), mpfr_limb_ptr); \ - (void) va_arg ((ap), mp_size_t); \ - break; \ - case MPZ_ARG: \ - (void) va_arg ((ap), mpz_srcptr); \ - break; \ - default: \ - switch ((specinfo).spec) \ - { \ - case 'd': \ - case 'i': \ - case 'o': \ - case 'u': \ - case 'x': \ - case 'X': \ - case 'c': \ - (void) va_arg ((ap), int); \ - break; \ - case 'f': \ - case 'F': \ - case 'e': \ - case 'E': \ - case 'g': \ - case 'G': \ - case 'a': \ - case 'A': \ - (void) va_arg ((ap), double); \ - break; \ - case 's': \ - (void) va_arg ((ap), char *); \ - break; \ - case 'p': \ - (void) va_arg ((ap), void *); \ - } \ - } \ - } while (0) - -/* Process the format part which does not deal with mpfr types, - 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. - FIXME: If buf.size = 0 or size != 0, gmp_vsnprintf should be called - instead of gmp_vasprintf, outputting data directly to the buffer - when applicable. -*/ -#define FLUSH(flag, start, end, ap, buf_ptr) \ - do { \ - const size_t n = (end) - (start); \ - if ((flag)) \ - /* previous specifiers are understood by gmp_printf */ \ - { \ - MPFR_TMP_DECL (marker); \ - 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'; \ - 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); \ - } \ - else if ((start) != (end)) \ - /* no conversion specification, just simple characters */ \ - 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) -{ - 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, mpfr_intmax_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)) - { - MPFR_LOG_MSG (("Overflow\n", 0)); - b->len = -1; - return 1; - } - else - { - b->len = newlen; - return 0; - } - } -} - -/* Increase buffer size by a number of character being the least multiple of - 4096 greater than len+1. */ -static void -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 (b->size < ((size_t) -1) - n); - - b->start = (char *) mpfr_reallocate_func (b->start, b->size, b->size + n); - b->size += n; - b->curr = b->start + pos; - - MPFR_ASSERTD (pos < b->size); - MPFR_ASSERTD (*b->curr == '\0'); -} - -/* Concatenate the first len characters of the string s to the buffer b and - 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 <= strlen (s)); - - if (buffer_incr_len (b, len)) - return 1; - - 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'); - } - - return 0; -} - -/* 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 mpfr_intmax_t n) -{ - MPFR_ASSERTD (n > 0); - - if (buffer_incr_len (b, n)) - return 1; - - if (b->size != 0) - { - MPFR_ASSERTD (*b->curr == '\0'); - - if (n > (size_t) -1 || b->size > ((size_t) -1) - n) - { - /* Reallocation will not be possible. Regard this as an overflow. */ - b->len = -1; - return 1; - } - - 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); - } - - 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 beginning and concatenate the result to the buffer b. - Assume c is not null (\0). Return non-zero if overflow. */ -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; - size_t size, q, r, fullsize, i; - char *oldcurr; - - MPFR_ASSERTD (b->size != 0); - MPFR_ASSERTD (tz == 0 || tz == 1); - - if (len <= ULONG_MAX) - MPFR_LOG_MSG (("len=%lu\n", (unsigned long) len)); - if (tz <= ULONG_MAX) - MPFR_LOG_MSG (("tz=%lu\n", (unsigned long) tz)); - - MPFR_ASSERTD (len <= strlen (str)); - MPFR_ASSERTD (c != '\0'); - - /* check that len + tz does not overflow */ - if (len > (size_t) -1 - tz) - return 1; - - size = len + tz; /* number of digits */ - MPFR_ASSERTD (size > 0); - - q = (size - 1) / step; /* number of separators C */ - r = ((size - 1) % step) + 1; /* number of digits in the leftmost block */ - MPFR_ASSERTD (r >= 1 && r <= step); - - /* check that size + q does not overflow */ - if (size > (size_t) -1 - q) - return 1; - - fullsize = size + q; /* number of digits and separators */ - - if (buffer_incr_len (b, fullsize)) - return 1; - - 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); - - MPFR_DBGRES (oldcurr = b->curr); - - /* first r significant digits (leftmost block) */ - if (r <= len) - { - memcpy (b->curr, str, r); - str += r; - len -= r; - } - else - { - MPFR_ASSERTD (r > len); - MPFR_ASSERTD (len < step); /* as a consequence */ - MPFR_ASSERTD (size <= step); /* as a consequence */ - MPFR_ASSERTD (q == 0); /* as a consequence */ - MPFR_ASSERTD (r == size); /* as a consequence */ - MPFR_ASSERTD (tz == 1); /* as a consequence */ - memcpy (b->curr, str, len); - *(b->curr + len) = '0'; /* trailing zero */ - /* We do not need to set len to 0 since it will not be read again - (q = 0, so that the loop below will have 0 iterations). */ - } - b->curr += r; - - for (i = 0; i < q; ++i) - { - *b->curr++ = c; - if (MPFR_LIKELY (len >= step)) - { - memcpy (b->curr, str, step); - len -= step; - str += step; - } - else - { - /* last digits */ - MPFR_ASSERTD (i == q - 1 && step - len == 1); - memcpy (b->curr, str, len); - *(b->curr + len) = '0'; /* trailing zero */ - } - b->curr += step; - } - - MPFR_ASSERTD (b->curr - oldcurr == fullsize); - - *b->curr = '\0'; - - MPFR_ASSERTD (b->curr < b->start + b->size); - - return 0; -} - -/* Helper struct and functions for temporary strings management */ -/* struct for easy string clearing */ -struct string_list -{ - char *string; - struct string_list *next; /* NULL in last node */ -}; - -/* initialization */ -static void -init_string_list (struct string_list *sl) -{ - sl->string = NULL; - sl->next = NULL; -} - -/* clear all strings in the list */ -static void -clear_string_list (struct string_list *sl) -{ - struct string_list *n; - - while (sl) - { - if (sl->string) - mpfr_free_str (sl->string); - n = sl->next; - mpfr_free_func (sl, sizeof(struct string_list)); - sl = n; - } -} - -/* add a string in the list */ -static char * -register_string (struct string_list *sl, char *new_string) -{ - /* look for the last node */ - while (sl->next) - sl = sl->next; - - sl->next = (struct string_list *) - mpfr_allocate_func (sizeof (struct string_list)); - - sl = sl->next; - sl->next = NULL; - return sl->string = new_string; -} - -/* padding type: where are the padding characters */ -enum pad_t - { - LEFT, /* spaces in left hand side for right justification */ - LEADING_ZEROS, /* padding with '0' characters in integral part */ - RIGHT /* spaces in right hand side for left justification */ - }; - -/* number_parts details how much characters are needed in each part of a float - print. */ -struct number_parts -{ - enum pad_t pad_type; /* Padding type */ - mpfr_intmax_t pad_size; /* Number of padding characters */ - - char sign; /* Sign character */ - - char *prefix_ptr; /* Pointer to prefix part */ - size_t prefix_size; /* Number of characters in *prefix_ptr */ - - char thousands_sep; /* Thousands separator (only with style 'f') */ - - char *ip_ptr; /* Pointer to integral part characters*/ - size_t ip_size; /* Number of digits in *ip_ptr */ - int ip_trailing_digits; /* Number of additional digits in integral part - (if spec.size != 0, this can only be a zero) */ - - char point; /* Decimal point character */ - - mpfr_intmax_t fp_leading_zeros; /* Number of additional leading zeros in - fractional part */ - char *fp_ptr; /* Pointer to fractional part characters */ - size_t fp_size; /* Number of digits in *fp_ptr */ - mpfr_intmax_t fp_trailing_zeros; /* Number of additional trailing zeros in - fractional part */ - - char *exp_ptr; /* Pointer to exponent part */ - size_t exp_size; /* Number of characters in *exp_ptr */ - - struct string_list *sl; /* List of string buffers in use: we need such a - mechanism because fp_ptr may point into the same - string as ip_ptr */ -}; - -/* For a real non zero number x, what is the base exponent f when rounding x - with rounding mode r to r(x) = m*b^f, where m is a digit and 1 <= m < b ? - Return non zero value if x is rounded up to b^f, return zero otherwise */ -static int -next_base_power_p (mpfr_srcptr x, int base, mpfr_rnd_t rnd) -{ - mpfr_prec_t nbits; - mp_limb_t pm; - mp_limb_t xm; - - MPFR_ASSERTD (MPFR_IS_PURE_FP (x)); - MPFR_ASSERTD (base == 2 || base == 16); - - /* Warning: the decimal point is AFTER THE FIRST DIGIT in this output - representation. */ - nbits = base == 2 ? 1 : 4; - - if (rnd == MPFR_RNDZ - || (rnd == MPFR_RNDD && MPFR_IS_POS (x)) - || (rnd == MPFR_RNDU && MPFR_IS_NEG (x)) - || MPFR_PREC (x) <= nbits) - /* no rounding when printing x with 1 digit */ - return 0; - - xm = MPFR_MANT (x) [MPFR_LIMB_SIZE (x) - 1]; - pm = MPFR_LIMB_MASK (GMP_NUMB_BITS - nbits); - if ((xm & ~pm) ^ ~pm) - /* do no round up if some of the nbits first bits are 0s. */ - return 0; - - if (rnd == MPFR_RNDN) - /* mask for rounding bit */ - pm = (MPFR_LIMB_ONE << (GMP_NUMB_BITS - nbits - 1)); - - /* round up if some remaining bits are 1 */ - /* warning: the return value must be an int */ - return xm & pm ? 1 : 0; -} - -/* Record information from mpfr_get_str() so as to avoid multiple - calls to this expensive function. */ -struct decimal_info -{ - mpfr_exp_t exp; - char *str; -}; - -/* For a real non zero number x, what is the exponent f so that - 10^f <= x < 10^(f+1). */ -static mpfr_exp_t -floor_log10 (mpfr_srcptr x) -{ - mpfr_t y; - mpfr_exp_t exp; - - /* make sure first that y can represent a mpfr_exp_t exactly - and can compare with x */ - mpfr_prec_t prec = sizeof (mpfr_exp_t) * CHAR_BIT; - mpfr_init2 (y, MAX (prec, MPFR_PREC (x))); - - exp = mpfr_ceil_mul (MPFR_GET_EXP (x), 10, 1) - 1; - mpfr_set_exp_t (y, exp, MPFR_RNDU); - /* The following call to mpfr_ui_pow should be fast: y is an integer - (not too large), so that mpfr_pow_z will be used internally. */ - mpfr_ui_pow (y, 10, y, MPFR_RNDU); - if (mpfr_cmpabs (x, y) < 0) - exp--; - - mpfr_clear (y); - return exp; -} - -#define NDIGITS 8 - -MPFR_RETURNS_NONNULL static char * -mpfr_get_str_wrapper (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; - - /* Possibles bases for the *printf functions. */ - MPFR_ASSERTD (base == 2 || base == 10 || base == 16); - - 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 == 2 ? '1' : base == 10 ? '9' : 'f'; - 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'. - - Return -1 in case of overflow on the sizes. */ -static int -regular_ab (struct number_parts *np, mpfr_srcptr p, - const struct printf_spec spec) -{ - int uppercase; - int base; - char *str; - mpfr_exp_t exp; - - uppercase = spec.spec == 'A'; - - /* sign */ - if (MPFR_IS_NEG (p)) - np->sign = '-'; - else if (spec.showsign || spec.space) - np->sign = spec.showsign ? '+' : ' '; - - if (spec.spec == 'a' || spec.spec == 'A') - /* prefix part */ - { - np->prefix_size = 2; - str = (char *) mpfr_allocate_func (1 + np->prefix_size); - str[0] = '0'; - str[1] = uppercase ? 'X' : 'x'; - str[2] = '\0'; - np->prefix_ptr = register_string (np->sl, str); - } - - /* integral part */ - np->ip_size = 1; - base = (spec.spec == 'b') ? 2 : 16; - - if (spec.prec != 0) - { - size_t nsd; - - /* 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 (which will give nsd > 1 below). */ - MPFR_ASSERTD (np->ip_size == 1); /* thus the + 1 below */ - if (spec.prec < 0) - nsd = 0; - else - { - if (MPFR_UNLIKELY (spec.prec > (size_t) -2)) /* overflow */ - return -1; - nsd = (size_t) spec.prec + 1; - MPFR_ASSERTD (nsd != 1); - } - str = mpfr_get_str_wrapper (&exp, base, nsd, p, spec); - register_string (np->sl, str); - np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */ - - if (base == 16) - /* EXP is the exponent for radix sixteen with decimal point BEFORE the - first digit, we want the exponent for radix two and the decimal - point AFTER the first digit. */ - { - /* An integer overflow is normally not possible since MPFR_EXP_MIN - is twice as large as MPFR_EMIN_MIN. */ - MPFR_ASSERTN (exp > (MPFR_EXP_MIN + 3) / 4); - exp = (exp - 1) * 4; - } - else - /* EXP is the exponent for decimal point BEFORE the first digit, we - want the exponent for decimal point AFTER the first digit. */ - { - /* An integer overflow is normally not possible since MPFR_EXP_MIN - is twice as large as MPFR_EMIN_MIN. */ - MPFR_ASSERTN (exp > MPFR_EXP_MIN); - --exp; - } - } - else if (next_base_power_p (p, base, spec.rnd_mode)) - { - str = (char *) mpfr_allocate_func (2); - str[0] = '1'; - str[1] = '\0'; - np->ip_ptr = register_string (np->sl, str); - - exp = MPFR_GET_EXP (p); - } - else if (base == 2) - { - str = (char *) mpfr_allocate_func (2); - str[0] = '1'; - str[1] = '\0'; - np->ip_ptr = register_string (np->sl, str); - - exp = MPFR_GET_EXP (p) - 1; - } - else - { - int digit; - mp_limb_t msl = MPFR_MANT (p)[MPFR_LIMB_SIZE (p) - 1]; - int rnd_bit = GMP_NUMB_BITS - 5; - - /* pick up the 4 first bits */ - digit = msl >> (rnd_bit + 1); - if (spec.rnd_mode == MPFR_RNDA - || (spec.rnd_mode == MPFR_RNDU && MPFR_IS_POS (p)) - || (spec.rnd_mode == MPFR_RNDD && MPFR_IS_NEG (p)) - || (spec.rnd_mode == MPFR_RNDN - && (msl & (MPFR_LIMB_ONE << rnd_bit)))) - digit++; - MPFR_ASSERTD (0 <= digit && digit <= 15); - - 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); - - exp = MPFR_GET_EXP (p) - 4; - } - - if (uppercase) - /* All digits in upper case */ - { - char *s1 = str; - while (*s1) - { - switch (*s1) - { - case 'a': - *s1 = 'A'; - break; - case 'b': - *s1 = 'B'; - break; - case 'c': - *s1 = 'C'; - break; - case 'd': - *s1 = 'D'; - break; - case 'e': - *s1 = 'E'; - break; - case 'f': - *s1 = 'F'; - break; - } - s1++; - } - } - - if (spec.spec == 'b' || spec.prec != 0) - /* compute the number of digits in fractional part */ - { - char *ptr; - size_t str_len; - - /* the sign has been skipped, skip also the first digit */ - ++str; - str_len = strlen (str); - ptr = str + str_len - 1; /* points to the end of str */ - - if (spec.prec < 0) - /* remove trailing zeros, if any */ - { - while (*ptr == '0' && str_len != 0) - { - --ptr; - --str_len; - } - } - - if (str_len != 0) - /* there are some non-zero digits in fractional part */ - { - np->fp_ptr = str; - np->fp_size = str_len; - /* Warning! str_len has type size_t, which is unsigned. */ - if (spec.prec > 0 && str_len < spec.prec) - { - np->fp_trailing_zeros = spec.prec - str_len; - MPFR_ASSERTD (np->fp_trailing_zeros >= 0); - } - } - } - - /* decimal point */ - if (np->fp_size != 0 || spec.alt) - np->point = MPFR_DECIMAL_POINT; - - /* the exponent part contains the character 'p', or 'P' plus the sign - character plus at least one digit and only as many more digits as - necessary to represent the exponent. - We assume that |EXP| < 10^INT_MAX. */ - np->exp_size = 3; - { - mpfr_uexp_t x; - - x = SAFE_ABS (mpfr_uexp_t, exp); - while (x > 9) - { - np->exp_size++; - x /= 10; - } - } - 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", - or "P%+.2li" */ - - exp_fmt[0] = uppercase ? 'P' : 'p'; - exp_fmt[1] = '\0'; - strcat (exp_fmt, "%+.1" MPFR_EXP_FSPEC "d"); - - if (MPFR_UNLIKELY (sprintf (str, exp_fmt, (mpfr_eexp_t) exp) < 0)) - return -1; - } - - return 0; -} - -/* 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 - a null pointer. - - Return -1 in case of overflow on the sizes. */ -static int -regular_eg (struct number_parts *np, mpfr_srcptr p, - const struct printf_spec spec, struct decimal_info *dec_info, - int keep_trailing_zeros) -{ - char *str; - mpfr_exp_t exp; - - const int uppercase = spec.spec == 'E' || spec.spec == 'G'; - - /* sign */ - if (MPFR_IS_NEG (p)) - np->sign = '-'; - else if (spec.showsign || spec.space) - np->sign = spec.showsign ? '+' : ' '; - - /* integral part */ - np->ip_size = 1; - if (dec_info == NULL) - { - size_t nsd; - - /* Number of significant digits: - - if no given precision, then let mpfr_get_str determine it, - - if a precision is specified, then one digit before decimal point - 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. */ - MPFR_ASSERTD (np->ip_size == 1); /* thus the + 1 below */ - if (spec.prec < 0) - nsd = 0; - else - { - if (MPFR_UNLIKELY (spec.prec > (size_t) -2)) /* overflow */ - return -1; - nsd = (size_t) spec.prec + 1; - } - str = mpfr_get_str_wrapper (&exp, 10, nsd, p, spec); - register_string (np->sl, str); - } - else - { - exp = dec_info->exp; - str = dec_info->str; - } - np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */ - - if (spec.prec != 0) - /* compute the number of digits in fractional part */ - { - char *ptr; - size_t str_len; - - /* the sign has been skipped, skip also the first digit */ - ++str; - str_len = strlen (str); - ptr = str + str_len - 1; /* points to the end of str */ - - if (!keep_trailing_zeros) - /* remove trailing zeros, if any */ - { - while (*ptr == '0' && str_len != 0) - { - --ptr; - --str_len; - } - } - - if (str_len != 0) - /* there are some non-zero digits in fractional part */ - { - np->fp_ptr = str; - np->fp_size = str_len; - /* Warning! str_len has type size_t, which is unsigned. */ - if (keep_trailing_zeros && spec.prec > 0 && str_len < spec.prec) - { - /* add missing trailing zeros */ - np->fp_trailing_zeros = spec.prec - str_len; - MPFR_ASSERTD (np->fp_trailing_zeros >= 0); - } - } - } - - /* decimal point */ - if (np->fp_size != 0 || spec.alt) - np->point = MPFR_DECIMAL_POINT; - - /* EXP is the exponent for decimal point BEFORE the first digit, we want - the exponent for decimal point AFTER the first digit. - Here, no possible overflow because exp < MPFR_EXP (p) / 3 */ - exp--; - - /* the exponent part contains the character 'e', or 'E' plus the sign - character plus at least two digits and only as many more digits as - necessary to represent the exponent. - We assume that |EXP| < 10^INT_MAX. */ - np->exp_size = 3; - { - mpfr_uexp_t x; - - x = SAFE_ABS (mpfr_uexp_t, exp); - while (x > 9) - { - np->exp_size++; - x /= 10; - } - } - if (np->exp_size < 4) - np->exp_size = 4; - - str = (char *) mpfr_allocate_func (1 + np->exp_size); - np->exp_ptr = register_string (np->sl, str); - - { - char exp_fmt[8]; /* e.g. "e%+.2i", or "E%+.2li" */ - - exp_fmt[0] = uppercase ? 'E' : 'e'; - exp_fmt[1] = '\0'; - strcat (exp_fmt, "%+.2" MPFR_EXP_FSPEC "d"); - - if (MPFR_UNLIKELY (sprintf (str, exp_fmt, (mpfr_eexp_t) exp) < 0)) - return -1; - } - - return 0; -} - -/* Determine the different parts of the string representation of the regular - number P when spec.spec is 'f', 'F', 'g', or 'G'. - dec_info contains the previously computed exponent and string or is - a null pointer. - - Return -1 in case of overflow on the sizes. */ -static int -regular_fg (struct number_parts *np, mpfr_srcptr p, - const struct printf_spec spec, struct decimal_info *dec_info, - int keep_trailing_zeros) -{ - mpfr_exp_t exp; - char * str; - - /* WARNING: an empty precision field is forbidden (it means precision = 6 - and it should have been changed to 6 before the function call) */ - MPFR_ASSERTD (spec.prec >= 0); - - /* sign */ - if (MPFR_IS_NEG (p)) - np->sign = '-'; - else if (spec.showsign || spec.space) - np->sign = spec.showsign ? '+' : ' '; - - if (MPFR_GET_EXP (p) <= 0) - /* 0 < |p| < 1 */ - { - /* Most of the time, integral part is 0 */ - np->ip_size = 1; - str = (char *) mpfr_allocate_func (1 + np->ip_size); - str[0] = '0'; - str[1] = '\0'; - np->ip_ptr = register_string (np->sl, str); - - if (spec.prec == 0) - /* only two possibilities: either 1 or 0. */ - { - mpfr_t y; - /* y = abs(p) */ - MPFR_ALIAS (y, p, 1, MPFR_EXP (p)); - - if (spec.rnd_mode == MPFR_RNDA - || (spec.rnd_mode == MPFR_RNDD && MPFR_IS_NEG (p)) - || (spec.rnd_mode == MPFR_RNDU && MPFR_IS_POS (p)) - || (spec.rnd_mode == MPFR_RNDN && mpfr_cmp_d (y, 0.5) > 0)) - /* rounded up to 1: one digit '1' in integral part. - note that 0.5 is rounded to 0 with RNDN (round ties to even) */ - np->ip_ptr[0] = '1'; - } - else - { - /* exp = position of the most significant decimal digit. */ - exp = floor_log10 (p); - MPFR_ASSERTD (exp < 0); - - if (exp < -spec.prec) - /* only the last digit may be non zero */ - { - int round_away; - - /* Due to mpfr_set_si below... */ - if (MPFR_UNLIKELY (spec.prec > LONG_MAX)) /* overflow */ - return -1; - - switch (spec.rnd_mode) - { - case MPFR_RNDA: - case MPFR_RNDF: /* round_away = 1 needed for %Rg */ - 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; - 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 - 0.5*10^(-spec.prec) different from |p| */ - e += 8; - mpfr_set_prec (y, e); - mpfr_set_si (y, -spec.prec, MPFR_RNDN); - mpfr_exp10 (y, y, MPFR_RNDD); - mpfr_div_2ui (y, y, 1, MPFR_RNDN); - cmp = mpfr_cmpabs (y, p); - } - while (cmp == 0); - - round_away = cmp < 0; - mpfr_clear (y); - } - break; - } - - if (round_away) - /* round away from zero: the last output digit is '1' */ - { - np->fp_leading_zeros = spec.prec - 1; - - np->fp_size = 1; - str = (char *) mpfr_allocate_func (1 + np->fp_size); - str[0] = '1'; - str[1] = '\0'; - np->fp_ptr = register_string (np->sl, str); - } - else - /* only zeros in fractional part */ - { - MPFR_ASSERTD (spec.spec == 'f' || spec.spec == 'F'); - np->fp_leading_zeros = spec.prec; - } - } - 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; - - MPFR_ASSERTD (exp <= -1); - MPFR_ASSERTD (spec.prec + (exp + 1) >= 0); - if (MPFR_UNLIKELY (spec.prec + (exp + 1) > (size_t) -1)) - return -1; - 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_wrapper (&exp, 10, nsd, p, spec); - register_string (np->sl, str); - } - else - { - exp = dec_info->exp; - str = dec_info->str; - } - if (MPFR_IS_NEG (p)) - /* skip sign */ - ++str; - if (exp == 1) - /* round up to 1 */ - { - MPFR_ASSERTD (str[0] == '1'); - np->ip_ptr[0] = '1'; - if (keep_trailing_zeros) - np->fp_leading_zeros = spec.prec; - } - else - { - np->fp_ptr = str; - np->fp_leading_zeros = -exp; - MPFR_ASSERTD (exp <= 0); - - str_len = strlen (str); /* the sign has been skipped */ - ptr = str + str_len - 1; /* points to the end of str */ - - if (!keep_trailing_zeros) - /* remove trailing zeros, if any */ - { - while (*ptr == '0' && str_len != 0) - { - --ptr; - --str_len; - } - } - - MPFR_ASSERTD (str_len > 0); - np->fp_size = str_len; - - /* The np->fp_size <= MPFR_INTMAX_MAX test and the - cast to mpfr_uintmax_t below allow one to avoid - integer overflow. */ - if (keep_trailing_zeros - && spec.prec > 0 - && np->fp_size <= MPFR_INTMAX_MAX - && ((mpfr_uintmax_t) - np->fp_leading_zeros + np->fp_size) < spec.prec) - { - /* add missing trailing zeros */ - np->fp_trailing_zeros = spec.prec - - np->fp_leading_zeros - np->fp_size; - MPFR_ASSERTD (np->fp_trailing_zeros >= 0); - } - } - } - } - - if (spec.alt || np->fp_leading_zeros != 0 || np->fp_size != 0 - || np->fp_trailing_zeros != 0) - np->point = MPFR_DECIMAL_POINT; - } - else - /* 1 <= |p| */ - { - size_t str_len; - - /* Determine the position of the most significant decimal digit. */ - exp = floor_log10 (p); - MPFR_ASSERTD (exp >= 0); - - if (dec_info == NULL) - { - /* %f case */ - mpfr_uintmax_t n; - - n = (mpfr_uintmax_t) spec.prec + (exp + 1); - if (MPFR_UNLIKELY (n > (size_t) -1)) - return -1; - str = mpfr_get_str_wrapper (&exp, 10, n, p, spec); - register_string (np->sl, str); - } - else - { - /* %g case */ - exp = dec_info->exp; - str = dec_info->str; - } - np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign */ - str_len = strlen (str); - - /* integral part */ - if (exp > str_len) - { - /* When spec.size == 0, mpfr_get_str may be called in a reduced - precision, so that some trailing digits may have been ignored. - When spec.size != 0, this case is also possible in the case - where p is rounded up to the next power of 10: a zero must be - added since the exponent has been increased by 1. */ - np->ip_trailing_digits = exp - str_len; - np->ip_size = str_len; - } - else - np->ip_size = exp; - - if (spec.group) - /* thousands separator in integral part */ - np->thousands_sep = MPFR_THOUSANDS_SEPARATOR; - - /* fractional part */ - str += np->ip_size; - str_len -= np->ip_size; - if (!keep_trailing_zeros) - /* remove trailing zeros, if any */ - { - char *ptr = str + str_len - 1; /* pointer to the last digit of - str */ - while (*ptr == '0' && str_len != 0) - { - --ptr; - --str_len; - } - } - - if (str_len > 0) - /* some nonzero digits in fractional part */ - { - np->point = MPFR_DECIMAL_POINT; - np->fp_ptr = str; - np->fp_size = str_len; - } - - /* Warning! str_len has type size_t, which is unsigned. */ - MPFR_ASSERTD (spec.prec >= 0); /* let's recall this */ - if (keep_trailing_zeros && str_len < spec.prec) - /* add missing trailing zeros */ - { - np->point = MPFR_DECIMAL_POINT; - np->fp_trailing_zeros = spec.prec - np->fp_size; - MPFR_ASSERTD (np->fp_trailing_zeros >= 0); - } - - if (spec.alt) - /* add decimal point even if no digits follow it */ - np->point = MPFR_DECIMAL_POINT; - } - - return 0; -} - -/* partition_number determines the different parts of the string - representation of the number p according to the given specification. - 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 occurred, in that case np's fields are in an - undefined state but all string buffers have been freed. */ -static mpfr_intmax_t -partition_number (struct number_parts *np, mpfr_srcptr p, - struct printf_spec spec) -{ - char *str; - mpfr_uintmax_t total; /* can hold the sum of two non-negative - signed integers + 1 */ - int uppercase; - - /* WARNING: left justification means right space padding */ - np->pad_type = spec.left ? RIGHT : spec.pad == '0' ? LEADING_ZEROS : LEFT; - np->pad_size = 0; - np->sign = '\0'; - np->prefix_ptr =NULL; - np->prefix_size = 0; - np->thousands_sep = '\0'; - np->ip_ptr = NULL; - np->ip_size = 0; - np->ip_trailing_digits = 0; - np->point = '\0'; - np->fp_leading_zeros = 0; - np->fp_ptr = NULL; - np->fp_size = 0; - np->fp_trailing_zeros = 0; - np->exp_ptr = NULL; - np->exp_size = 0; - np->sl = (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' - || spec.spec == 'G'; - - if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (p))) - { - if (MPFR_IS_NAN (p)) - { - if (np->pad_type == LEADING_ZEROS) - /* don't want "0000nan", change to right justification padding - with left spaces instead */ - np->pad_type = LEFT; - - 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)) - { - if (np->pad_type == LEADING_ZEROS) - /* don't want "0000inf", change to right justification padding - with left spaces instead */ - np->pad_type = LEFT; - - if (MPFR_IS_NEG (p)) - np->sign = '-'; - - 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 - { - 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. */ - if (MPFR_IS_NEG (p)) - /* signed zero */ - np->sign = '-'; - else if (spec.showsign || spec.space) - np->sign = spec.showsign ? '+' : ' '; - - if (spec.spec == 'a' || spec.spec == 'A') - /* prefix part */ - { - np->prefix_size = 2; - str = (char *) mpfr_allocate_func (1 + np->prefix_size); - str[0] = '0'; - str[1] = uppercase ? 'X' : 'x'; - str[2] = '\0'; - np->prefix_ptr = register_string (np->sl, str); - } - - /* integral part */ - np->ip_size = 1; - str = (char *) mpfr_allocate_func (1 + np->ip_size); - str[0] = '0'; - str[1] = '\0'; - np->ip_ptr = register_string (np->sl, str); - - if (spec.prec < 0) /* empty precision field */ - { - if (spec.spec == 'e' || spec.spec == 'E') - spec.prec = mpfr_get_str_ndigits (10, MPFR_GET_PREC (p)) - 1; - else if (spec.spec == 'f' || spec.spec == 'F' || - spec.spec == 'g' || spec.spec == 'G') - spec.prec = DEFAULT_DECIMAL_PREC; - } - - if (spec.prec > 0 - && ((spec.spec != 'g' && spec.spec != 'G') || spec.alt)) - /* fractional part */ - { - np->point = MPFR_DECIMAL_POINT; - np->fp_trailing_zeros = (spec.spec == 'g' || spec.spec == 'G') ? - spec.prec - 1 : spec.prec; - MPFR_ASSERTD (np->fp_trailing_zeros >= 0); - } - else if (spec.alt) - np->point = MPFR_DECIMAL_POINT; - - if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b' - || spec.spec == 'e' || spec.spec == 'E') - /* exponent part */ - { - np->exp_size = (spec.spec == 'e' || spec.spec == 'E') ? 4 : 3; - str = (char *) mpfr_allocate_func (1 + np->exp_size); - if (spec.spec == 'e' || spec.spec == 'E') - strcpy (str, uppercase ? "E+00" : "e+00"); - else - strcpy (str, uppercase ? "P+0" : "p+0"); - np->exp_ptr = register_string (np->sl, str); - } - } - } - 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 - { - MPFR_ASSERTD (MPFR_IS_PURE_FP (p)); - if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b') - { - if (regular_ab (np, p, spec) == -1) - goto error; - } - else if (spec.spec == 'f' || spec.spec == 'F') - { - if (spec.prec < 0) - spec.prec = DEFAULT_DECIMAL_PREC; - if (regular_fg (np, p, spec, NULL, 1) == -1) - goto error; - } - else if (spec.spec == 'e' || spec.spec == 'E') - { - if (regular_eg (np, p, spec, NULL, 1) == -1) - goto error; - } - else - /* %g case */ - { - /* Use the C99 rules: - if T > X >= -4 then the conversion is with style 'f'/'F' and - precision T-(X+1). - otherwise, the conversion is with style 'e'/'E' and - precision T-1. - 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, e, k; - struct decimal_info dec_info; - - threshold = spec.prec < 0 ? DEFAULT_DECIMAL_PREC : - spec.prec == 0 ? 1 : spec.prec; - MPFR_ASSERTD (threshold >= 1); - - /* Here we cannot call mpfr_get_str_wrapper 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. */ - x = dec_info.exp - 1; - - if (threshold > x && x >= -4) - { - /* the conversion is with style 'f' */ - spec.prec = threshold - x - 1; - - if (regular_fg (np, p, spec, &dec_info, spec.alt) == -1) - goto error; - } - else - { - spec.prec = threshold - 1; - - if (regular_eg (np, p, spec, &dec_info, spec.alt) == -1) - goto error; - } - } - } - - /* 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) > MPFR_INTMAX_MAX)) \ - goto error; \ - total += (v); \ - if (MPFR_UNLIKELY (total > MPFR_INTMAX_MAX)) \ - goto error; \ - } while (0) - - total = np->sign ? 1 : 0; - INCR_TOTAL (np->prefix_size); - INCR_TOTAL (np->ip_size); - INCR_TOTAL (np->ip_trailing_digits); - MPFR_ASSERTD (np->ip_size + np->ip_trailing_digits >= 1); - if (np->thousands_sep) - /* ' flag, style f and the thousands separator in current locale is not - reduced to the null character */ - INCR_TOTAL ((np->ip_size + np->ip_trailing_digits - 1) / 3); - if (np->point) - ++total; - INCR_TOTAL (np->fp_leading_zeros); - INCR_TOTAL (np->fp_size); - INCR_TOTAL (np->fp_trailing_zeros); - INCR_TOTAL (np->exp_size); - - if (spec.width > total) - /* pad with spaces or zeros depending on np->pad_type */ - { - np->pad_size = spec.width - total; - total = spec.width; - } - - MPFR_ASSERTD (total > 0 && total <= MPFR_INTMAX_MAX); - return total; - - error: - clear_string_list (np->sl); - np->prefix_ptr = NULL; - np->ip_ptr = NULL; - np->fp_ptr = NULL; - np->exp_ptr = NULL; - return -1; -} - -/* sprnt_fp prints a mpfr_t according to spec.spec specification. - - 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 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) -{ - mpfr_intmax_t length, start; - struct number_parts np; - - length = partition_number (&np, p, spec); - if (MPFR_UNLIKELY (length < 0)) - { - 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) - buffer_pad (buf, ' ', np.pad_size); - - /* sign character (may be '-', '+', or ' ') */ - if (np.sign) - buffer_pad (buf, np.sign, 1); - - /* prefix part */ - if (np.prefix_ptr) - buffer_cat (buf, np.prefix_ptr, np.prefix_size); - - /* right justification padding with leading zeros */ - if (np.pad_type == LEADING_ZEROS && np.pad_size != 0) - buffer_pad (buf, '0', np.pad_size); - - /* integral part (may also be "nan" or "inf") */ - MPFR_ASSERTN (np.ip_ptr != NULL); /* never empty */ - if (MPFR_UNLIKELY (np.thousands_sep)) - { - if (buffer_sandwich (buf, np.ip_ptr, np.ip_size, np.ip_trailing_digits, - np.thousands_sep)) - { - buf->len = -1; - goto clear_and_exit; - } - } - else - { - buffer_cat (buf, np.ip_ptr, np.ip_size); - - /* possible trailing zero in integral part (spec.size != 0) */ - MPFR_ASSERTD (np.ip_trailing_digits <= 1); - if (np.ip_trailing_digits != 0) - buffer_pad (buf, '0', 1); - } - - /* decimal point */ - if (np.point) - buffer_pad (buf, np.point, 1); - - /* leading zeros in fractional part */ - if (np.fp_leading_zeros != 0) - buffer_pad (buf, '0', np.fp_leading_zeros); - - /* significant digits in fractional part */ - if (np.fp_ptr) - buffer_cat (buf, np.fp_ptr, np.fp_size); - - /* trailing zeros in fractional part */ - if (np.fp_trailing_zeros != 0) - buffer_pad (buf, '0', np.fp_trailing_zeros); - - /* exponent part */ - if (np.exp_ptr) - buffer_cat (buf, np.exp_ptr, np.exp_size); - - /* 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 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_vasnprintf_aux (char **ptr, char *Buf, size_t size, const char *fmt, - va_list ap) -{ - struct string_buffer buf; - int nbchar; - - /* information on the conversion specification filled by the parser */ - struct printf_spec spec; - /* flag raised when previous part of fmt need to be processed by - gmp_vsnprintf */ - int xgmp_fmt_flag; - /* beginning and end of the previous unprocessed part of fmt */ - const char *start, *end; - /* pointer to arguments for gmp_vasprintf */ - va_list ap2; - - MPFR_SAVE_EXPO_DECL (expo); - MPFR_SAVE_EXPO_MARK (expo); - - /* FIXME: Once buf.len >= size, switch to size = 0 for efficiency and - avoid potential DoS? i.e. we no longer need to generate the strings - (potentially huge), just compute the lengths. */ - - buffer_init (&buf, ptr != NULL || size != 0 ? 4096 : 0); - xgmp_fmt_flag = 0; - va_copy (ap2, ap); - start = fmt; - while (*fmt != '\0') - { - int overflow = 0; - - /* Look for the next format specification */ - while (*fmt != '\0' && *fmt != '%') - ++fmt; - - if (*fmt == '\0') - break; - - if (*++fmt == '%') - /* %%: go one step further otherwise the second '%' would be - considered as a new conversion specification introducing - character */ - { - ++fmt; - xgmp_fmt_flag = 1; - continue; - } - - end = fmt - 1; - - /* format string analysis */ - specinfo_init (&spec); - fmt = parse_flags (fmt, &spec); - - READ_INT (ap, fmt, spec.width); - if (spec.width < 0) /* integer read via '*', no overflow */ - { - spec.left = 1; - /* Since the type of the integer is int, spec.width >= INT_MIN, - so that an overflow is possible here only if mpfr_intmax_t - has the same size of int. The INT_MIN < - MPFR_INTMAX_MAX - test allows the compiler to optimize when it is false. */ - if (MPFR_UNLIKELY (INT_MIN < - MPFR_INTMAX_MAX && - spec.width < - MPFR_INTMAX_MAX)) - overflow = 1; - else - spec.width = - spec.width; - } - /* Note: We will make sure that spec.width is not used in case of - overflow. */ - MPFR_ASSERTD (overflow || spec.width >= 0); - - if (*fmt == '.') - { - const char *f = ++fmt; - READ_INT (ap, fmt, spec.prec); - if (f == fmt || spec.prec < 0) - spec.prec = -1; - } - else - spec.prec = -1; - MPFR_ASSERTD (spec.prec >= -1); - - fmt = parse_arg_type (fmt, &spec); - if (spec.arg_type == UNSUPPORTED) - /* 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) - { - case '\0': - break; - case '*': - ++fmt; - spec.rnd_mode = (mpfr_rnd_t) va_arg (ap, int); - break; - case 'D': - ++fmt; - spec.rnd_mode = MPFR_RNDD; - break; - case 'U': - ++fmt; - spec.rnd_mode = MPFR_RNDU; - break; - case 'Y': - ++fmt; - spec.rnd_mode = MPFR_RNDA; - break; - case 'Z': - ++fmt; - spec.rnd_mode = MPFR_RNDZ; - break; - case 'N': - ++fmt; - MPFR_FALLTHROUGH; - default: - spec.rnd_mode = MPFR_RNDN; - } - } - - spec.spec = *fmt; - if (!specinfo_is_valid (spec)) - /* 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 != '\0') - fmt++; - - /* Format processing */ - if (spec.spec == '\0') - /* end of the format string */ - break; - else if (spec.spec == 'n') - /* put the number of characters written so far in the location pointed - by the next va_list argument; the types of pointer accepted are the - same as in GMP (except unsupported quad_t) plus pointer to a mpfr_t - so as to be able to accept the same format strings. */ - { - void *p; - - p = va_arg (ap, void *); - FLUSH (xgmp_fmt_flag, start, end, ap2, &buf); - va_end (ap2); - start = fmt; - - switch (spec.arg_type) - { - case CHAR_ARG: - *(char *) p = (char) buf.len; - break; - case SHORT_ARG: - *(short *) p = (short) buf.len; - break; - case LONG_ARG: - *(long *) p = (long) buf.len; - break; -#ifdef HAVE_LONG_LONG - case LONG_LONG_ARG: - *(long long *) p = (long long) buf.len; - break; -#endif -#ifdef _MPFR_H_HAVE_INTMAX_T - case INTMAX_ARG: - *(intmax_t *) p = (intmax_t) buf.len; - break; -#endif - case SIZE_ARG: - *(size_t *) p = buf.len; - break; - case PTRDIFF_ARG: - *(ptrdiff_t *) p = (ptrdiff_t) buf.len; - break; - case MPF_ARG: - mpf_set_ui ((mpf_ptr) p, (unsigned long) buf.len); - break; - case MPQ_ARG: - mpq_set_ui ((mpq_ptr) p, (unsigned long) buf.len, 1L); - break; - case MP_LIMB_ARG: - *(mp_limb_t *) p = (mp_limb_t) buf.len; - break; - case MP_LIMB_ARRAY_ARG: - { - mp_limb_t *q = (mp_limb_t *) p; - mp_size_t n; - n = va_arg (ap, mp_size_t); - if (n < 0) - n = -n; - else if (n == 0) - break; - - /* we assume here that mp_limb_t is wider than int */ - *q = (mp_limb_t) buf.len; - while (--n != 0) - { - q++; - *q = MPFR_LIMB_ZERO; - } - } - break; - case MPZ_ARG: - mpz_set_ui ((mpz_ptr) p, (unsigned long) buf.len); - break; - - case MPFR_ARG: - mpfr_set_ui ((mpfr_ptr) p, (unsigned long) buf.len, - spec.rnd_mode); - break; - - default: - *(int *) p = (int) buf.len; - } - va_copy (ap2, ap); /* after the switch, due to MP_LIMB_ARRAY_ARG - case */ - } - else if (spec.arg_type == MPFR_PREC_ARG) - /* output mpfr_prec_t variable */ - { - char *s; - char format[MPFR_PREC_FORMAT_SIZE + 12]; /* e.g. "%0#+ -'*.*ld\0" */ - size_t length; - mpfr_prec_t prec; - - /* FIXME: With buf.size = 0 and a huge width or precision, this - can uselessly take much memory. And even with buf.size != 0, - this would take more memory than necessary and need a large - buffer_cat. A solution: compute a bound on the maximum - number of significant digits, and handle the additional - characters separately. Moreover, if buf.size = 0 or size != 0, - gmp_snprintf should be called instead of gmp_asprintf, - outputting data directly to the buffer when applicable. - See also: https://sourceware.org/bugzilla/show_bug.cgi?id=23432 - Add testcases. */ - - prec = va_arg (ap, mpfr_prec_t); - - FLUSH (xgmp_fmt_flag, start, end, ap2, &buf); - va_end (ap2); - va_copy (ap2, ap); - start = fmt; - - /* The restriction to INT_MAX is a limitation due to the fact - that *.* is used below. If the width or precision field is - larger than INT_MAX, then there is a real overflow on the - return value due to the padding characters, thus the error - is correct. The only minor drawback is that some variables - corresponding to the 'n' conversion specifier with a type - larger than int may not be set. This is not a bug, as there - are no strong guarantees for such variables in case of error. - FIXME: If size = 0 and max(spec.width,spec.prec) is large - enough, there is no need to call gmp_asprintf since we are - just interested in the length, which should be this maximum; - in particular, this should avoid the overflow issue. */ - if (overflow || spec.width > INT_MAX || spec.prec > INT_MAX) - { - buf.len = -1; - goto error; - } - - /* Recalled from above. */ - MPFR_ASSERTD (spec.width >= 0); - MPFR_ASSERTD (spec.prec >= -1); - - /* construct format string, like "%*.*hd" "%*.*d" or "%*.*ld" */ - sprintf (format, "%%%s%s%s%s%s%s*.*" MPFR_PREC_FORMAT_TYPE "%c", - spec.pad == '0' ? "0" : "", - spec.alt ? "#" : "", - spec.showsign ? "+" : "", - spec.space ? " " : "", - spec.left ? "-" : "", - spec.group ? "'" : "", - spec.spec); - MPFR_LOG_MSG (("MPFR_PREC_ARG: format for gmp_asprintf: \"%s\"\n", - format)); - MPFR_LOG_MSG (("MPFR_PREC_ARG: width = %d, prec = %d, value = %" - MPFR_PREC_FORMAT_TYPE "d\n", - (int) spec.width, (int) spec.prec, prec)); - length = gmp_asprintf (&s, format, - (int) spec.width, (int) spec.prec, prec); - 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); - va_end (ap2); - va_copy (ap2, ap); - start = fmt; - - if (overflow) - { - buf.len = -1; - goto error; - } - - if (ptr == NULL) - spec.size = size; - sprnt_fp (&buf, p, spec); - } - else - /* gmp_printf specification, step forward in the va_list */ - { - CONSUME_VA_ARG (spec, ap); - xgmp_fmt_flag = 1; - } - } - - if (start != fmt) - FLUSH (xgmp_fmt_flag, start, fmt, ap2, &buf); - - va_end (ap2); - - if (buf.len == -1 || buf.len > INT_MAX) /* overflow */ - goto overflow; - - 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 the number of characters that would have - been written had 'size' been sufficiently large, - not counting the terminating null character */ - - error: - va_end (ap2); - if (buf.len == -1) /* overflow */ - { - overflow: - MPFR_LOG_MSG (("Overflow\n", 0)); - MPFR_SAVE_EXPO_UPDATE_FLAGS (expo, MPFR_FLAGS_ERANGE); -#ifdef EOVERFLOW - MPFR_LOG_MSG (("Setting errno to EOVERFLOW\n", 0)); - errno = EOVERFLOW; -#endif - } - - MPFR_SAVE_EXPO_FREE (expo); - if (ptr != NULL) /* implement mpfr_vasprintf */ - *ptr = NULL; - if (ptr != NULL || size != 0) - 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 */ |