summaryrefslogtreecommitdiff
path: root/Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c')
-rw-r--r--Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c2086
1 files changed, 2086 insertions, 0 deletions
diff --git a/Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c b/Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c
new file mode 100644
index 00000000000..31e001cb5b2
--- /dev/null
+++ b/Build/source/libs/mpfr/mpfr-3.1.2/src/vasprintf.c
@@ -0,0 +1,2086 @@
+/* mpfr_vasprintf -- main function for the printf functions family
+ plus helper macros & functions.
+
+Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+Contributed by the AriC and Caramel 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
+http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/* The mpfr_printf-like functions are defined only if <stdarg.h> exists */
+#ifdef HAVE_STDARG
+
+#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>
+#define __STDC_LIMIT_MACROS /* SIZE_MAX defined with <stdint.h> inclusion */
+#else
+#include <stddef.h> /* for ptrdiff_t */
+#endif
+
+#define MPFR_NEED_LONGLONG_H
+#include "mpfr-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
+
+/* 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; saturate to INT_MAX. */
+#define READ_INT(ap, format, specinfo, field, label_out) \
+ do { \
+ while (*(format)) \
+ { \
+ int _i; \
+ switch (*(format)) \
+ { \
+ case '0': \
+ case '1': \
+ case '2': \
+ case '3': \
+ case '4': \
+ case '5': \
+ case '6': \
+ case '7': \
+ case '8': \
+ case '9': \
+ specinfo.field = (specinfo.field <= INT_MAX / 10) ? \
+ specinfo.field * 10 : INT_MAX; \
+ _i = *(format) - '0'; \
+ MPFR_ASSERTN (_i >= 0 && _i <= 9); \
+ specinfo.field = (specinfo.field <= INT_MAX - _i) ? \
+ specinfo.field + _i : INT_MAX; \
+ ++(format); \
+ break; \
+ case '*': \
+ specinfo.field = va_arg ((ap), int); \
+ ++(format); \
+ default: \
+ goto label_out; \
+ } \
+ } \
+ } 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 */
+
+ int width; /* Width */
+ int prec; /* Precision */
+
+ 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->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;
+ }
+}
+
+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;
+}
+
+static const char *
+parse_arg_type (const char *format, struct printf_spec *specinfo)
+{
+ switch (*format)
+ {
+ case '\0':
+ 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;
+ case 'l':
+ if (*++format == 'l')
+ {
+ ++format;
+#if defined (HAVE_LONG_LONG) && !defined(NPRINTF_LL)
+ 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) && !defined(NPRINTF_J)
+ specinfo->arg_type = INTMAX_ARG;
+#else
+ specinfo->arg_type = UNSUPPORTED;
+#endif
+ break;
+ case 'z':
+ ++format;
+ specinfo->arg_type = SIZE_ARG;
+ 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;
+ 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 dependant).
+ 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
+
+#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. */
+#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; \
+ 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) \
+ { \
+ MPFR_TMP_FREE (marker); \
+ goto error; \
+ } \
+ (flag) = 0; \
+ MPFR_TMP_FREE (marker); \
+ } \
+ else if ((start) != (end)) \
+ /* no conversion specification, just simple characters */ \
+ buffer_cat ((buf_ptr), (start), n); \
+ } while (0)
+
+struct string_buffer
+{
+ char *start; /* beginning of the buffer */
+ char *curr; /* null terminating character */
+ size_t size; /* buffer capacity */
+};
+
+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;
+ b->size = s;
+}
+
+/* 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));
+ MPFR_ASSERTD (pos < b->size);
+
+ MPFR_ASSERTN ((len & ~((size_t) 4095)) <= (size_t)(SIZE_MAX - 4096));
+ MPFR_ASSERTN (b->size < SIZE_MAX - n);
+
+ b->start =
+ (char *) (*__gmp_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 LEN first characters of the string S to the buffer B and
+ expand it if needed. */
+static void
+buffer_cat (struct string_buffer *b, const char *s, size_t len)
+{
+ MPFR_ASSERTD (len != 0);
+ MPFR_ASSERTD (len <= strlen (s));
+
+ if (MPFR_UNLIKELY ((b->curr + len) >= (b->start + b->size)))
+ buffer_widen (b, len);
+
+ strncat (b->curr, s, len);
+ b->curr += len;
+
+ MPFR_ASSERTD (b->curr < b->start + b->size);
+ MPFR_ASSERTD (*b->curr == '\0');
+}
+
+/* Add N characters C to the end of buffer B */
+static void
+buffer_pad (struct string_buffer *b, const char c, const size_t n)
+{
+ 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 (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);
+}
+
+/* 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
+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 (size != 0);
+ if (c == '\0')
+ {
+ buffer_cat (b, str, len);
+ buffer_pad (b, '0', tz);
+ return;
+ }
+
+ 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);
+
+ /* first R significant digits */
+ memcpy (b->curr, str, r);
+ b->curr += r;
+ str += r;
+ len -= r;
+
+ /* 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);
+
+ b->curr += step;
+ str += step;
+ }
+
+ *b->curr = '\0';
+
+ MPFR_ASSERTD (b->curr < b->start + b->size);
+}
+
+/* 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;
+
+ length = gmp_vasprintf (&s, fmt, ap);
+ if (length > 0)
+ buffer_cat (b, s, length);
+
+ mpfr_free_str (s);
+ return length;
+}
+
+/* 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 */
+};
+
+/* initialisation */
+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;
+ (*__gmp_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*)
+ (*__gmp_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 */
+ size_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_zeros; /* Number of additional null digits in integral
+ part */
+
+ char point; /* Decimal point character */
+
+ int 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 */
+ int 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;
+}
+
+/* Determine the different parts of the string representation of the regular
+ number P when SPEC.SPEC is 'a', 'A', or 'b'.
+
+ return -1 if some field > INT_MAX */
+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 *) (*__gmp_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. */
+ nsd = spec.prec < 0 ? 0 : spec.prec + np->ip_size;
+ str = mpfr_get_str (0, &exp, base, nsd, p, spec.rnd_mode);
+ 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. */
+ {
+ MPFR_ASSERTN (exp > MPFR_EMIN_MIN /4); /* possible overflow */
+ 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. */
+ {
+ MPFR_ASSERTN (exp > MPFR_EMIN_MIN); /* possible overflow */
+ --exp;
+ }
+ }
+ else if (next_base_power_p (p, base, spec.rnd_mode))
+ {
+ str = (char *)(*__gmp_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 *)(*__gmp_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 *)(*__gmp_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 > INT_MAX)
+ /* too many digits in fractional part */
+ return -1;
+
+ if (str_len != 0)
+ /* there are some non-zero digits in fractional part */
+ {
+ np->fp_ptr = str;
+ np->fp_size = str_len;
+ if ((int) str_len < spec.prec)
+ np->fp_trailing_zeros = spec.prec - str_len;
+ }
+ }
+
+ /* 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 *) (*__gmp_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 (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 NULL.
+
+ return -1 if some field > INT_MAX */
+static int
+regular_eg (struct number_parts *np, mpfr_srcptr p,
+ const struct printf_spec spec, struct decimal_info *dec_info)
+{
+ char *str;
+ mpfr_exp_t exp;
+
+ const int uppercase = spec.spec == 'E' || spec.spec == 'G';
+ const int spec_g = spec.spec == 'g' || spec.spec == 'G';
+ const int keep_trailing_zeros = (spec_g && spec.alt)
+ || (!spec_g && (spec.prec > 0));
+
+ /* 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. */
+ nsd = (spec.prec < 0) ? 0 : spec.prec + np->ip_size;
+ str = mpfr_get_str (0, &exp, 10, nsd, p, spec.rnd_mode);
+ 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 > INT_MAX)
+ /* too many digits in fractional part */
+ return -1;
+
+ if (str_len != 0)
+ /* there are some non-zero digits in fractional part */
+ {
+ np->fp_ptr = str;
+ np->fp_size = str_len;
+ 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;
+ }
+ }
+
+ /* 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 *) (*__gmp_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 (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 NULL.
+
+ return -1 if some field of number_parts is greater than INT_MAX */
+static int
+regular_fg (struct number_parts *np, mpfr_srcptr p,
+ const struct printf_spec spec, struct decimal_info *dec_info)
+{
+ mpfr_exp_t exp;
+ char * str;
+ const int spec_g = (spec.spec == 'g' || spec.spec == 'G');
+ const int keep_trailing_zeros = !spec_g || spec.alt;
+
+ /* 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 *) (*__gmp_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;
+ switch (spec.rnd_mode)
+ {
+ case MPFR_RNDA:
+ round_away = 1;
+ break;
+ case MPFR_RNDD:
+ round_away = MPFR_IS_NEG (p);
+ break;
+ case MPFR_RNDU:
+ round_away = MPFR_IS_POS (p);
+ break;
+ case MPFR_RNDN:
+ {
+ /* compare |p| to y = 0.5*10^(-spec.prec) */
+ mpfr_t y;
+ mpfr_exp_t e = MAX (MPFR_PREC (p), 56);
+ 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);
+ } while (mpfr_cmpabs (y, p) == 0);
+
+ round_away = mpfr_cmpabs (y, p) < 0;
+ mpfr_clear (y);
+ }
+ break;
+ default:
+ round_away = 0;
+ }
+
+ 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 *) (*__gmp_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_g);
+ np->fp_leading_zeros = spec.prec;
+ }
+ }
+ else
+ /* the most significant digits are the last
+ spec.prec + exp + 1 digits in fractional part */
+ {
+ char *ptr;
+ size_t str_len;
+ if (dec_info == NULL)
+ {
+ size_t 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);
+ 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 (!spec_g || spec.alt)
+ 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)
+ {
+ --ptr;
+ --str_len;
+ }
+ }
+
+ if (str_len > INT_MAX)
+ /* too many digits in fractional part */
+ return -1;
+
+ MPFR_ASSERTD (str_len > 0);
+ np->fp_size = str_len;
+
+ if ((!spec_g || spec.alt)
+ && spec.prec > 0
+ && (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;
+ }
+ }
+ }
+
+ 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 (exp > INT_MAX)
+ /* P is too large to print all its integral part digits */
+ return -1;
+
+ 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);
+ 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 */
+ str_len = strlen (str);
+
+ /* integral part */
+ if (exp > str_len)
+ /* mpfr_get_str gives no trailing zero when p is rounded up to the next
+ power of 10 (p integer, so no fractional part) */
+ {
+ np->ip_trailing_zeros = 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 */
+ {
+ if (str_len > INT_MAX)
+ /* too many digits in fractional part */
+ return -1;
+
+ np->point = MPFR_DECIMAL_POINT;
+ np->fp_ptr = str;
+ np->fp_size = str_len;
+ }
+
+ 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;
+ }
+
+ 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 occured, in that case np's fields are in an undefined
+ state but all string buffers have been freed. */
+static int
+partition_number (struct number_parts *np, mpfr_srcptr p,
+ struct printf_spec spec)
+{
+ char *str;
+ long total;
+ 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_zeros = 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 *)
+ (*__gmp_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;
+
+ 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);
+ }
+ }
+ 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 = '-';
+
+ 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);
+ }
+ }
+ else
+ /* p == 0 */
+ {
+ /* 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 *) (*__gmp_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 *) (*__gmp_allocate_func) (1 + np->ip_size);
+ str[0] = '0';
+ str[1] = '\0';
+ np->ip_ptr = register_string (np->sl, str);
+
+ 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;
+ }
+ 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 *) (*__gmp_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
+ /* regular p, p != 0 */
+ {
+ 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 == -1)
+ spec.prec = 6;
+ if (regular_fg (np, p, spec, NULL) == -1)
+ goto error;
+ }
+ else if (spec.spec == 'e' || spec.spec == 'E')
+ {
+ if (regular_eg (np, p, spec, NULL) == -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;
+ 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);
+ 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) == -1)
+ goto error;
+ }
+ else
+ {
+ spec.prec = threshold - 1;
+
+ if (regular_eg (np, p, spec, &dec_info) == -1)
+ goto error;
+ }
+ }
+ }
+
+ /* compute the number of characters to be written verifying it is not too
+ much */
+ total = np->sign ? 1 : 0;
+ total += np->prefix_size;
+ total += np->ip_size;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ total += np->ip_trailing_zeros;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ if (np->thousands_sep)
+ /* ' flag, style f and the thousands separator in current locale is not
+ reduced to the null character */
+ total += (np->ip_size + np->ip_trailing_zeros) / 3;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ if (np->point)
+ ++total;
+ total += np->fp_leading_zeros;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ total += np->fp_size;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ total += np->fp_trailing_zeros;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+ total += np->exp_size;
+ if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
+ goto error;
+
+ if (spec.width > total)
+ /* pad with spaces or zeros depending on np->pad_type */
+ {
+ np->pad_size = spec.width - total;
+ total += np->pad_size; /* here total == spec.width,
+ so 0 < total < INT_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 characters). */
+static int
+sprnt_fp (struct string_buffer *buf, mpfr_srcptr p,
+ const struct printf_spec spec)
+{
+ int length;
+ struct number_parts np;
+
+ length = partition_number (&np, p, spec);
+ if (length < 0)
+ return -1;
+
+ /* 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))
+ buffer_sandwich (buf, np.ip_ptr, np.ip_size, np.ip_trailing_zeros,
+ np.thousands_sep);
+ else
+ {
+ buffer_cat (buf, np.ip_ptr, np.ip_size);
+
+ /* trailing zeros in integral part */
+ if (np.ip_trailing_zeros != 0)
+ buffer_pad (buf, '0', np.ip_trailing_zeros);
+ }
+
+ /* 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 justication padding with right spaces */
+ if (np.pad_type == RIGHT && np.pad_size != 0)
+ buffer_pad (buf, ' ', np.pad_size);
+
+ clear_string_list (np.sl);
+ return length;
+}
+
+int
+mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
+{
+ struct string_buffer buf;
+ size_t nbchar;
+
+ /* informations 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);
+
+ nbchar = 0;
+ buffer_init (&buf, 4096);
+ xgmp_fmt_flag = 0;
+ va_copy (ap2, ap);
+ start = fmt;
+ while (*fmt)
+ {
+ /* Look for the next format specification */
+ while ((*fmt) && (*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, width_analysis);
+ width_analysis:
+ if (spec.width < 0)
+ {
+ spec.left = 1;
+ spec.width = -spec.width;
+ MPFR_ASSERTN (spec.width < INT_MAX);
+ }
+ if (*fmt == '.')
+ {
+ const char *f = ++fmt;
+ READ_INT (ap, fmt, spec, prec, prec_analysis);
+ prec_analysis:
+ if (f == fmt)
+ spec.prec = -1;
+ }
+ else
+ spec.prec = -1;
+
+ fmt = parse_arg_type (fmt, &spec);
+ if (spec.arg_type == UNSUPPORTED)
+ /* the current architecture doesn't support this type */
+ {
+ goto error;
+ }
+ 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;
+ default:
+ spec.rnd_mode = MPFR_RNDN;
+ }
+ }
+
+ spec.spec = *fmt;
+ if (!specinfo_is_valid (spec))
+ goto error;
+
+ if (*fmt)
+ 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;
+ 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;
+ break;
+ case SHORT_ARG:
+ *(short *) p = (short) nchar;
+ break;
+ case LONG_ARG:
+ *(long *) p = (long) nchar;
+ break;
+#ifdef HAVE_LONG_LONG
+ case LONG_LONG_ARG:
+ *(long long *) p = (long long) nchar;
+ break;
+#endif
+#ifdef _MPFR_H_HAVE_INTMAX_T
+ case INTMAX_ARG:
+ *(intmax_t *) p = (intmax_t) nchar;
+ break;
+#endif
+ case SIZE_ARG:
+ *(size_t *) p = nchar;
+ break;
+ case PTRDIFF_ARG:
+ *(ptrdiff_t *) p = (ptrdiff_t) nchar;
+ break;
+ case MPF_ARG:
+ mpf_set_ui ((mpf_ptr) p, (unsigned long) nchar);
+ break;
+ case MPQ_ARG:
+ mpq_set_ui ((mpq_ptr) p, (unsigned long) nchar, 1L);
+ break;
+ case MP_LIMB_ARG:
+ *(mp_limb_t *) p = (mp_limb_t) nchar;
+ 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) nchar;
+ while (--n != 0)
+ {
+ q++;
+ *q = (mp_limb_t) 0;
+ }
+ }
+ break;
+ case MPZ_ARG:
+ mpz_set_ui ((mpz_ptr) p, (unsigned long) nchar);
+ break;
+
+ case MPFR_ARG:
+ mpfr_set_ui ((mpfr_ptr) p, (unsigned long) nchar,
+ spec.rnd_mode);
+ break;
+
+ default:
+ *(int *) p = (int) nchar;
+ }
+ 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 + 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);
+ va_end (ap2);
+ va_copy (ap2, ap);
+ start = fmt;
+
+ /* construct format string, like "%*.*hu" "%*.*u" or "%*.*lu" */
+ format[0] = '%';
+ format[1] = '*';
+ format[2] = '.';
+ format[3] = '*';
+ format[4] = '\0';
+ strcat (format, MPFR_PREC_FORMAT_TYPE);
+ 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;
+ }
+ }
+ else if (spec.arg_type == MPFR_ARG)
+ /* output a mpfr_t variable */
+ {
+ mpfr_srcptr p;
+
+ p = va_arg (ap, mpfr_srcptr);
+
+ FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
+ va_end (ap2);
+ 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;
+ }
+ }
+ 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);
+ 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)
+ {
+ MPFR_SAVE_EXPO_FREE (expo);
+ return nbchar;
+ }
+
+ overflow_error:
+ MPFR_SAVE_EXPO_UPDATE_FLAGS(expo, MPFR_FLAGS_ERANGE);
+#ifdef EOVERFLOW
+ errno = EOVERFLOW;
+#endif
+
+ error:
+ MPFR_SAVE_EXPO_FREE (expo);
+ *ptr = NULL;
+ (*__gmp_free_func) (buf.start, buf.size);
+
+ return -1;
+}
+
+#endif /* HAVE_STDARG */