14a238c70SJohn Marino /* mpfr_vasprintf -- main function for the printf functions family
24a238c70SJohn Marino plus helper macros & functions.
34a238c70SJohn Marino
4ab6d115fSJohn Marino Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
5ab6d115fSJohn Marino Contributed by the AriC and Caramel projects, INRIA.
64a238c70SJohn Marino
74a238c70SJohn Marino This file is part of the GNU MPFR Library.
84a238c70SJohn Marino
94a238c70SJohn Marino The GNU MPFR Library is free software; you can redistribute it and/or modify
104a238c70SJohn Marino it under the terms of the GNU Lesser General Public License as published by
114a238c70SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
124a238c70SJohn Marino option) any later version.
134a238c70SJohn Marino
144a238c70SJohn Marino The GNU MPFR Library is distributed in the hope that it will be useful, but
154a238c70SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
164a238c70SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
174a238c70SJohn Marino License for more details.
184a238c70SJohn Marino
194a238c70SJohn Marino You should have received a copy of the GNU Lesser General Public License
204a238c70SJohn Marino along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
214a238c70SJohn Marino http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
224a238c70SJohn Marino 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
234a238c70SJohn Marino
244a238c70SJohn Marino #ifdef HAVE_CONFIG_H
254a238c70SJohn Marino #include "config.h"
264a238c70SJohn Marino #endif
274a238c70SJohn Marino
284a238c70SJohn Marino /* The mpfr_printf-like functions are defined only if <stdarg.h> exists */
294a238c70SJohn Marino #ifdef HAVE_STDARG
304a238c70SJohn Marino
314a238c70SJohn Marino #include <stdarg.h>
324a238c70SJohn Marino
334a238c70SJohn Marino #ifndef HAVE_VA_COPY
344a238c70SJohn Marino # ifdef HAVE___VA_COPY
354a238c70SJohn Marino # define va_copy(dst,src) __va_copy(dst, src)
364a238c70SJohn Marino # else
374a238c70SJohn Marino /* autoconf manual advocates this fallback.
384a238c70SJohn Marino This is also the solution chosen by gmp */
394a238c70SJohn Marino # define va_copy(dst,src) \
404a238c70SJohn Marino do { memcpy(&(dst), &(src), sizeof(va_list)); } while (0)
414a238c70SJohn Marino # endif /* HAVE___VA_COPY */
424a238c70SJohn Marino #endif /* HAVE_VA_COPY */
434a238c70SJohn Marino
444a238c70SJohn Marino #ifdef HAVE_WCHAR_H
454a238c70SJohn Marino #include <wchar.h>
464a238c70SJohn Marino #endif
474a238c70SJohn Marino
484a238c70SJohn Marino #if defined (__cplusplus)
494a238c70SJohn Marino #include <cstddef>
504a238c70SJohn Marino #define __STDC_LIMIT_MACROS /* SIZE_MAX defined with <stdint.h> inclusion */
514a238c70SJohn Marino #else
524a238c70SJohn Marino #include <stddef.h> /* for ptrdiff_t */
534a238c70SJohn Marino #endif
544a238c70SJohn Marino
554a238c70SJohn Marino #define MPFR_NEED_LONGLONG_H
564a238c70SJohn Marino #include "mpfr-intmax.h"
574a238c70SJohn Marino #include "mpfr-impl.h"
584a238c70SJohn Marino
594a238c70SJohn Marino /* Define a length modifier corresponding to mpfr_prec_t.
604a238c70SJohn Marino We use literal string instead of literal character so as to permit future
614a238c70SJohn Marino extension to long long int ("ll"). */
624a238c70SJohn Marino #if _MPFR_PREC_FORMAT == 1
634a238c70SJohn Marino #define MPFR_PREC_FORMAT_TYPE "h"
644a238c70SJohn Marino #define MPFR_PREC_FORMAT_SIZE 1
654a238c70SJohn Marino #elif _MPFR_PREC_FORMAT == 2
664a238c70SJohn Marino #define MPFR_PREC_FORMAT_TYPE ""
674a238c70SJohn Marino #define MPFR_PREC_FORMAT_SIZE 0
684a238c70SJohn Marino #elif _MPFR_PREC_FORMAT == 3
694a238c70SJohn Marino #define MPFR_PREC_FORMAT_TYPE "l"
704a238c70SJohn Marino #define MPFR_PREC_FORMAT_SIZE 1
714a238c70SJohn Marino #else
724a238c70SJohn Marino #error "mpfr_prec_t size not supported"
734a238c70SJohn Marino #endif
744a238c70SJohn Marino
754a238c70SJohn Marino /* Output for special values defined in the C99 standard */
764a238c70SJohn Marino #define MPFR_NAN_STRING_LC "nan"
774a238c70SJohn Marino #define MPFR_NAN_STRING_UC "NAN"
784a238c70SJohn Marino #define MPFR_NAN_STRING_LENGTH 3
794a238c70SJohn Marino #define MPFR_INF_STRING_LC "inf"
804a238c70SJohn Marino #define MPFR_INF_STRING_UC "INF"
814a238c70SJohn Marino #define MPFR_INF_STRING_LENGTH 3
824a238c70SJohn Marino
834a238c70SJohn Marino /* The implicit \0 is useless, but we do not write num_to_text[16]
844a238c70SJohn Marino otherwise g++ complains. */
854a238c70SJohn Marino static const char num_to_text[] = "0123456789abcdef";
864a238c70SJohn Marino
874a238c70SJohn Marino /* some macro and functions for parsing format string */
884a238c70SJohn Marino
894a238c70SJohn Marino /* Read an integer; saturate to INT_MAX. */
904a238c70SJohn Marino #define READ_INT(ap, format, specinfo, field, label_out) \
914a238c70SJohn Marino do { \
924a238c70SJohn Marino while (*(format)) \
934a238c70SJohn Marino { \
944a238c70SJohn Marino int _i; \
954a238c70SJohn Marino switch (*(format)) \
964a238c70SJohn Marino { \
974a238c70SJohn Marino case '0': \
984a238c70SJohn Marino case '1': \
994a238c70SJohn Marino case '2': \
1004a238c70SJohn Marino case '3': \
1014a238c70SJohn Marino case '4': \
1024a238c70SJohn Marino case '5': \
1034a238c70SJohn Marino case '6': \
1044a238c70SJohn Marino case '7': \
1054a238c70SJohn Marino case '8': \
1064a238c70SJohn Marino case '9': \
1074a238c70SJohn Marino specinfo.field = (specinfo.field <= INT_MAX / 10) ? \
1084a238c70SJohn Marino specinfo.field * 10 : INT_MAX; \
1094a238c70SJohn Marino _i = *(format) - '0'; \
1104a238c70SJohn Marino MPFR_ASSERTN (_i >= 0 && _i <= 9); \
1114a238c70SJohn Marino specinfo.field = (specinfo.field <= INT_MAX - _i) ? \
1124a238c70SJohn Marino specinfo.field + _i : INT_MAX; \
1134a238c70SJohn Marino ++(format); \
1144a238c70SJohn Marino break; \
1154a238c70SJohn Marino case '*': \
1164a238c70SJohn Marino specinfo.field = va_arg ((ap), int); \
1174a238c70SJohn Marino ++(format); \
1184a238c70SJohn Marino default: \
1194a238c70SJohn Marino goto label_out; \
1204a238c70SJohn Marino } \
1214a238c70SJohn Marino } \
1224a238c70SJohn Marino } while (0)
1234a238c70SJohn Marino
1244a238c70SJohn Marino /* arg_t contains all the types described by the 'type' field of the
1254a238c70SJohn Marino format string */
1264a238c70SJohn Marino enum arg_t
1274a238c70SJohn Marino {
1284a238c70SJohn Marino NONE,
1294a238c70SJohn Marino CHAR_ARG,
1304a238c70SJohn Marino SHORT_ARG,
1314a238c70SJohn Marino LONG_ARG,
1324a238c70SJohn Marino LONG_LONG_ARG,
1334a238c70SJohn Marino INTMAX_ARG,
1344a238c70SJohn Marino SIZE_ARG,
1354a238c70SJohn Marino PTRDIFF_ARG,
1364a238c70SJohn Marino LONG_DOUBLE_ARG,
1374a238c70SJohn Marino MPF_ARG,
1384a238c70SJohn Marino MPQ_ARG,
1394a238c70SJohn Marino MP_LIMB_ARG,
1404a238c70SJohn Marino MP_LIMB_ARRAY_ARG,
1414a238c70SJohn Marino MPZ_ARG,
1424a238c70SJohn Marino MPFR_PREC_ARG,
1434a238c70SJohn Marino MPFR_ARG,
1444a238c70SJohn Marino UNSUPPORTED
1454a238c70SJohn Marino };
1464a238c70SJohn Marino
1474a238c70SJohn Marino /* Each conversion specification of the format string will be translated in a
1484a238c70SJohn Marino printf_spec structure by the parser.
1494a238c70SJohn Marino This structure is adapted from the GNU libc one. */
1504a238c70SJohn Marino struct printf_spec
1514a238c70SJohn Marino {
1524a238c70SJohn Marino unsigned int alt:1; /* # flag */
1534a238c70SJohn Marino unsigned int space:1; /* Space flag */
1544a238c70SJohn Marino unsigned int left:1; /* - flag */
1554a238c70SJohn Marino unsigned int showsign:1; /* + flag */
1564a238c70SJohn Marino unsigned int group:1; /* ' flag */
1574a238c70SJohn Marino
1584a238c70SJohn Marino int width; /* Width */
1594a238c70SJohn Marino int prec; /* Precision */
1604a238c70SJohn Marino
1614a238c70SJohn Marino enum arg_t arg_type; /* Type of argument */
1624a238c70SJohn Marino mpfr_rnd_t rnd_mode; /* Rounding mode */
1634a238c70SJohn Marino char spec; /* Conversion specifier */
1644a238c70SJohn Marino
1654a238c70SJohn Marino char pad; /* Padding character */
1664a238c70SJohn Marino };
1674a238c70SJohn Marino
1684a238c70SJohn Marino static void
specinfo_init(struct printf_spec * specinfo)1694a238c70SJohn Marino specinfo_init (struct printf_spec *specinfo)
1704a238c70SJohn Marino {
1714a238c70SJohn Marino specinfo->alt = 0;
1724a238c70SJohn Marino specinfo->space = 0;
1734a238c70SJohn Marino specinfo->left = 0;
1744a238c70SJohn Marino specinfo->showsign = 0;
1754a238c70SJohn Marino specinfo->group = 0;
1764a238c70SJohn Marino specinfo->width = 0;
1774a238c70SJohn Marino specinfo->prec = 0;
1784a238c70SJohn Marino specinfo->arg_type = NONE;
1794a238c70SJohn Marino specinfo->rnd_mode = MPFR_RNDN;
1804a238c70SJohn Marino specinfo->spec = '\0';
1814a238c70SJohn Marino specinfo->pad = ' ';
1824a238c70SJohn Marino }
1834a238c70SJohn Marino
1844a238c70SJohn Marino #define FLOATING_POINT_ARG_TYPE(at) \
1854a238c70SJohn Marino ((at) == MPFR_ARG || (at) == MPF_ARG || (at) == LONG_DOUBLE_ARG)
1864a238c70SJohn Marino
1874a238c70SJohn Marino #define INTEGER_LIKE_ARG_TYPE(at) \
1884a238c70SJohn Marino ((at) == SHORT_ARG || (at) == LONG_ARG || (at) == LONG_LONG_ARG \
1894a238c70SJohn Marino || (at) == INTMAX_ARG || (at) == MPFR_PREC_ARG || (at) == MPZ_ARG \
1904a238c70SJohn Marino || (at) == MPQ_ARG || (at) == MP_LIMB_ARG || (at) == MP_LIMB_ARRAY_ARG \
1914a238c70SJohn Marino || (at) == CHAR_ARG || (at) == SIZE_ARG || (at) == PTRDIFF_ARG)
1924a238c70SJohn Marino
1934a238c70SJohn Marino static int
specinfo_is_valid(struct printf_spec spec)1944a238c70SJohn Marino specinfo_is_valid (struct printf_spec spec)
1954a238c70SJohn Marino {
1964a238c70SJohn Marino switch (spec.spec)
1974a238c70SJohn Marino {
1984a238c70SJohn Marino case 'n':
1994a238c70SJohn Marino return -1;
2004a238c70SJohn Marino
2014a238c70SJohn Marino case 'a': case 'A':
2024a238c70SJohn Marino case 'e': case 'E':
2034a238c70SJohn Marino case 'f': case 'F':
2044a238c70SJohn Marino case 'g': case 'G':
2054a238c70SJohn Marino return (spec.arg_type == NONE
2064a238c70SJohn Marino || FLOATING_POINT_ARG_TYPE (spec.arg_type));
2074a238c70SJohn Marino
2084a238c70SJohn Marino case 'b':
2094a238c70SJohn Marino return spec.arg_type == MPFR_ARG;
2104a238c70SJohn Marino
2114a238c70SJohn Marino case 'd': case 'i':
2124a238c70SJohn Marino case 'u': case 'o':
2134a238c70SJohn Marino case 'x': case 'X':
2144a238c70SJohn Marino return (spec.arg_type == NONE
2154a238c70SJohn Marino || INTEGER_LIKE_ARG_TYPE (spec.arg_type));
2164a238c70SJohn Marino
2174a238c70SJohn Marino case 'c':
2184a238c70SJohn Marino case 's':
2194a238c70SJohn Marino return (spec.arg_type == NONE || spec.arg_type == LONG_ARG);
2204a238c70SJohn Marino
2214a238c70SJohn Marino case 'p':
2224a238c70SJohn Marino return spec.arg_type == NONE;
2234a238c70SJohn Marino
2244a238c70SJohn Marino default:
2254a238c70SJohn Marino return 0;
2264a238c70SJohn Marino }
2274a238c70SJohn Marino }
2284a238c70SJohn Marino
2294a238c70SJohn Marino static const char *
parse_flags(const char * format,struct printf_spec * specinfo)2304a238c70SJohn Marino parse_flags (const char *format, struct printf_spec *specinfo)
2314a238c70SJohn Marino {
2324a238c70SJohn Marino while (*format)
2334a238c70SJohn Marino {
2344a238c70SJohn Marino switch (*format)
2354a238c70SJohn Marino {
2364a238c70SJohn Marino case '0':
2374a238c70SJohn Marino specinfo->pad = '0';
2384a238c70SJohn Marino ++format;
2394a238c70SJohn Marino break;
2404a238c70SJohn Marino case '#':
2414a238c70SJohn Marino specinfo->alt = 1;
2424a238c70SJohn Marino ++format;
2434a238c70SJohn Marino break;
2444a238c70SJohn Marino case '+':
2454a238c70SJohn Marino specinfo->showsign = 1;
2464a238c70SJohn Marino ++format;
2474a238c70SJohn Marino break;
2484a238c70SJohn Marino case ' ':
2494a238c70SJohn Marino specinfo->space = 1;
2504a238c70SJohn Marino ++format;
2514a238c70SJohn Marino break;
2524a238c70SJohn Marino case '-':
2534a238c70SJohn Marino specinfo->left = 1;
2544a238c70SJohn Marino ++format;
2554a238c70SJohn Marino break;
2564a238c70SJohn Marino case '\'':
2574a238c70SJohn Marino /* Single UNIX Specification for thousand separator */
2584a238c70SJohn Marino specinfo->group = 1;
2594a238c70SJohn Marino ++format;
2604a238c70SJohn Marino break;
2614a238c70SJohn Marino default:
2624a238c70SJohn Marino return format;
2634a238c70SJohn Marino }
2644a238c70SJohn Marino }
2654a238c70SJohn Marino return format;
2664a238c70SJohn Marino }
2674a238c70SJohn Marino
2684a238c70SJohn Marino static const char *
parse_arg_type(const char * format,struct printf_spec * specinfo)2694a238c70SJohn Marino parse_arg_type (const char *format, struct printf_spec *specinfo)
2704a238c70SJohn Marino {
2714a238c70SJohn Marino switch (*format)
2724a238c70SJohn Marino {
2734a238c70SJohn Marino case '\0':
2744a238c70SJohn Marino break;
2754a238c70SJohn Marino case 'h':
2764a238c70SJohn Marino if (*++format == 'h')
2774a238c70SJohn Marino #ifndef NPRINTF_HH
2784a238c70SJohn Marino {
2794a238c70SJohn Marino ++format;
2804a238c70SJohn Marino specinfo->arg_type = CHAR_ARG;
2814a238c70SJohn Marino }
2824a238c70SJohn Marino #else
2834a238c70SJohn Marino specinfo->arg_type = UNSUPPORTED;
2844a238c70SJohn Marino #endif
2854a238c70SJohn Marino else
2864a238c70SJohn Marino specinfo->arg_type = SHORT_ARG;
2874a238c70SJohn Marino break;
2884a238c70SJohn Marino case 'l':
2894a238c70SJohn Marino if (*++format == 'l')
2904a238c70SJohn Marino {
2914a238c70SJohn Marino ++format;
2924a238c70SJohn Marino #if defined (HAVE_LONG_LONG) && !defined(NPRINTF_LL)
2934a238c70SJohn Marino specinfo->arg_type = LONG_LONG_ARG;
2944a238c70SJohn Marino #else
2954a238c70SJohn Marino specinfo->arg_type = UNSUPPORTED;
2964a238c70SJohn Marino #endif
2974a238c70SJohn Marino break;
2984a238c70SJohn Marino }
2994a238c70SJohn Marino else
3004a238c70SJohn Marino {
3014a238c70SJohn Marino specinfo->arg_type = LONG_ARG;
3024a238c70SJohn Marino break;
3034a238c70SJohn Marino }
3044a238c70SJohn Marino case 'j':
3054a238c70SJohn Marino ++format;
3064a238c70SJohn Marino #if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J)
3074a238c70SJohn Marino specinfo->arg_type = INTMAX_ARG;
3084a238c70SJohn Marino #else
3094a238c70SJohn Marino specinfo->arg_type = UNSUPPORTED;
3104a238c70SJohn Marino #endif
3114a238c70SJohn Marino break;
3124a238c70SJohn Marino case 'z':
3134a238c70SJohn Marino ++format;
3144a238c70SJohn Marino specinfo->arg_type = SIZE_ARG;
3154a238c70SJohn Marino break;
3164a238c70SJohn Marino case 't':
3174a238c70SJohn Marino ++format;
3184a238c70SJohn Marino #ifndef NPRINTF_T
3194a238c70SJohn Marino specinfo->arg_type = PTRDIFF_ARG;
3204a238c70SJohn Marino #else
3214a238c70SJohn Marino specinfo->arg_type = UNSUPPORTED;
3224a238c70SJohn Marino #endif
3234a238c70SJohn Marino break;
3244a238c70SJohn Marino case 'L':
3254a238c70SJohn Marino ++format;
3264a238c70SJohn Marino #ifndef NPRINTF_L
3274a238c70SJohn Marino specinfo->arg_type = LONG_DOUBLE_ARG;
3284a238c70SJohn Marino #else
3294a238c70SJohn Marino specinfo->arg_type = UNSUPPORTED;
3304a238c70SJohn Marino #endif
3314a238c70SJohn Marino break;
3324a238c70SJohn Marino case 'F':
3334a238c70SJohn Marino ++format;
3344a238c70SJohn Marino specinfo->arg_type = MPF_ARG;
3354a238c70SJohn Marino break;
3364a238c70SJohn Marino case 'Q':
3374a238c70SJohn Marino ++format;
3384a238c70SJohn Marino specinfo->arg_type = MPQ_ARG;
3394a238c70SJohn Marino break;
3404a238c70SJohn Marino case 'M':
3414a238c70SJohn Marino ++format;
3424a238c70SJohn Marino /* The 'M' specifier was added in gmp 4.2.0 */
3434a238c70SJohn Marino specinfo->arg_type = MP_LIMB_ARG;
3444a238c70SJohn Marino break;
3454a238c70SJohn Marino case 'N':
3464a238c70SJohn Marino ++format;
3474a238c70SJohn Marino specinfo->arg_type = MP_LIMB_ARRAY_ARG;
3484a238c70SJohn Marino break;
3494a238c70SJohn Marino case 'Z':
3504a238c70SJohn Marino ++format;
3514a238c70SJohn Marino specinfo->arg_type = MPZ_ARG;
3524a238c70SJohn Marino break;
3534a238c70SJohn Marino
3544a238c70SJohn Marino /* mpfr specific specifiers */
3554a238c70SJohn Marino case 'P':
3564a238c70SJohn Marino ++format;
3574a238c70SJohn Marino specinfo->arg_type = MPFR_PREC_ARG;
3584a238c70SJohn Marino break;
3594a238c70SJohn Marino case 'R':
3604a238c70SJohn Marino ++format;
3614a238c70SJohn Marino specinfo->arg_type = MPFR_ARG;
3624a238c70SJohn Marino }
3634a238c70SJohn Marino return format;
3644a238c70SJohn Marino }
3654a238c70SJohn Marino
3664a238c70SJohn Marino
3674a238c70SJohn Marino /* some macros and functions filling the buffer */
3684a238c70SJohn Marino
3694a238c70SJohn Marino /* CONSUME_VA_ARG removes from va_list AP the type expected by SPECINFO */
3704a238c70SJohn Marino
3714a238c70SJohn Marino /* With a C++ compiler wchar_t and enumeration in va_list are converted to
3724a238c70SJohn Marino integer type : int, unsigned int, long or unsigned long (unfortunately,
3734a238c70SJohn Marino this is implementation dependant).
3744a238c70SJohn Marino We follow gmp which assumes in print/doprnt.c that wchar_t is converted
3754a238c70SJohn Marino to int (because wchar_t <= int).
3764a238c70SJohn Marino For wint_t, we assume that the case WINT_MAX < INT_MAX yields an
3774a238c70SJohn Marino integer promotion. */
3784a238c70SJohn Marino #ifdef HAVE_WCHAR_H
3794a238c70SJohn Marino #if defined(WINT_MAX) && WINT_MAX < INT_MAX
3804a238c70SJohn Marino typedef int mpfr_va_wint; /* integer promotion */
3814a238c70SJohn Marino #else
3824a238c70SJohn Marino typedef wint_t mpfr_va_wint;
3834a238c70SJohn Marino #endif
3844a238c70SJohn Marino #define CASE_LONG_ARG(specinfo, ap) \
3854a238c70SJohn Marino case LONG_ARG: \
3864a238c70SJohn Marino if (((specinfo).spec == 'd') || ((specinfo).spec == 'i') \
3874a238c70SJohn Marino || ((specinfo).spec == 'o') || ((specinfo).spec == 'u') \
3884a238c70SJohn Marino || ((specinfo).spec == 'x') || ((specinfo).spec == 'X')) \
3894a238c70SJohn Marino (void) va_arg ((ap), long); \
3904a238c70SJohn Marino else if ((specinfo).spec == 'c') \
3914a238c70SJohn Marino (void) va_arg ((ap), mpfr_va_wint); \
3924a238c70SJohn Marino else if ((specinfo).spec == 's') \
3934a238c70SJohn Marino (void) va_arg ((ap), int); /* we assume integer promotion */ \
3944a238c70SJohn Marino break;
3954a238c70SJohn Marino #else
3964a238c70SJohn Marino #define CASE_LONG_ARG(specinfo, ap) \
3974a238c70SJohn Marino case LONG_ARG: \
3984a238c70SJohn Marino (void) va_arg ((ap), long); \
3994a238c70SJohn Marino break;
4004a238c70SJohn Marino #endif
4014a238c70SJohn Marino
4024a238c70SJohn Marino #if defined(_MPFR_H_HAVE_INTMAX_T)
4034a238c70SJohn Marino #define CASE_INTMAX_ARG(specinfo, ap) \
4044a238c70SJohn Marino case INTMAX_ARG: \
4054a238c70SJohn Marino (void) va_arg ((ap), intmax_t); \
4064a238c70SJohn Marino break;
4074a238c70SJohn Marino #else
4084a238c70SJohn Marino #define CASE_INTMAX_ARG(specinfo, ap)
4094a238c70SJohn Marino #endif
4104a238c70SJohn Marino
4114a238c70SJohn Marino #ifdef HAVE_LONG_LONG
4124a238c70SJohn Marino #define CASE_LONG_LONG_ARG(specinfo, ap) \
4134a238c70SJohn Marino case LONG_LONG_ARG: \
4144a238c70SJohn Marino (void) va_arg ((ap), long long); \
4154a238c70SJohn Marino break;
4164a238c70SJohn Marino #else
4174a238c70SJohn Marino #define CASE_LONG_LONG_ARG(specinfo, ap)
4184a238c70SJohn Marino #endif
4194a238c70SJohn Marino
4204a238c70SJohn Marino #define CONSUME_VA_ARG(specinfo, ap) \
4214a238c70SJohn Marino do { \
4224a238c70SJohn Marino switch ((specinfo).arg_type) \
4234a238c70SJohn Marino { \
4244a238c70SJohn Marino case CHAR_ARG: \
4254a238c70SJohn Marino case SHORT_ARG: \
4264a238c70SJohn Marino (void) va_arg ((ap), int); \
4274a238c70SJohn Marino break; \
4284a238c70SJohn Marino CASE_LONG_ARG (specinfo, ap) \
4294a238c70SJohn Marino CASE_LONG_LONG_ARG (specinfo, ap) \
4304a238c70SJohn Marino CASE_INTMAX_ARG (specinfo, ap) \
4314a238c70SJohn Marino case SIZE_ARG: \
4324a238c70SJohn Marino (void) va_arg ((ap), size_t); \
4334a238c70SJohn Marino break; \
4344a238c70SJohn Marino case PTRDIFF_ARG: \
4354a238c70SJohn Marino (void) va_arg ((ap), ptrdiff_t); \
4364a238c70SJohn Marino break; \
4374a238c70SJohn Marino case LONG_DOUBLE_ARG: \
4384a238c70SJohn Marino (void) va_arg ((ap), long double); \
4394a238c70SJohn Marino break; \
4404a238c70SJohn Marino case MPF_ARG: \
4414a238c70SJohn Marino (void) va_arg ((ap), mpf_srcptr); \
4424a238c70SJohn Marino break; \
4434a238c70SJohn Marino case MPQ_ARG: \
4444a238c70SJohn Marino (void) va_arg ((ap), mpq_srcptr); \
4454a238c70SJohn Marino break; \
4464a238c70SJohn Marino case MP_LIMB_ARG: \
4474a238c70SJohn Marino (void) va_arg ((ap), mp_limb_t); \
4484a238c70SJohn Marino break; \
4494a238c70SJohn Marino case MP_LIMB_ARRAY_ARG: \
4504a238c70SJohn Marino (void) va_arg ((ap), mpfr_limb_ptr); \
4514a238c70SJohn Marino (void) va_arg ((ap), mp_size_t); \
4524a238c70SJohn Marino break; \
4534a238c70SJohn Marino case MPZ_ARG: \
4544a238c70SJohn Marino (void) va_arg ((ap), mpz_srcptr); \
4554a238c70SJohn Marino break; \
4564a238c70SJohn Marino default: \
4574a238c70SJohn Marino switch ((specinfo).spec) \
4584a238c70SJohn Marino { \
4594a238c70SJohn Marino case 'd': \
4604a238c70SJohn Marino case 'i': \
4614a238c70SJohn Marino case 'o': \
4624a238c70SJohn Marino case 'u': \
4634a238c70SJohn Marino case 'x': \
4644a238c70SJohn Marino case 'X': \
4654a238c70SJohn Marino case 'c': \
4664a238c70SJohn Marino (void) va_arg ((ap), int); \
4674a238c70SJohn Marino break; \
4684a238c70SJohn Marino case 'f': \
4694a238c70SJohn Marino case 'F': \
4704a238c70SJohn Marino case 'e': \
4714a238c70SJohn Marino case 'E': \
4724a238c70SJohn Marino case 'g': \
4734a238c70SJohn Marino case 'G': \
4744a238c70SJohn Marino case 'a': \
4754a238c70SJohn Marino case 'A': \
4764a238c70SJohn Marino (void) va_arg ((ap), double); \
4774a238c70SJohn Marino break; \
4784a238c70SJohn Marino case 's': \
4794a238c70SJohn Marino (void) va_arg ((ap), char *); \
4804a238c70SJohn Marino break; \
4814a238c70SJohn Marino case 'p': \
4824a238c70SJohn Marino (void) va_arg ((ap), void *); \
4834a238c70SJohn Marino } \
4844a238c70SJohn Marino } \
4854a238c70SJohn Marino } while (0)
4864a238c70SJohn Marino
4874a238c70SJohn Marino /* process the format part which does not deal with mpfr types,
4884a238c70SJohn Marino jump to external label 'error' if gmp_asprintf return -1. */
4894a238c70SJohn Marino #define FLUSH(flag, start, end, ap, buf_ptr) \
4904a238c70SJohn Marino do { \
4914a238c70SJohn Marino const size_t n = (end) - (start); \
4924a238c70SJohn Marino if ((flag)) \
4934a238c70SJohn Marino /* previous specifiers are understood by gmp_printf */ \
4944a238c70SJohn Marino { \
4954a238c70SJohn Marino MPFR_TMP_DECL (marker); \
4964a238c70SJohn Marino char *fmt_copy; \
4974a238c70SJohn Marino MPFR_TMP_MARK (marker); \
4984a238c70SJohn Marino fmt_copy = (char*) MPFR_TMP_ALLOC (n + 1); \
4994a238c70SJohn Marino strncpy (fmt_copy, (start), n); \
5004a238c70SJohn Marino fmt_copy[n] = '\0'; \
5014a238c70SJohn Marino if (sprntf_gmp ((buf_ptr), (fmt_copy), (ap)) == -1) \
5024a238c70SJohn Marino { \
5034a238c70SJohn Marino MPFR_TMP_FREE (marker); \
5044a238c70SJohn Marino goto error; \
5054a238c70SJohn Marino } \
5064a238c70SJohn Marino (flag) = 0; \
5074a238c70SJohn Marino MPFR_TMP_FREE (marker); \
5084a238c70SJohn Marino } \
5094a238c70SJohn Marino else if ((start) != (end)) \
5104a238c70SJohn Marino /* no conversion specification, just simple characters */ \
5114a238c70SJohn Marino buffer_cat ((buf_ptr), (start), n); \
5124a238c70SJohn Marino } while (0)
5134a238c70SJohn Marino
5144a238c70SJohn Marino struct string_buffer
5154a238c70SJohn Marino {
5164a238c70SJohn Marino char *start; /* beginning of the buffer */
5174a238c70SJohn Marino char *curr; /* null terminating character */
5184a238c70SJohn Marino size_t size; /* buffer capacity */
5194a238c70SJohn Marino };
5204a238c70SJohn Marino
5214a238c70SJohn Marino static void
buffer_init(struct string_buffer * b,size_t s)5224a238c70SJohn Marino buffer_init (struct string_buffer *b, size_t s)
5234a238c70SJohn Marino {
5244a238c70SJohn Marino b->start = (char *) (*__gmp_allocate_func) (s);
5254a238c70SJohn Marino b->start[0] = '\0';
5264a238c70SJohn Marino b->curr = b->start;
5274a238c70SJohn Marino b->size = s;
5284a238c70SJohn Marino }
5294a238c70SJohn Marino
5304a238c70SJohn Marino /* Increase buffer size by a number of character being the least multiple of
5314a238c70SJohn Marino 4096 greater than LEN+1. */
5324a238c70SJohn Marino static void
buffer_widen(struct string_buffer * b,size_t len)5334a238c70SJohn Marino buffer_widen (struct string_buffer *b, size_t len)
5344a238c70SJohn Marino {
5354a238c70SJohn Marino const size_t pos = b->curr - b->start;
5364a238c70SJohn Marino const size_t n = 0x1000 + (len & ~((size_t) 0xfff));
5374a238c70SJohn Marino MPFR_ASSERTD (pos < b->size);
5384a238c70SJohn Marino
5394a238c70SJohn Marino MPFR_ASSERTN ((len & ~((size_t) 4095)) <= (size_t)(SIZE_MAX - 4096));
5404a238c70SJohn Marino MPFR_ASSERTN (b->size < SIZE_MAX - n);
5414a238c70SJohn Marino
5424a238c70SJohn Marino b->start =
5434a238c70SJohn Marino (char *) (*__gmp_reallocate_func) (b->start, b->size, b->size + n);
5444a238c70SJohn Marino b->size += n;
5454a238c70SJohn Marino b->curr = b->start + pos;
5464a238c70SJohn Marino
5474a238c70SJohn Marino MPFR_ASSERTD (pos < b->size);
5484a238c70SJohn Marino MPFR_ASSERTD (*b->curr == '\0');
5494a238c70SJohn Marino }
5504a238c70SJohn Marino
5514a238c70SJohn Marino /* Concatenate the LEN first characters of the string S to the buffer B and
5524a238c70SJohn Marino expand it if needed. */
5534a238c70SJohn Marino static void
buffer_cat(struct string_buffer * b,const char * s,size_t len)5544a238c70SJohn Marino buffer_cat (struct string_buffer *b, const char *s, size_t len)
5554a238c70SJohn Marino {
5564a238c70SJohn Marino MPFR_ASSERTD (len != 0);
5574a238c70SJohn Marino MPFR_ASSERTD (len <= strlen (s));
5584a238c70SJohn Marino
5594a238c70SJohn Marino if (MPFR_UNLIKELY ((b->curr + len) >= (b->start + b->size)))
5604a238c70SJohn Marino buffer_widen (b, len);
5614a238c70SJohn Marino
5624a238c70SJohn Marino strncat (b->curr, s, len);
5634a238c70SJohn Marino b->curr += len;
5644a238c70SJohn Marino
5654a238c70SJohn Marino MPFR_ASSERTD (b->curr < b->start + b->size);
5664a238c70SJohn Marino MPFR_ASSERTD (*b->curr == '\0');
5674a238c70SJohn Marino }
5684a238c70SJohn Marino
5694a238c70SJohn Marino /* Add N characters C to the end of buffer B */
5704a238c70SJohn Marino static void
buffer_pad(struct string_buffer * b,const char c,const size_t n)5714a238c70SJohn Marino buffer_pad (struct string_buffer *b, const char c, const size_t n)
5724a238c70SJohn Marino {
5734a238c70SJohn Marino MPFR_ASSERTD (n != 0);
5744a238c70SJohn Marino
5754a238c70SJohn Marino MPFR_ASSERTN (b->size < SIZE_MAX - n - 1);
5764a238c70SJohn Marino if (MPFR_UNLIKELY ((b->curr + n + 1) > (b->start + b->size)))
5774a238c70SJohn Marino buffer_widen (b, n);
5784a238c70SJohn Marino
5794a238c70SJohn Marino if (n == 1)
5804a238c70SJohn Marino *b->curr = c;
5814a238c70SJohn Marino else
5824a238c70SJohn Marino memset (b->curr, c, n);
5834a238c70SJohn Marino b->curr += n;
5844a238c70SJohn Marino *b->curr = '\0';
5854a238c70SJohn Marino
5864a238c70SJohn Marino MPFR_ASSERTD (b->curr < b->start + b->size);
5874a238c70SJohn Marino }
5884a238c70SJohn Marino
5894a238c70SJohn Marino /* Form a string by concatenating the first LEN characters of STR to TZ
5904a238c70SJohn Marino zero(s), insert into one character C each 3 characters starting from end
5914a238c70SJohn Marino to begining and concatenate the result to the buffer B. */
5924a238c70SJohn Marino static void
buffer_sandwich(struct string_buffer * b,char * str,size_t len,const size_t tz,const char c)5934a238c70SJohn Marino buffer_sandwich (struct string_buffer *b, char *str, size_t len,
5944a238c70SJohn Marino const size_t tz, const char c)
5954a238c70SJohn Marino {
5964a238c70SJohn Marino const size_t step = 3;
5974a238c70SJohn Marino const size_t size = len + tz;
5984a238c70SJohn Marino const size_t r = size % step == 0 ? step : size % step;
5994a238c70SJohn Marino const size_t q = size % step == 0 ? size / step - 1 : size / step;
6004a238c70SJohn Marino size_t i;
6014a238c70SJohn Marino
6024a238c70SJohn Marino MPFR_ASSERTD (size != 0);
6034a238c70SJohn Marino if (c == '\0')
6044a238c70SJohn Marino {
6054a238c70SJohn Marino buffer_cat (b, str, len);
6064a238c70SJohn Marino buffer_pad (b, '0', tz);
6074a238c70SJohn Marino return;
6084a238c70SJohn Marino }
6094a238c70SJohn Marino
6104a238c70SJohn Marino MPFR_ASSERTN (b->size < SIZE_MAX - size - 1 - q);
6114a238c70SJohn Marino MPFR_ASSERTD (len <= strlen (str));
6124a238c70SJohn Marino if (MPFR_UNLIKELY ((b->curr + size + 1 + q) > (b->start + b->size)))
6134a238c70SJohn Marino buffer_widen (b, size + q);
6144a238c70SJohn Marino
6154a238c70SJohn Marino /* first R significant digits */
6164a238c70SJohn Marino memcpy (b->curr, str, r);
6174a238c70SJohn Marino b->curr += r;
6184a238c70SJohn Marino str += r;
6194a238c70SJohn Marino len -= r;
6204a238c70SJohn Marino
6214a238c70SJohn Marino /* blocks of thousands. Warning: STR might end in the middle of a block */
6224a238c70SJohn Marino for (i = 0; i < q; ++i)
6234a238c70SJohn Marino {
6244a238c70SJohn Marino *b->curr++ = c;
6254a238c70SJohn Marino if (MPFR_LIKELY (len > 0))
6264a238c70SJohn Marino {
6274a238c70SJohn Marino if (MPFR_LIKELY (len >= step))
6284a238c70SJohn Marino /* step significant digits */
6294a238c70SJohn Marino {
6304a238c70SJohn Marino memcpy (b->curr, str, step);
6314a238c70SJohn Marino len -= step;
6324a238c70SJohn Marino }
6334a238c70SJohn Marino else
6344a238c70SJohn Marino /* last digits in STR, fill up thousand block with zeros */
6354a238c70SJohn Marino {
6364a238c70SJohn Marino memcpy (b->curr, str, len);
6374a238c70SJohn Marino memset (b->curr + len, '0', step - len);
6384a238c70SJohn Marino len = 0;
6394a238c70SJohn Marino }
6404a238c70SJohn Marino }
6414a238c70SJohn Marino else
6424a238c70SJohn Marino /* trailing zeros */
6434a238c70SJohn Marino memset (b->curr, '0', step);
6444a238c70SJohn Marino
6454a238c70SJohn Marino b->curr += step;
6464a238c70SJohn Marino str += step;
6474a238c70SJohn Marino }
6484a238c70SJohn Marino
6494a238c70SJohn Marino *b->curr = '\0';
6504a238c70SJohn Marino
6514a238c70SJohn Marino MPFR_ASSERTD (b->curr < b->start + b->size);
6524a238c70SJohn Marino }
6534a238c70SJohn Marino
6544a238c70SJohn Marino /* let gmp_xprintf process the part it can understand */
6554a238c70SJohn Marino static int
sprntf_gmp(struct string_buffer * b,const char * fmt,va_list ap)6564a238c70SJohn Marino sprntf_gmp (struct string_buffer *b, const char *fmt, va_list ap)
6574a238c70SJohn Marino {
6584a238c70SJohn Marino int length;
6594a238c70SJohn Marino char *s;
6604a238c70SJohn Marino
6614a238c70SJohn Marino length = gmp_vasprintf (&s, fmt, ap);
6624a238c70SJohn Marino if (length > 0)
6634a238c70SJohn Marino buffer_cat (b, s, length);
6644a238c70SJohn Marino
6654a238c70SJohn Marino mpfr_free_str (s);
6664a238c70SJohn Marino return length;
6674a238c70SJohn Marino }
6684a238c70SJohn Marino
6694a238c70SJohn Marino /* Helper struct and functions for temporary strings management */
6704a238c70SJohn Marino /* struct for easy string clearing */
6714a238c70SJohn Marino struct string_list
6724a238c70SJohn Marino {
6734a238c70SJohn Marino char *string;
6744a238c70SJohn Marino struct string_list *next; /* NULL in last node */
6754a238c70SJohn Marino };
6764a238c70SJohn Marino
6774a238c70SJohn Marino /* initialisation */
6784a238c70SJohn Marino static void
init_string_list(struct string_list * sl)6794a238c70SJohn Marino init_string_list (struct string_list *sl)
6804a238c70SJohn Marino {
6814a238c70SJohn Marino sl->string = NULL;
6824a238c70SJohn Marino sl->next = NULL;
6834a238c70SJohn Marino }
6844a238c70SJohn Marino
6854a238c70SJohn Marino /* clear all strings in the list */
6864a238c70SJohn Marino static void
clear_string_list(struct string_list * sl)6874a238c70SJohn Marino clear_string_list (struct string_list *sl)
6884a238c70SJohn Marino {
6894a238c70SJohn Marino struct string_list *n;
6904a238c70SJohn Marino
6914a238c70SJohn Marino while (sl)
6924a238c70SJohn Marino {
6934a238c70SJohn Marino if (sl->string)
6944a238c70SJohn Marino mpfr_free_str (sl->string);
6954a238c70SJohn Marino n = sl->next;
6964a238c70SJohn Marino (*__gmp_free_func) (sl, sizeof(struct string_list));
6974a238c70SJohn Marino sl = n;
6984a238c70SJohn Marino }
6994a238c70SJohn Marino }
7004a238c70SJohn Marino
7014a238c70SJohn Marino /* add a string in the list */
7024a238c70SJohn Marino static char *
register_string(struct string_list * sl,char * new_string)7034a238c70SJohn Marino register_string (struct string_list *sl, char *new_string)
7044a238c70SJohn Marino {
7054a238c70SJohn Marino /* look for the last node */
7064a238c70SJohn Marino while (sl->next)
7074a238c70SJohn Marino sl = sl->next;
7084a238c70SJohn Marino
7094a238c70SJohn Marino sl->next = (struct string_list*)
7104a238c70SJohn Marino (*__gmp_allocate_func) (sizeof (struct string_list));
7114a238c70SJohn Marino
7124a238c70SJohn Marino sl = sl->next;
7134a238c70SJohn Marino sl->next = NULL;
7144a238c70SJohn Marino return sl->string = new_string;
7154a238c70SJohn Marino }
7164a238c70SJohn Marino
7174a238c70SJohn Marino /* padding type: where are the padding characters */
7184a238c70SJohn Marino enum pad_t
7194a238c70SJohn Marino {
7204a238c70SJohn Marino LEFT, /* spaces in left hand side for right justification */
7214a238c70SJohn Marino LEADING_ZEROS, /* padding with '0' characters in integral part */
7224a238c70SJohn Marino RIGHT /* spaces in right hand side for left justification */
7234a238c70SJohn Marino };
7244a238c70SJohn Marino
7254a238c70SJohn Marino /* number_parts details how much characters are needed in each part of a float
7264a238c70SJohn Marino print. */
7274a238c70SJohn Marino struct number_parts
7284a238c70SJohn Marino {
7294a238c70SJohn Marino enum pad_t pad_type; /* Padding type */
7304a238c70SJohn Marino size_t pad_size; /* Number of padding characters */
7314a238c70SJohn Marino
7324a238c70SJohn Marino char sign; /* Sign character */
7334a238c70SJohn Marino
7344a238c70SJohn Marino char *prefix_ptr; /* Pointer to prefix part */
7354a238c70SJohn Marino size_t prefix_size; /* Number of characters in *prefix_ptr */
7364a238c70SJohn Marino
7374a238c70SJohn Marino char thousands_sep; /* Thousands separator (only with style 'f') */
7384a238c70SJohn Marino
7394a238c70SJohn Marino char *ip_ptr; /* Pointer to integral part characters*/
7404a238c70SJohn Marino size_t ip_size; /* Number of digits in *ip_ptr */
7414a238c70SJohn Marino int ip_trailing_zeros; /* Number of additional null digits in integral
7424a238c70SJohn Marino part */
7434a238c70SJohn Marino
7444a238c70SJohn Marino char point; /* Decimal point character */
7454a238c70SJohn Marino
7464a238c70SJohn Marino int fp_leading_zeros; /* Number of additional leading zeros in fractional
7474a238c70SJohn Marino part */
7484a238c70SJohn Marino char *fp_ptr; /* Pointer to fractional part characters */
7494a238c70SJohn Marino size_t fp_size; /* Number of digits in *fp_ptr */
7504a238c70SJohn Marino int fp_trailing_zeros; /* Number of additional trailing zeros in fractional
7514a238c70SJohn Marino part */
7524a238c70SJohn Marino
7534a238c70SJohn Marino char *exp_ptr; /* Pointer to exponent part */
7544a238c70SJohn Marino size_t exp_size; /* Number of characters in *exp_ptr */
7554a238c70SJohn Marino
7564a238c70SJohn Marino struct string_list *sl; /* List of string buffers in use: we need such a
7574a238c70SJohn Marino mechanism because fp_ptr may point into the same
7584a238c70SJohn Marino string as ip_ptr */
7594a238c70SJohn Marino };
7604a238c70SJohn Marino
7614a238c70SJohn Marino /* For a real non zero number x, what is the base exponent f when rounding x
7624a238c70SJohn Marino with rounding mode r to r(x) = m*b^f, where m is a digit and 1 <= m < b ?
7634a238c70SJohn Marino Return non zero value if x is rounded up to b^f, return zero otherwise */
7644a238c70SJohn Marino static int
next_base_power_p(mpfr_srcptr x,int base,mpfr_rnd_t rnd)7654a238c70SJohn Marino next_base_power_p (mpfr_srcptr x, int base, mpfr_rnd_t rnd)
7664a238c70SJohn Marino {
7674a238c70SJohn Marino mpfr_prec_t nbits;
7684a238c70SJohn Marino mp_limb_t pm;
7694a238c70SJohn Marino mp_limb_t xm;
7704a238c70SJohn Marino
7714a238c70SJohn Marino MPFR_ASSERTD (MPFR_IS_PURE_FP (x));
7724a238c70SJohn Marino MPFR_ASSERTD (base == 2 || base == 16);
7734a238c70SJohn Marino
7744a238c70SJohn Marino /* Warning: the decimal point is AFTER THE FIRST DIGIT in this output
7754a238c70SJohn Marino representation. */
7764a238c70SJohn Marino nbits = base == 2 ? 1 : 4;
7774a238c70SJohn Marino
7784a238c70SJohn Marino if (rnd == MPFR_RNDZ
7794a238c70SJohn Marino || (rnd == MPFR_RNDD && MPFR_IS_POS (x))
7804a238c70SJohn Marino || (rnd == MPFR_RNDU && MPFR_IS_NEG (x))
7814a238c70SJohn Marino || MPFR_PREC (x) <= nbits)
7824a238c70SJohn Marino /* no rounding when printing x with 1 digit */
7834a238c70SJohn Marino return 0;
7844a238c70SJohn Marino
7854a238c70SJohn Marino xm = MPFR_MANT (x) [MPFR_LIMB_SIZE (x) - 1];
7864a238c70SJohn Marino pm = MPFR_LIMB_MASK (GMP_NUMB_BITS - nbits);
7874a238c70SJohn Marino if ((xm & ~pm) ^ ~pm)
7884a238c70SJohn Marino /* do no round up if some of the nbits first bits are 0s. */
7894a238c70SJohn Marino return 0;
7904a238c70SJohn Marino
7914a238c70SJohn Marino if (rnd == MPFR_RNDN)
7924a238c70SJohn Marino /* mask for rounding bit */
7934a238c70SJohn Marino pm = (MPFR_LIMB_ONE << (GMP_NUMB_BITS - nbits - 1));
7944a238c70SJohn Marino
7954a238c70SJohn Marino /* round up if some remaining bits are 1 */
7964a238c70SJohn Marino /* warning: the return value must be an int */
7974a238c70SJohn Marino return xm & pm ? 1 : 0;
7984a238c70SJohn Marino }
7994a238c70SJohn Marino
8004a238c70SJohn Marino /* Record information from mpfr_get_str() so as to avoid multiple
8014a238c70SJohn Marino calls to this expensive function. */
8024a238c70SJohn Marino struct decimal_info
8034a238c70SJohn Marino {
8044a238c70SJohn Marino mpfr_exp_t exp;
8054a238c70SJohn Marino char *str;
8064a238c70SJohn Marino };
8074a238c70SJohn Marino
8084a238c70SJohn Marino /* For a real non zero number x, what is the exponent f so that
8094a238c70SJohn Marino 10^f <= x < 10^(f+1). */
8104a238c70SJohn Marino static mpfr_exp_t
floor_log10(mpfr_srcptr x)8114a238c70SJohn Marino floor_log10 (mpfr_srcptr x)
8124a238c70SJohn Marino {
8134a238c70SJohn Marino mpfr_t y;
8144a238c70SJohn Marino mpfr_exp_t exp;
8154a238c70SJohn Marino
8164a238c70SJohn Marino /* make sure first that y can represent a mpfr_exp_t exactly
8174a238c70SJohn Marino and can compare with x */
8184a238c70SJohn Marino mpfr_prec_t prec = sizeof (mpfr_exp_t) * CHAR_BIT;
8194a238c70SJohn Marino mpfr_init2 (y, MAX (prec, MPFR_PREC (x)));
8204a238c70SJohn Marino
8214a238c70SJohn Marino exp = mpfr_ceil_mul (MPFR_GET_EXP (x), 10, 1) - 1;
8224a238c70SJohn Marino mpfr_set_exp_t (y, exp, MPFR_RNDU);
8234a238c70SJohn Marino /* The following call to mpfr_ui_pow should be fast: y is an integer
8244a238c70SJohn Marino (not too large), so that mpfr_pow_z will be used internally. */
8254a238c70SJohn Marino mpfr_ui_pow (y, 10, y, MPFR_RNDU);
8264a238c70SJohn Marino if (mpfr_cmpabs (x, y) < 0)
8274a238c70SJohn Marino exp--;
8284a238c70SJohn Marino
8294a238c70SJohn Marino mpfr_clear (y);
8304a238c70SJohn Marino return exp;
8314a238c70SJohn Marino }
8324a238c70SJohn Marino
8334a238c70SJohn Marino /* Determine the different parts of the string representation of the regular
8344a238c70SJohn Marino number P when SPEC.SPEC is 'a', 'A', or 'b'.
8354a238c70SJohn Marino
8364a238c70SJohn Marino return -1 if some field > INT_MAX */
8374a238c70SJohn Marino static int
regular_ab(struct number_parts * np,mpfr_srcptr p,const struct printf_spec spec)8384a238c70SJohn Marino regular_ab (struct number_parts *np, mpfr_srcptr p,
8394a238c70SJohn Marino const struct printf_spec spec)
8404a238c70SJohn Marino {
8414a238c70SJohn Marino int uppercase;
8424a238c70SJohn Marino int base;
8434a238c70SJohn Marino char *str;
8444a238c70SJohn Marino mpfr_exp_t exp;
8454a238c70SJohn Marino
8464a238c70SJohn Marino uppercase = spec.spec == 'A';
8474a238c70SJohn Marino
8484a238c70SJohn Marino /* sign */
8494a238c70SJohn Marino if (MPFR_IS_NEG (p))
8504a238c70SJohn Marino np->sign = '-';
8514a238c70SJohn Marino else if (spec.showsign || spec.space)
8524a238c70SJohn Marino np->sign = spec.showsign ? '+' : ' ';
8534a238c70SJohn Marino
8544a238c70SJohn Marino if (spec.spec == 'a' || spec.spec == 'A')
8554a238c70SJohn Marino /* prefix part */
8564a238c70SJohn Marino {
8574a238c70SJohn Marino np->prefix_size = 2;
8584a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
8594a238c70SJohn Marino str[0] = '0';
8604a238c70SJohn Marino str[1] = uppercase ? 'X' : 'x';
8614a238c70SJohn Marino str[2] = '\0';
8624a238c70SJohn Marino np->prefix_ptr = register_string (np->sl, str);
8634a238c70SJohn Marino }
8644a238c70SJohn Marino
8654a238c70SJohn Marino /* integral part */
8664a238c70SJohn Marino np->ip_size = 1;
8674a238c70SJohn Marino base = (spec.spec == 'b') ? 2 : 16;
8684a238c70SJohn Marino
8694a238c70SJohn Marino if (spec.prec != 0)
8704a238c70SJohn Marino {
8714a238c70SJohn Marino size_t nsd;
8724a238c70SJohn Marino
8734a238c70SJohn Marino /* Number of significant digits:
8744a238c70SJohn Marino - if no given precision, let mpfr_get_str determine it;
8754a238c70SJohn Marino - if a non-zero precision is specified, then one digit before decimal
8764a238c70SJohn Marino point plus SPEC.PREC after it. */
8774a238c70SJohn Marino nsd = spec.prec < 0 ? 0 : spec.prec + np->ip_size;
8784a238c70SJohn Marino str = mpfr_get_str (0, &exp, base, nsd, p, spec.rnd_mode);
8794a238c70SJohn Marino register_string (np->sl, str);
8804a238c70SJohn Marino np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */
8814a238c70SJohn Marino
8824a238c70SJohn Marino if (base == 16)
8834a238c70SJohn Marino /* EXP is the exponent for radix sixteen with decimal point BEFORE the
8844a238c70SJohn Marino first digit, we want the exponent for radix two and the decimal
8854a238c70SJohn Marino point AFTER the first digit. */
8864a238c70SJohn Marino {
8874a238c70SJohn Marino MPFR_ASSERTN (exp > MPFR_EMIN_MIN /4); /* possible overflow */
8884a238c70SJohn Marino exp = (exp - 1) * 4;
8894a238c70SJohn Marino }
8904a238c70SJohn Marino else
8914a238c70SJohn Marino /* EXP is the exponent for decimal point BEFORE the first digit, we
8924a238c70SJohn Marino want the exponent for decimal point AFTER the first digit. */
8934a238c70SJohn Marino {
8944a238c70SJohn Marino MPFR_ASSERTN (exp > MPFR_EMIN_MIN); /* possible overflow */
8954a238c70SJohn Marino --exp;
8964a238c70SJohn Marino }
8974a238c70SJohn Marino }
8984a238c70SJohn Marino else if (next_base_power_p (p, base, spec.rnd_mode))
8994a238c70SJohn Marino {
9004a238c70SJohn Marino str = (char *)(*__gmp_allocate_func) (2);
9014a238c70SJohn Marino str[0] = '1';
9024a238c70SJohn Marino str[1] = '\0';
9034a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
9044a238c70SJohn Marino
9054a238c70SJohn Marino exp = MPFR_GET_EXP (p);
9064a238c70SJohn Marino }
9074a238c70SJohn Marino else if (base == 2)
9084a238c70SJohn Marino {
9094a238c70SJohn Marino str = (char *)(*__gmp_allocate_func) (2);
9104a238c70SJohn Marino str[0] = '1';
9114a238c70SJohn Marino str[1] = '\0';
9124a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
9134a238c70SJohn Marino
9144a238c70SJohn Marino exp = MPFR_GET_EXP (p) - 1;
9154a238c70SJohn Marino }
9164a238c70SJohn Marino else
9174a238c70SJohn Marino {
9184a238c70SJohn Marino int digit;
9194a238c70SJohn Marino mp_limb_t msl = MPFR_MANT (p)[MPFR_LIMB_SIZE (p) - 1];
9204a238c70SJohn Marino int rnd_bit = GMP_NUMB_BITS - 5;
9214a238c70SJohn Marino
9224a238c70SJohn Marino /* pick up the 4 first bits */
9234a238c70SJohn Marino digit = msl >> (rnd_bit+1);
9244a238c70SJohn Marino if (spec.rnd_mode == MPFR_RNDA
9254a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDU && MPFR_IS_POS (p))
9264a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDD && MPFR_IS_NEG (p))
9274a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDN
9284a238c70SJohn Marino && (msl & (MPFR_LIMB_ONE << rnd_bit))))
9294a238c70SJohn Marino digit++;
9304a238c70SJohn Marino MPFR_ASSERTD ((0 <= digit) && (digit <= 15));
9314a238c70SJohn Marino
9324a238c70SJohn Marino str = (char *)(*__gmp_allocate_func) (1 + np->ip_size);
9334a238c70SJohn Marino str[0] = num_to_text [digit];
9344a238c70SJohn Marino str[1] = '\0';
9354a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
9364a238c70SJohn Marino
9374a238c70SJohn Marino exp = MPFR_GET_EXP (p) - 4;
9384a238c70SJohn Marino }
9394a238c70SJohn Marino
9404a238c70SJohn Marino if (uppercase)
9414a238c70SJohn Marino /* All digits in upper case */
9424a238c70SJohn Marino {
9434a238c70SJohn Marino char *s1 = str;
9444a238c70SJohn Marino while (*s1)
9454a238c70SJohn Marino {
9464a238c70SJohn Marino switch (*s1)
9474a238c70SJohn Marino {
9484a238c70SJohn Marino case 'a':
9494a238c70SJohn Marino *s1 = 'A';
9504a238c70SJohn Marino break;
9514a238c70SJohn Marino case 'b':
9524a238c70SJohn Marino *s1 = 'B';
9534a238c70SJohn Marino break;
9544a238c70SJohn Marino case 'c':
9554a238c70SJohn Marino *s1 = 'C';
9564a238c70SJohn Marino break;
9574a238c70SJohn Marino case 'd':
9584a238c70SJohn Marino *s1 = 'D';
9594a238c70SJohn Marino break;
9604a238c70SJohn Marino case 'e':
9614a238c70SJohn Marino *s1 = 'E';
9624a238c70SJohn Marino break;
9634a238c70SJohn Marino case 'f':
9644a238c70SJohn Marino *s1 = 'F';
9654a238c70SJohn Marino break;
9664a238c70SJohn Marino }
9674a238c70SJohn Marino s1++;
9684a238c70SJohn Marino }
9694a238c70SJohn Marino }
9704a238c70SJohn Marino
9714a238c70SJohn Marino if (spec.spec == 'b' || spec.prec != 0)
9724a238c70SJohn Marino /* compute the number of digits in fractional part */
9734a238c70SJohn Marino {
9744a238c70SJohn Marino char *ptr;
9754a238c70SJohn Marino size_t str_len;
9764a238c70SJohn Marino
9774a238c70SJohn Marino /* the sign has been skipped, skip also the first digit */
9784a238c70SJohn Marino ++str;
9794a238c70SJohn Marino str_len = strlen (str);
9804a238c70SJohn Marino ptr = str + str_len - 1; /* points to the end of str */
9814a238c70SJohn Marino
9824a238c70SJohn Marino if (spec.prec < 0)
9834a238c70SJohn Marino /* remove trailing zeros, if any */
9844a238c70SJohn Marino {
9854a238c70SJohn Marino while ((*ptr == '0') && (str_len != 0))
9864a238c70SJohn Marino {
9874a238c70SJohn Marino --ptr;
9884a238c70SJohn Marino --str_len;
9894a238c70SJohn Marino }
9904a238c70SJohn Marino }
9914a238c70SJohn Marino
9924a238c70SJohn Marino if (str_len > INT_MAX)
9934a238c70SJohn Marino /* too many digits in fractional part */
9944a238c70SJohn Marino return -1;
9954a238c70SJohn Marino
9964a238c70SJohn Marino if (str_len != 0)
9974a238c70SJohn Marino /* there are some non-zero digits in fractional part */
9984a238c70SJohn Marino {
9994a238c70SJohn Marino np->fp_ptr = str;
10004a238c70SJohn Marino np->fp_size = str_len;
10014a238c70SJohn Marino if ((int) str_len < spec.prec)
10024a238c70SJohn Marino np->fp_trailing_zeros = spec.prec - str_len;
10034a238c70SJohn Marino }
10044a238c70SJohn Marino }
10054a238c70SJohn Marino
10064a238c70SJohn Marino /* decimal point */
10074a238c70SJohn Marino if ((np->fp_size != 0) || spec.alt)
10084a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
10094a238c70SJohn Marino
10104a238c70SJohn Marino /* the exponent part contains the character 'p', or 'P' plus the sign
10114a238c70SJohn Marino character plus at least one digit and only as many more digits as
10124a238c70SJohn Marino necessary to represent the exponent.
10134a238c70SJohn Marino We assume that |EXP| < 10^INT_MAX. */
10144a238c70SJohn Marino np->exp_size = 3;
10154a238c70SJohn Marino {
10164a238c70SJohn Marino mpfr_uexp_t x;
10174a238c70SJohn Marino
10184a238c70SJohn Marino x = SAFE_ABS (mpfr_uexp_t, exp);
10194a238c70SJohn Marino while (x > 9)
10204a238c70SJohn Marino {
10214a238c70SJohn Marino np->exp_size++;
10224a238c70SJohn Marino x /= 10;
10234a238c70SJohn Marino }
10244a238c70SJohn Marino }
10254a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
10264a238c70SJohn Marino np->exp_ptr = register_string (np->sl, str);
10274a238c70SJohn Marino {
10284a238c70SJohn Marino char exp_fmt[8]; /* contains at most 7 characters like in "p%+.1i",
10294a238c70SJohn Marino or "P%+.2li" */
10304a238c70SJohn Marino
10314a238c70SJohn Marino exp_fmt[0] = uppercase ? 'P' : 'p';
10324a238c70SJohn Marino exp_fmt[1] = '\0';
10334a238c70SJohn Marino strcat (exp_fmt, "%+.1" MPFR_EXP_FSPEC "d");
10344a238c70SJohn Marino
10354a238c70SJohn Marino if (sprintf (str, exp_fmt, (mpfr_eexp_t) exp) < 0)
10364a238c70SJohn Marino return -1;
10374a238c70SJohn Marino }
10384a238c70SJohn Marino
10394a238c70SJohn Marino return 0;
10404a238c70SJohn Marino }
10414a238c70SJohn Marino
10424a238c70SJohn Marino /* Determine the different parts of the string representation of the regular
10434a238c70SJohn Marino number P when SPEC.SPEC is 'e', 'E', 'g', or 'G'.
10444a238c70SJohn Marino DEC_INFO contains the previously computed exponent and string or is NULL.
10454a238c70SJohn Marino
10464a238c70SJohn Marino return -1 if some field > INT_MAX */
10474a238c70SJohn Marino static int
regular_eg(struct number_parts * np,mpfr_srcptr p,const struct printf_spec spec,struct decimal_info * dec_info)10484a238c70SJohn Marino regular_eg (struct number_parts *np, mpfr_srcptr p,
10494a238c70SJohn Marino const struct printf_spec spec, struct decimal_info *dec_info)
10504a238c70SJohn Marino {
10514a238c70SJohn Marino char *str;
10524a238c70SJohn Marino mpfr_exp_t exp;
10534a238c70SJohn Marino
10544a238c70SJohn Marino const int uppercase = spec.spec == 'E' || spec.spec == 'G';
10554a238c70SJohn Marino const int spec_g = spec.spec == 'g' || spec.spec == 'G';
10564a238c70SJohn Marino const int keep_trailing_zeros = (spec_g && spec.alt)
10574a238c70SJohn Marino || (!spec_g && (spec.prec > 0));
10584a238c70SJohn Marino
10594a238c70SJohn Marino /* sign */
10604a238c70SJohn Marino if (MPFR_IS_NEG (p))
10614a238c70SJohn Marino np->sign = '-';
10624a238c70SJohn Marino else if (spec.showsign || spec.space)
10634a238c70SJohn Marino np->sign = spec.showsign ? '+' : ' ';
10644a238c70SJohn Marino
10654a238c70SJohn Marino /* integral part */
10664a238c70SJohn Marino np->ip_size = 1;
10674a238c70SJohn Marino if (dec_info == NULL)
10684a238c70SJohn Marino {
10694a238c70SJohn Marino size_t nsd;
10704a238c70SJohn Marino
10714a238c70SJohn Marino /* Number of significant digits:
10724a238c70SJohn Marino - if no given precision, then let mpfr_get_str determine it,
10734a238c70SJohn Marino - if a precision is specified, then one digit before decimal point
10744a238c70SJohn Marino plus SPEC.PREC after it.
10754a238c70SJohn Marino We use the fact here that mpfr_get_str allows us to ask for only one
10764a238c70SJohn Marino significant digit when the base is not a power of 2. */
10774a238c70SJohn Marino nsd = (spec.prec < 0) ? 0 : spec.prec + np->ip_size;
10784a238c70SJohn Marino str = mpfr_get_str (0, &exp, 10, nsd, p, spec.rnd_mode);
10794a238c70SJohn Marino register_string (np->sl, str);
10804a238c70SJohn Marino }
10814a238c70SJohn Marino else
10824a238c70SJohn Marino {
10834a238c70SJohn Marino exp = dec_info->exp;
10844a238c70SJohn Marino str = dec_info->str;
10854a238c70SJohn Marino }
10864a238c70SJohn Marino np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign if any */
10874a238c70SJohn Marino
10884a238c70SJohn Marino if (spec.prec != 0)
10894a238c70SJohn Marino /* compute the number of digits in fractional part */
10904a238c70SJohn Marino {
10914a238c70SJohn Marino char *ptr;
10924a238c70SJohn Marino size_t str_len;
10934a238c70SJohn Marino
10944a238c70SJohn Marino /* the sign has been skipped, skip also the first digit */
10954a238c70SJohn Marino ++str;
10964a238c70SJohn Marino str_len = strlen (str);
10974a238c70SJohn Marino ptr = str + str_len - 1; /* points to the end of str */
10984a238c70SJohn Marino
10994a238c70SJohn Marino if (!keep_trailing_zeros)
11004a238c70SJohn Marino /* remove trailing zeros, if any */
11014a238c70SJohn Marino {
11024a238c70SJohn Marino while ((*ptr == '0') && (str_len != 0))
11034a238c70SJohn Marino {
11044a238c70SJohn Marino --ptr;
11054a238c70SJohn Marino --str_len;
11064a238c70SJohn Marino }
11074a238c70SJohn Marino }
11084a238c70SJohn Marino
11094a238c70SJohn Marino if (str_len > INT_MAX)
11104a238c70SJohn Marino /* too many digits in fractional part */
11114a238c70SJohn Marino return -1;
11124a238c70SJohn Marino
11134a238c70SJohn Marino if (str_len != 0)
11144a238c70SJohn Marino /* there are some non-zero digits in fractional part */
11154a238c70SJohn Marino {
11164a238c70SJohn Marino np->fp_ptr = str;
11174a238c70SJohn Marino np->fp_size = str_len;
11184a238c70SJohn Marino if ((!spec_g || spec.alt) && (spec.prec > 0)
11194a238c70SJohn Marino && ((int)str_len < spec.prec))
11204a238c70SJohn Marino /* add missing trailing zeros */
11214a238c70SJohn Marino np->fp_trailing_zeros = spec.prec - str_len;
11224a238c70SJohn Marino }
11234a238c70SJohn Marino }
11244a238c70SJohn Marino
11254a238c70SJohn Marino /* decimal point */
11264a238c70SJohn Marino if (np->fp_size != 0 || spec.alt)
11274a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
11284a238c70SJohn Marino
11294a238c70SJohn Marino /* EXP is the exponent for decimal point BEFORE the first digit, we want
11304a238c70SJohn Marino the exponent for decimal point AFTER the first digit.
11314a238c70SJohn Marino Here, no possible overflow because exp < MPFR_EXP (p) / 3 */
11324a238c70SJohn Marino exp--;
11334a238c70SJohn Marino
11344a238c70SJohn Marino /* the exponent part contains the character 'e', or 'E' plus the sign
11354a238c70SJohn Marino character plus at least two digits and only as many more digits as
11364a238c70SJohn Marino necessary to represent the exponent.
11374a238c70SJohn Marino We assume that |EXP| < 10^INT_MAX. */
11384a238c70SJohn Marino np->exp_size = 3;
11394a238c70SJohn Marino {
11404a238c70SJohn Marino mpfr_uexp_t x;
11414a238c70SJohn Marino
11424a238c70SJohn Marino x = SAFE_ABS (mpfr_uexp_t, exp);
11434a238c70SJohn Marino while (x > 9)
11444a238c70SJohn Marino {
11454a238c70SJohn Marino np->exp_size++;
11464a238c70SJohn Marino x /= 10;
11474a238c70SJohn Marino }
11484a238c70SJohn Marino }
11494a238c70SJohn Marino if (np->exp_size < 4)
11504a238c70SJohn Marino np->exp_size = 4;
11514a238c70SJohn Marino
11524a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
11534a238c70SJohn Marino np->exp_ptr = register_string (np->sl, str);
11544a238c70SJohn Marino
11554a238c70SJohn Marino {
11564a238c70SJohn Marino char exp_fmt[8]; /* e.g. "e%+.2i", or "E%+.2li" */
11574a238c70SJohn Marino
11584a238c70SJohn Marino exp_fmt[0] = uppercase ? 'E' : 'e';
11594a238c70SJohn Marino exp_fmt[1] = '\0';
11604a238c70SJohn Marino strcat (exp_fmt, "%+.2" MPFR_EXP_FSPEC "d");
11614a238c70SJohn Marino
11624a238c70SJohn Marino if (sprintf (str, exp_fmt, (mpfr_eexp_t) exp) < 0)
11634a238c70SJohn Marino return -1;
11644a238c70SJohn Marino }
11654a238c70SJohn Marino
11664a238c70SJohn Marino return 0;
11674a238c70SJohn Marino }
11684a238c70SJohn Marino
11694a238c70SJohn Marino /* Determine the different parts of the string representation of the regular
11704a238c70SJohn Marino number P when SPEC.SPEC is 'f', 'F', 'g', or 'G'.
11714a238c70SJohn Marino DEC_INFO contains the previously computed exponent and string or is NULL.
11724a238c70SJohn Marino
11734a238c70SJohn Marino return -1 if some field of number_parts is greater than INT_MAX */
11744a238c70SJohn Marino static int
regular_fg(struct number_parts * np,mpfr_srcptr p,const struct printf_spec spec,struct decimal_info * dec_info)11754a238c70SJohn Marino regular_fg (struct number_parts *np, mpfr_srcptr p,
11764a238c70SJohn Marino const struct printf_spec spec, struct decimal_info *dec_info)
11774a238c70SJohn Marino {
11784a238c70SJohn Marino mpfr_exp_t exp;
11794a238c70SJohn Marino char * str;
11804a238c70SJohn Marino const int spec_g = (spec.spec == 'g' || spec.spec == 'G');
1181ab6d115fSJohn Marino const int keep_trailing_zeros = !spec_g || spec.alt;
11824a238c70SJohn Marino
11834a238c70SJohn Marino /* WARNING: an empty precision field is forbidden (it means precision = 6
11844a238c70SJohn Marino and it should have been changed to 6 before the function call) */
11854a238c70SJohn Marino MPFR_ASSERTD (spec.prec >= 0);
11864a238c70SJohn Marino
11874a238c70SJohn Marino /* sign */
11884a238c70SJohn Marino if (MPFR_IS_NEG (p))
11894a238c70SJohn Marino np->sign = '-';
11904a238c70SJohn Marino else if (spec.showsign || spec.space)
11914a238c70SJohn Marino np->sign = spec.showsign ? '+' : ' ';
11924a238c70SJohn Marino
11934a238c70SJohn Marino if (MPFR_GET_EXP (p) <= 0)
11944a238c70SJohn Marino /* 0 < |p| < 1 */
11954a238c70SJohn Marino {
11964a238c70SJohn Marino /* Most of the time, integral part is 0 */
11974a238c70SJohn Marino np->ip_size = 1;
11984a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
11994a238c70SJohn Marino str[0] = '0';
12004a238c70SJohn Marino str[1] = '\0';
12014a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
12024a238c70SJohn Marino
12034a238c70SJohn Marino if (spec.prec == 0)
12044a238c70SJohn Marino /* only two possibilities: either 1 or 0. */
12054a238c70SJohn Marino {
12064a238c70SJohn Marino mpfr_t y;
12074a238c70SJohn Marino /* y = abs(p) */
12084a238c70SJohn Marino MPFR_ALIAS (y, p, 1, MPFR_EXP (p));
12094a238c70SJohn Marino
12104a238c70SJohn Marino if (spec.rnd_mode == MPFR_RNDA
12114a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDD && MPFR_IS_NEG (p))
12124a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDU && MPFR_IS_POS (p))
12134a238c70SJohn Marino || (spec.rnd_mode == MPFR_RNDN && mpfr_cmp_d (y, 0.5) > 0))
12144a238c70SJohn Marino /* rounded up to 1: one digit '1' in integral part.
12154a238c70SJohn Marino note that 0.5 is rounded to 0 with RNDN (round ties to even) */
12164a238c70SJohn Marino np->ip_ptr[0] = '1';
12174a238c70SJohn Marino }
12184a238c70SJohn Marino else
12194a238c70SJohn Marino {
12204a238c70SJohn Marino /* exp = position of the most significant decimal digit. */
12214a238c70SJohn Marino exp = floor_log10 (p);
12224a238c70SJohn Marino MPFR_ASSERTD (exp < 0);
12234a238c70SJohn Marino
12244a238c70SJohn Marino if (exp < -spec.prec)
12254a238c70SJohn Marino /* only the last digit may be non zero */
12264a238c70SJohn Marino {
12274a238c70SJohn Marino int round_away;
12284a238c70SJohn Marino switch (spec.rnd_mode)
12294a238c70SJohn Marino {
12304a238c70SJohn Marino case MPFR_RNDA:
12314a238c70SJohn Marino round_away = 1;
12324a238c70SJohn Marino break;
12334a238c70SJohn Marino case MPFR_RNDD:
12344a238c70SJohn Marino round_away = MPFR_IS_NEG (p);
12354a238c70SJohn Marino break;
12364a238c70SJohn Marino case MPFR_RNDU:
12374a238c70SJohn Marino round_away = MPFR_IS_POS (p);
12384a238c70SJohn Marino break;
12394a238c70SJohn Marino case MPFR_RNDN:
12404a238c70SJohn Marino {
12414a238c70SJohn Marino /* compare |p| to y = 0.5*10^(-spec.prec) */
12424a238c70SJohn Marino mpfr_t y;
12434a238c70SJohn Marino mpfr_exp_t e = MAX (MPFR_PREC (p), 56);
12444a238c70SJohn Marino mpfr_init2 (y, e + 8);
12454a238c70SJohn Marino do
12464a238c70SJohn Marino {
12474a238c70SJohn Marino /* find a lower approximation of
12484a238c70SJohn Marino 0.5*10^(-spec.prec) different from |p| */
12494a238c70SJohn Marino e += 8;
12504a238c70SJohn Marino mpfr_set_prec (y, e);
12514a238c70SJohn Marino mpfr_set_si (y, -spec.prec, MPFR_RNDN);
12524a238c70SJohn Marino mpfr_exp10 (y, y, MPFR_RNDD);
12534a238c70SJohn Marino mpfr_div_2ui (y, y, 1, MPFR_RNDN);
12544a238c70SJohn Marino } while (mpfr_cmpabs (y, p) == 0);
12554a238c70SJohn Marino
12564a238c70SJohn Marino round_away = mpfr_cmpabs (y, p) < 0;
12574a238c70SJohn Marino mpfr_clear (y);
12584a238c70SJohn Marino }
12594a238c70SJohn Marino break;
12604a238c70SJohn Marino default:
12614a238c70SJohn Marino round_away = 0;
12624a238c70SJohn Marino }
12634a238c70SJohn Marino
12644a238c70SJohn Marino if (round_away)
12654a238c70SJohn Marino /* round away from zero: the last output digit is '1' */
12664a238c70SJohn Marino {
12674a238c70SJohn Marino np->fp_leading_zeros = spec.prec - 1;
12684a238c70SJohn Marino
12694a238c70SJohn Marino np->fp_size = 1;
12704a238c70SJohn Marino str =
12714a238c70SJohn Marino (char *) (*__gmp_allocate_func) (1 + np->fp_size);
12724a238c70SJohn Marino str[0] = '1';
12734a238c70SJohn Marino str[1] = '\0';
12744a238c70SJohn Marino np->fp_ptr = register_string (np->sl, str);
12754a238c70SJohn Marino }
12764a238c70SJohn Marino else
12774a238c70SJohn Marino /* only zeros in fractional part */
12784a238c70SJohn Marino {
12794a238c70SJohn Marino MPFR_ASSERTD (!spec_g);
12804a238c70SJohn Marino np->fp_leading_zeros = spec.prec;
12814a238c70SJohn Marino }
12824a238c70SJohn Marino }
12834a238c70SJohn Marino else
12844a238c70SJohn Marino /* the most significant digits are the last
12854a238c70SJohn Marino spec.prec + exp + 1 digits in fractional part */
12864a238c70SJohn Marino {
12874a238c70SJohn Marino char *ptr;
12884a238c70SJohn Marino size_t str_len;
12894a238c70SJohn Marino if (dec_info == NULL)
12904a238c70SJohn Marino {
12914a238c70SJohn Marino size_t nsd = spec.prec + exp + 1;
12924a238c70SJohn Marino /* WARNING: nsd may equal 1, but here we use the
12934a238c70SJohn Marino fact that mpfr_get_str can return one digit with
12944a238c70SJohn Marino base ten (undocumented feature, see comments in
12954a238c70SJohn Marino get_str.c) */
12964a238c70SJohn Marino
12974a238c70SJohn Marino str = mpfr_get_str (NULL, &exp, 10, nsd, p, spec.rnd_mode);
12984a238c70SJohn Marino register_string (np->sl, str);
12994a238c70SJohn Marino }
13004a238c70SJohn Marino else
13014a238c70SJohn Marino {
13024a238c70SJohn Marino exp = dec_info->exp;
13034a238c70SJohn Marino str = dec_info->str;
13044a238c70SJohn Marino }
13054a238c70SJohn Marino if (MPFR_IS_NEG (p))
1306ab6d115fSJohn Marino /* skip sign */
13074a238c70SJohn Marino ++str;
13084a238c70SJohn Marino if (exp == 1)
13094a238c70SJohn Marino /* round up to 1 */
13104a238c70SJohn Marino {
13114a238c70SJohn Marino MPFR_ASSERTD (str[0] == '1');
13124a238c70SJohn Marino np->ip_ptr[0] = '1';
13134a238c70SJohn Marino if (!spec_g || spec.alt)
13144a238c70SJohn Marino np->fp_leading_zeros = spec.prec;
13154a238c70SJohn Marino }
13164a238c70SJohn Marino else
13174a238c70SJohn Marino {
13184a238c70SJohn Marino np->fp_ptr = str;
13194a238c70SJohn Marino np->fp_leading_zeros = -exp;
13204a238c70SJohn Marino MPFR_ASSERTD (exp <= 0);
13214a238c70SJohn Marino
13224a238c70SJohn Marino str_len = strlen (str); /* the sign has been skipped */
13234a238c70SJohn Marino ptr = str + str_len - 1; /* points to the end of str */
13244a238c70SJohn Marino
13254a238c70SJohn Marino if (!keep_trailing_zeros)
13264a238c70SJohn Marino /* remove trailing zeros, if any */
13274a238c70SJohn Marino {
13284a238c70SJohn Marino while ((*ptr == '0') && str_len)
13294a238c70SJohn Marino {
13304a238c70SJohn Marino --ptr;
13314a238c70SJohn Marino --str_len;
13324a238c70SJohn Marino }
13334a238c70SJohn Marino }
13344a238c70SJohn Marino
13354a238c70SJohn Marino if (str_len > INT_MAX)
13364a238c70SJohn Marino /* too many digits in fractional part */
13374a238c70SJohn Marino return -1;
13384a238c70SJohn Marino
13394a238c70SJohn Marino MPFR_ASSERTD (str_len > 0);
13404a238c70SJohn Marino np->fp_size = str_len;
13414a238c70SJohn Marino
13424a238c70SJohn Marino if ((!spec_g || spec.alt)
13434a238c70SJohn Marino && spec.prec > 0
13444a238c70SJohn Marino && (np->fp_leading_zeros + np->fp_size < spec.prec))
13454a238c70SJohn Marino /* add missing trailing zeros */
13464a238c70SJohn Marino np->fp_trailing_zeros = spec.prec - np->fp_leading_zeros
13474a238c70SJohn Marino - np->fp_size;
13484a238c70SJohn Marino }
13494a238c70SJohn Marino }
13504a238c70SJohn Marino }
13514a238c70SJohn Marino
13524a238c70SJohn Marino if (spec.alt || np->fp_leading_zeros != 0 || np->fp_size != 0
13534a238c70SJohn Marino || np->fp_trailing_zeros != 0)
13544a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
13554a238c70SJohn Marino }
13564a238c70SJohn Marino else
13574a238c70SJohn Marino /* 1 <= |p| */
13584a238c70SJohn Marino {
1359ab6d115fSJohn Marino size_t str_len;
13604a238c70SJohn Marino
13614a238c70SJohn Marino /* Determine the position of the most significant decimal digit. */
13624a238c70SJohn Marino exp = floor_log10 (p);
13634a238c70SJohn Marino MPFR_ASSERTD (exp >= 0);
13644a238c70SJohn Marino if (exp > INT_MAX)
13654a238c70SJohn Marino /* P is too large to print all its integral part digits */
13664a238c70SJohn Marino return -1;
13674a238c70SJohn Marino
13684a238c70SJohn Marino if (dec_info == NULL)
1369ab6d115fSJohn Marino { /* this case occurs with mpfr_printf ("%.0RUf", x) with x=9.5 */
1370ab6d115fSJohn Marino str =
1371ab6d115fSJohn Marino mpfr_get_str (NULL, &exp, 10, spec.prec+exp+1, p, spec.rnd_mode);
13724a238c70SJohn Marino register_string (np->sl, str);
13734a238c70SJohn Marino }
13744a238c70SJohn Marino else
13754a238c70SJohn Marino {
13764a238c70SJohn Marino exp = dec_info->exp;
13774a238c70SJohn Marino str = dec_info->str;
13784a238c70SJohn Marino }
13794a238c70SJohn Marino np->ip_ptr = MPFR_IS_NEG (p) ? ++str : str; /* skip sign */
1380ab6d115fSJohn Marino str_len = strlen (str);
1381ab6d115fSJohn Marino
1382ab6d115fSJohn Marino /* integral part */
1383ab6d115fSJohn Marino if (exp > str_len)
1384ab6d115fSJohn Marino /* mpfr_get_str gives no trailing zero when p is rounded up to the next
1385ab6d115fSJohn Marino power of 10 (p integer, so no fractional part) */
1386ab6d115fSJohn Marino {
1387ab6d115fSJohn Marino np->ip_trailing_zeros = exp - str_len;
1388ab6d115fSJohn Marino np->ip_size = str_len;
1389ab6d115fSJohn Marino }
1390ab6d115fSJohn Marino else
1391ab6d115fSJohn Marino np->ip_size = exp;
13924a238c70SJohn Marino
13934a238c70SJohn Marino if (spec.group)
13944a238c70SJohn Marino /* thousands separator in integral part */
13954a238c70SJohn Marino np->thousands_sep = MPFR_THOUSANDS_SEPARATOR;
13964a238c70SJohn Marino
1397ab6d115fSJohn Marino /* fractional part */
1398ab6d115fSJohn Marino str += np->ip_size;
1399ab6d115fSJohn Marino str_len -= np->ip_size;
14004a238c70SJohn Marino if (!keep_trailing_zeros)
14014a238c70SJohn Marino /* remove trailing zeros, if any */
14024a238c70SJohn Marino {
1403ab6d115fSJohn Marino char *ptr = str + str_len - 1; /* pointer to the last digit of
1404ab6d115fSJohn Marino str */
14054a238c70SJohn Marino while ((*ptr == '0') && (str_len != 0))
14064a238c70SJohn Marino {
14074a238c70SJohn Marino --ptr;
14084a238c70SJohn Marino --str_len;
14094a238c70SJohn Marino }
14104a238c70SJohn Marino }
14114a238c70SJohn Marino
1412ab6d115fSJohn Marino if (str_len > 0)
1413ab6d115fSJohn Marino /* some nonzero digits in fractional part */
1414ab6d115fSJohn Marino {
14154a238c70SJohn Marino if (str_len > INT_MAX)
14164a238c70SJohn Marino /* too many digits in fractional part */
14174a238c70SJohn Marino return -1;
14184a238c70SJohn Marino
14194a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
1420ab6d115fSJohn Marino np->fp_ptr = str;
14214a238c70SJohn Marino np->fp_size = str_len;
14224a238c70SJohn Marino }
14234a238c70SJohn Marino
1424ab6d115fSJohn Marino if (keep_trailing_zeros && str_len < spec.prec)
1425ab6d115fSJohn Marino /* add missing trailing zeros */
14264a238c70SJohn Marino {
1427ab6d115fSJohn Marino np->point = MPFR_DECIMAL_POINT;
1428ab6d115fSJohn Marino np->fp_trailing_zeros = spec.prec - np->fp_size;
1429ab6d115fSJohn Marino }
14304a238c70SJohn Marino
1431ab6d115fSJohn Marino if (spec.alt)
1432ab6d115fSJohn Marino /* add decimal point even if no digits follow it */
14334a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
14344a238c70SJohn Marino }
14354a238c70SJohn Marino
14364a238c70SJohn Marino return 0;
14374a238c70SJohn Marino }
14384a238c70SJohn Marino
14394a238c70SJohn Marino /* partition_number determines the different parts of the string
14404a238c70SJohn Marino representation of the number p according to the given specification.
14414a238c70SJohn Marino partition_number initializes the given structure np, so all previous
14424a238c70SJohn Marino information in that variable is lost.
14434a238c70SJohn Marino return the total number of characters to be written.
14444a238c70SJohn Marino return -1 if an error occured, in that case np's fields are in an undefined
14454a238c70SJohn Marino state but all string buffers have been freed. */
14464a238c70SJohn Marino static int
partition_number(struct number_parts * np,mpfr_srcptr p,struct printf_spec spec)14474a238c70SJohn Marino partition_number (struct number_parts *np, mpfr_srcptr p,
14484a238c70SJohn Marino struct printf_spec spec)
14494a238c70SJohn Marino {
14504a238c70SJohn Marino char *str;
14514a238c70SJohn Marino long total;
14524a238c70SJohn Marino int uppercase;
14534a238c70SJohn Marino
14544a238c70SJohn Marino /* WARNING: left justification means right space padding */
14554a238c70SJohn Marino np->pad_type = spec.left ? RIGHT : spec.pad == '0' ? LEADING_ZEROS : LEFT;
14564a238c70SJohn Marino np->pad_size = 0;
14574a238c70SJohn Marino np->sign = '\0';
14584a238c70SJohn Marino np->prefix_ptr =NULL;
14594a238c70SJohn Marino np->prefix_size = 0;
14604a238c70SJohn Marino np->thousands_sep = '\0';
14614a238c70SJohn Marino np->ip_ptr = NULL;
14624a238c70SJohn Marino np->ip_size = 0;
14634a238c70SJohn Marino np->ip_trailing_zeros = 0;
14644a238c70SJohn Marino np->point = '\0';
14654a238c70SJohn Marino np->fp_leading_zeros = 0;
14664a238c70SJohn Marino np->fp_ptr = NULL;
14674a238c70SJohn Marino np->fp_size = 0;
14684a238c70SJohn Marino np->fp_trailing_zeros = 0;
14694a238c70SJohn Marino np->exp_ptr = NULL;
14704a238c70SJohn Marino np->exp_size = 0;
14714a238c70SJohn Marino np->sl = (struct string_list *)
14724a238c70SJohn Marino (*__gmp_allocate_func) (sizeof (struct string_list));
14734a238c70SJohn Marino init_string_list (np->sl);
14744a238c70SJohn Marino
14754a238c70SJohn Marino uppercase = spec.spec == 'A' || spec.spec == 'E' || spec.spec == 'F'
14764a238c70SJohn Marino || spec.spec == 'G';
14774a238c70SJohn Marino
14784a238c70SJohn Marino if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (p)))
14794a238c70SJohn Marino {
14804a238c70SJohn Marino if (MPFR_IS_NAN (p))
14814a238c70SJohn Marino {
14824a238c70SJohn Marino if (np->pad_type == LEADING_ZEROS)
14834a238c70SJohn Marino /* don't want "0000nan", change to right justification padding
14844a238c70SJohn Marino with left spaces instead */
14854a238c70SJohn Marino np->pad_type = LEFT;
14864a238c70SJohn Marino
14874a238c70SJohn Marino if (uppercase)
14884a238c70SJohn Marino {
14894a238c70SJohn Marino np->ip_size = MPFR_NAN_STRING_LENGTH;
14904a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
14914a238c70SJohn Marino strcpy (str, MPFR_NAN_STRING_UC);
14924a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
14934a238c70SJohn Marino }
14944a238c70SJohn Marino else
14954a238c70SJohn Marino {
14964a238c70SJohn Marino np->ip_size = MPFR_NAN_STRING_LENGTH;
14974a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
14984a238c70SJohn Marino strcpy (str, MPFR_NAN_STRING_LC);
14994a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
15004a238c70SJohn Marino }
15014a238c70SJohn Marino }
15024a238c70SJohn Marino else if (MPFR_IS_INF (p))
15034a238c70SJohn Marino {
15044a238c70SJohn Marino if (np->pad_type == LEADING_ZEROS)
15054a238c70SJohn Marino /* don't want "0000inf", change to right justification padding
15064a238c70SJohn Marino with left spaces instead */
15074a238c70SJohn Marino np->pad_type = LEFT;
15084a238c70SJohn Marino
15094a238c70SJohn Marino if (MPFR_IS_NEG (p))
15104a238c70SJohn Marino np->sign = '-';
15114a238c70SJohn Marino
15124a238c70SJohn Marino if (uppercase)
15134a238c70SJohn Marino {
15144a238c70SJohn Marino np->ip_size = MPFR_INF_STRING_LENGTH;
15154a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
15164a238c70SJohn Marino strcpy (str, MPFR_INF_STRING_UC);
15174a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
15184a238c70SJohn Marino }
15194a238c70SJohn Marino else
15204a238c70SJohn Marino {
15214a238c70SJohn Marino np->ip_size = MPFR_INF_STRING_LENGTH;
15224a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
15234a238c70SJohn Marino strcpy (str, MPFR_INF_STRING_LC);
15244a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
15254a238c70SJohn Marino }
15264a238c70SJohn Marino }
15274a238c70SJohn Marino else
15284a238c70SJohn Marino /* p == 0 */
15294a238c70SJohn Marino {
15304a238c70SJohn Marino /* note: for 'g' spec, zero is always displayed with 'f'-style with
15314a238c70SJohn Marino precision spec.prec - 1 and the trailing zeros are removed unless
15324a238c70SJohn Marino the flag '#' is used. */
15334a238c70SJohn Marino if (MPFR_IS_NEG (p))
15344a238c70SJohn Marino /* signed zero */
15354a238c70SJohn Marino np->sign = '-';
15364a238c70SJohn Marino else if (spec.showsign || spec.space)
15374a238c70SJohn Marino np->sign = spec.showsign ? '+' : ' ';
15384a238c70SJohn Marino
15394a238c70SJohn Marino if (spec.spec == 'a' || spec.spec == 'A')
15404a238c70SJohn Marino /* prefix part */
15414a238c70SJohn Marino {
15424a238c70SJohn Marino np->prefix_size = 2;
15434a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->prefix_size);
15444a238c70SJohn Marino str[0] = '0';
15454a238c70SJohn Marino str[1] = uppercase ? 'X' : 'x';
15464a238c70SJohn Marino str[2] = '\0';
15474a238c70SJohn Marino np->prefix_ptr = register_string (np->sl, str);
15484a238c70SJohn Marino }
15494a238c70SJohn Marino
15504a238c70SJohn Marino /* integral part */
15514a238c70SJohn Marino np->ip_size = 1;
15524a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->ip_size);
15534a238c70SJohn Marino str[0] = '0';
15544a238c70SJohn Marino str[1] = '\0';
15554a238c70SJohn Marino np->ip_ptr = register_string (np->sl, str);
15564a238c70SJohn Marino
15574a238c70SJohn Marino if (spec.prec > 0
15584a238c70SJohn Marino && ((spec.spec != 'g' && spec.spec != 'G') || spec.alt))
15594a238c70SJohn Marino /* fractional part */
15604a238c70SJohn Marino {
15614a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
1562*122b686eSSascha Wildner np->fp_trailing_zeros = (spec.spec == 'g' || spec.spec == 'G') ?
15634a238c70SJohn Marino spec.prec - 1 : spec.prec;
15644a238c70SJohn Marino }
15654a238c70SJohn Marino else if (spec.alt)
15664a238c70SJohn Marino np->point = MPFR_DECIMAL_POINT;
15674a238c70SJohn Marino
15684a238c70SJohn Marino if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b'
15694a238c70SJohn Marino || spec.spec == 'e' || spec.spec == 'E')
15704a238c70SJohn Marino /* exponent part */
15714a238c70SJohn Marino {
15724a238c70SJohn Marino np->exp_size = (spec.spec == 'e' || spec.spec == 'E') ? 4 : 3;
15734a238c70SJohn Marino str = (char *) (*__gmp_allocate_func) (1 + np->exp_size);
15744a238c70SJohn Marino if (spec.spec == 'e' || spec.spec == 'E')
15754a238c70SJohn Marino strcpy (str, uppercase ? "E+00" : "e+00");
15764a238c70SJohn Marino else
15774a238c70SJohn Marino strcpy (str, uppercase ? "P+0" : "p+0");
15784a238c70SJohn Marino np->exp_ptr = register_string (np->sl, str);
15794a238c70SJohn Marino }
15804a238c70SJohn Marino }
15814a238c70SJohn Marino }
15824a238c70SJohn Marino else
15834a238c70SJohn Marino /* regular p, p != 0 */
15844a238c70SJohn Marino {
15854a238c70SJohn Marino if (spec.spec == 'a' || spec.spec == 'A' || spec.spec == 'b')
15864a238c70SJohn Marino {
15874a238c70SJohn Marino if (regular_ab (np, p, spec) == -1)
15884a238c70SJohn Marino goto error;
15894a238c70SJohn Marino }
15904a238c70SJohn Marino else if (spec.spec == 'f' || spec.spec == 'F')
15914a238c70SJohn Marino {
15924a238c70SJohn Marino if (spec.prec == -1)
15934a238c70SJohn Marino spec.prec = 6;
15944a238c70SJohn Marino if (regular_fg (np, p, spec, NULL) == -1)
15954a238c70SJohn Marino goto error;
15964a238c70SJohn Marino }
15974a238c70SJohn Marino else if (spec.spec == 'e' || spec.spec == 'E')
15984a238c70SJohn Marino {
15994a238c70SJohn Marino if (regular_eg (np, p, spec, NULL) == -1)
16004a238c70SJohn Marino goto error;
16014a238c70SJohn Marino }
16024a238c70SJohn Marino else
16034a238c70SJohn Marino /* %g case */
16044a238c70SJohn Marino {
16054a238c70SJohn Marino /* Use the C99 rules:
16064a238c70SJohn Marino if T > X >= -4 then the conversion is with style 'f'/'F' and
16074a238c70SJohn Marino precision T-(X+1).
16084a238c70SJohn Marino otherwise, the conversion is with style 'e'/'E' and
16094a238c70SJohn Marino precision T-1.
16104a238c70SJohn Marino where T is the threshold computed below and X is the exponent
16114a238c70SJohn Marino that would be displayed with style 'e' and precision T-1. */
16124a238c70SJohn Marino int threshold;
16134a238c70SJohn Marino mpfr_exp_t x;
16144a238c70SJohn Marino struct decimal_info dec_info;
16154a238c70SJohn Marino
16164a238c70SJohn Marino threshold = (spec.prec < 0) ? 6 : (spec.prec == 0) ? 1 : spec.prec;
16174a238c70SJohn Marino dec_info.str = mpfr_get_str (NULL, &dec_info.exp, 10, threshold,
16184a238c70SJohn Marino p, spec.rnd_mode);
16194a238c70SJohn Marino register_string (np->sl, dec_info.str);
16204a238c70SJohn Marino /* mpfr_get_str corresponds to a significand between 0.1 and 1,
16214a238c70SJohn Marino whereas here we want a significand between 1 and 10. */
16224a238c70SJohn Marino x = dec_info.exp - 1;
16234a238c70SJohn Marino
16244a238c70SJohn Marino if (threshold > x && x >= -4)
16254a238c70SJohn Marino {
16264a238c70SJohn Marino /* the conversion is with style 'f' */
16274a238c70SJohn Marino spec.prec = threshold - x - 1;
16284a238c70SJohn Marino
16294a238c70SJohn Marino if (regular_fg (np, p, spec, &dec_info) == -1)
16304a238c70SJohn Marino goto error;
16314a238c70SJohn Marino }
16324a238c70SJohn Marino else
16334a238c70SJohn Marino {
16344a238c70SJohn Marino spec.prec = threshold - 1;
16354a238c70SJohn Marino
16364a238c70SJohn Marino if (regular_eg (np, p, spec, &dec_info) == -1)
16374a238c70SJohn Marino goto error;
16384a238c70SJohn Marino }
16394a238c70SJohn Marino }
16404a238c70SJohn Marino }
16414a238c70SJohn Marino
16424a238c70SJohn Marino /* compute the number of characters to be written verifying it is not too
16434a238c70SJohn Marino much */
16444a238c70SJohn Marino total = np->sign ? 1 : 0;
16454a238c70SJohn Marino total += np->prefix_size;
16464a238c70SJohn Marino total += np->ip_size;
16474a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16484a238c70SJohn Marino goto error;
16494a238c70SJohn Marino total += np->ip_trailing_zeros;
16504a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16514a238c70SJohn Marino goto error;
16524a238c70SJohn Marino if (np->thousands_sep)
16534a238c70SJohn Marino /* ' flag, style f and the thousands separator in current locale is not
16544a238c70SJohn Marino reduced to the null character */
16554a238c70SJohn Marino total += (np->ip_size + np->ip_trailing_zeros) / 3;
16564a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16574a238c70SJohn Marino goto error;
16584a238c70SJohn Marino if (np->point)
16594a238c70SJohn Marino ++total;
16604a238c70SJohn Marino total += np->fp_leading_zeros;
16614a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16624a238c70SJohn Marino goto error;
16634a238c70SJohn Marino total += np->fp_size;
16644a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16654a238c70SJohn Marino goto error;
16664a238c70SJohn Marino total += np->fp_trailing_zeros;
16674a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16684a238c70SJohn Marino goto error;
16694a238c70SJohn Marino total += np->exp_size;
16704a238c70SJohn Marino if (MPFR_UNLIKELY (total < 0 || total > INT_MAX))
16714a238c70SJohn Marino goto error;
16724a238c70SJohn Marino
16734a238c70SJohn Marino if (spec.width > total)
16744a238c70SJohn Marino /* pad with spaces or zeros depending on np->pad_type */
16754a238c70SJohn Marino {
16764a238c70SJohn Marino np->pad_size = spec.width - total;
16774a238c70SJohn Marino total += np->pad_size; /* here total == spec.width,
16784a238c70SJohn Marino so 0 < total < INT_MAX */
16794a238c70SJohn Marino }
16804a238c70SJohn Marino
16814a238c70SJohn Marino return total;
16824a238c70SJohn Marino
16834a238c70SJohn Marino error:
16844a238c70SJohn Marino clear_string_list (np->sl);
16854a238c70SJohn Marino np->prefix_ptr = NULL;
16864a238c70SJohn Marino np->ip_ptr = NULL;
16874a238c70SJohn Marino np->fp_ptr = NULL;
16884a238c70SJohn Marino np->exp_ptr = NULL;
16894a238c70SJohn Marino return -1;
16904a238c70SJohn Marino }
16914a238c70SJohn Marino
16924a238c70SJohn Marino /* sprnt_fp prints a mpfr_t according to spec.spec specification.
16934a238c70SJohn Marino
16944a238c70SJohn Marino return the size of the string (not counting the terminating '\0')
16954a238c70SJohn Marino return -1 if the built string is too long (i.e. has more than
16964a238c70SJohn Marino INT_MAX characters). */
16974a238c70SJohn Marino static int
sprnt_fp(struct string_buffer * buf,mpfr_srcptr p,const struct printf_spec spec)16984a238c70SJohn Marino sprnt_fp (struct string_buffer *buf, mpfr_srcptr p,
16994a238c70SJohn Marino const struct printf_spec spec)
17004a238c70SJohn Marino {
17014a238c70SJohn Marino int length;
17024a238c70SJohn Marino struct number_parts np;
17034a238c70SJohn Marino
17044a238c70SJohn Marino length = partition_number (&np, p, spec);
17054a238c70SJohn Marino if (length < 0)
17064a238c70SJohn Marino return -1;
17074a238c70SJohn Marino
17084a238c70SJohn Marino /* right justification padding with left spaces */
17094a238c70SJohn Marino if (np.pad_type == LEFT && np.pad_size != 0)
17104a238c70SJohn Marino buffer_pad (buf, ' ', np.pad_size);
17114a238c70SJohn Marino
17124a238c70SJohn Marino /* sign character (may be '-', '+', or ' ') */
17134a238c70SJohn Marino if (np.sign)
17144a238c70SJohn Marino buffer_pad (buf, np.sign, 1);
17154a238c70SJohn Marino
17164a238c70SJohn Marino /* prefix part */
17174a238c70SJohn Marino if (np.prefix_ptr)
17184a238c70SJohn Marino buffer_cat (buf, np.prefix_ptr, np.prefix_size);
17194a238c70SJohn Marino
17204a238c70SJohn Marino /* right justification padding with leading zeros */
17214a238c70SJohn Marino if (np.pad_type == LEADING_ZEROS && np.pad_size != 0)
17224a238c70SJohn Marino buffer_pad (buf, '0', np.pad_size);
17234a238c70SJohn Marino
17244a238c70SJohn Marino /* integral part (may also be "nan" or "inf") */
17254a238c70SJohn Marino MPFR_ASSERTN (np.ip_ptr != NULL); /* never empty */
17264a238c70SJohn Marino if (MPFR_UNLIKELY (np.thousands_sep))
17274a238c70SJohn Marino buffer_sandwich (buf, np.ip_ptr, np.ip_size, np.ip_trailing_zeros,
17284a238c70SJohn Marino np.thousands_sep);
17294a238c70SJohn Marino else
17304a238c70SJohn Marino {
17314a238c70SJohn Marino buffer_cat (buf, np.ip_ptr, np.ip_size);
17324a238c70SJohn Marino
17334a238c70SJohn Marino /* trailing zeros in integral part */
17344a238c70SJohn Marino if (np.ip_trailing_zeros != 0)
17354a238c70SJohn Marino buffer_pad (buf, '0', np.ip_trailing_zeros);
17364a238c70SJohn Marino }
17374a238c70SJohn Marino
17384a238c70SJohn Marino /* decimal point */
17394a238c70SJohn Marino if (np.point)
17404a238c70SJohn Marino buffer_pad (buf, np.point, 1);
17414a238c70SJohn Marino
17424a238c70SJohn Marino /* leading zeros in fractional part */
17434a238c70SJohn Marino if (np.fp_leading_zeros != 0)
17444a238c70SJohn Marino buffer_pad (buf, '0', np.fp_leading_zeros);
17454a238c70SJohn Marino
17464a238c70SJohn Marino /* significant digits in fractional part */
17474a238c70SJohn Marino if (np.fp_ptr)
17484a238c70SJohn Marino buffer_cat (buf, np.fp_ptr, np.fp_size);
17494a238c70SJohn Marino
17504a238c70SJohn Marino /* trailing zeros in fractional part */
17514a238c70SJohn Marino if (np.fp_trailing_zeros != 0)
17524a238c70SJohn Marino buffer_pad (buf, '0', np.fp_trailing_zeros);
17534a238c70SJohn Marino
17544a238c70SJohn Marino /* exponent part */
17554a238c70SJohn Marino if (np.exp_ptr)
17564a238c70SJohn Marino buffer_cat (buf, np.exp_ptr, np.exp_size);
17574a238c70SJohn Marino
17584a238c70SJohn Marino /* left justication padding with right spaces */
17594a238c70SJohn Marino if (np.pad_type == RIGHT && np.pad_size != 0)
17604a238c70SJohn Marino buffer_pad (buf, ' ', np.pad_size);
17614a238c70SJohn Marino
17624a238c70SJohn Marino clear_string_list (np.sl);
17634a238c70SJohn Marino return length;
17644a238c70SJohn Marino }
17654a238c70SJohn Marino
17664a238c70SJohn Marino int
mpfr_vasprintf(char ** ptr,const char * fmt,va_list ap)17674a238c70SJohn Marino mpfr_vasprintf (char **ptr, const char *fmt, va_list ap)
17684a238c70SJohn Marino {
17694a238c70SJohn Marino struct string_buffer buf;
17704a238c70SJohn Marino size_t nbchar;
17714a238c70SJohn Marino
17724a238c70SJohn Marino /* informations on the conversion specification filled by the parser */
17734a238c70SJohn Marino struct printf_spec spec;
17744a238c70SJohn Marino /* flag raised when previous part of fmt need to be processed by
17754a238c70SJohn Marino gmp_vsnprintf */
17764a238c70SJohn Marino int xgmp_fmt_flag;
17774a238c70SJohn Marino /* beginning and end of the previous unprocessed part of fmt */
17784a238c70SJohn Marino const char *start, *end;
17794a238c70SJohn Marino /* pointer to arguments for gmp_vasprintf */
17804a238c70SJohn Marino va_list ap2;
17814a238c70SJohn Marino
17824a238c70SJohn Marino MPFR_SAVE_EXPO_DECL (expo);
17834a238c70SJohn Marino MPFR_SAVE_EXPO_MARK (expo);
17844a238c70SJohn Marino
17854a238c70SJohn Marino nbchar = 0;
17864a238c70SJohn Marino buffer_init (&buf, 4096);
17874a238c70SJohn Marino xgmp_fmt_flag = 0;
17884a238c70SJohn Marino va_copy (ap2, ap);
17894a238c70SJohn Marino start = fmt;
17904a238c70SJohn Marino while (*fmt)
17914a238c70SJohn Marino {
17924a238c70SJohn Marino /* Look for the next format specification */
17934a238c70SJohn Marino while ((*fmt) && (*fmt != '%'))
17944a238c70SJohn Marino ++fmt;
17954a238c70SJohn Marino
17964a238c70SJohn Marino if (*fmt == '\0')
17974a238c70SJohn Marino break;
17984a238c70SJohn Marino
17994a238c70SJohn Marino if (*++fmt == '%')
18004a238c70SJohn Marino /* %%: go one step further otherwise the second '%' would be
18014a238c70SJohn Marino considered as a new conversion specification introducing
18024a238c70SJohn Marino character */
18034a238c70SJohn Marino {
18044a238c70SJohn Marino ++fmt;
18054a238c70SJohn Marino xgmp_fmt_flag = 1;
18064a238c70SJohn Marino continue;
18074a238c70SJohn Marino }
18084a238c70SJohn Marino
18094a238c70SJohn Marino end = fmt - 1;
18104a238c70SJohn Marino
18114a238c70SJohn Marino /* format string analysis */
18124a238c70SJohn Marino specinfo_init (&spec);
18134a238c70SJohn Marino fmt = parse_flags (fmt, &spec);
18144a238c70SJohn Marino
18154a238c70SJohn Marino READ_INT (ap, fmt, spec, width, width_analysis);
18164a238c70SJohn Marino width_analysis:
18174a238c70SJohn Marino if (spec.width < 0)
18184a238c70SJohn Marino {
18194a238c70SJohn Marino spec.left = 1;
18204a238c70SJohn Marino spec.width = -spec.width;
18214a238c70SJohn Marino MPFR_ASSERTN (spec.width < INT_MAX);
18224a238c70SJohn Marino }
18234a238c70SJohn Marino if (*fmt == '.')
18244a238c70SJohn Marino {
18254a238c70SJohn Marino const char *f = ++fmt;
18264a238c70SJohn Marino READ_INT (ap, fmt, spec, prec, prec_analysis);
18274a238c70SJohn Marino prec_analysis:
18284a238c70SJohn Marino if (f == fmt)
18294a238c70SJohn Marino spec.prec = -1;
18304a238c70SJohn Marino }
18314a238c70SJohn Marino else
18324a238c70SJohn Marino spec.prec = -1;
18334a238c70SJohn Marino
18344a238c70SJohn Marino fmt = parse_arg_type (fmt, &spec);
18354a238c70SJohn Marino if (spec.arg_type == UNSUPPORTED)
18364a238c70SJohn Marino /* the current architecture doesn't support this type */
18374a238c70SJohn Marino {
18384a238c70SJohn Marino goto error;
18394a238c70SJohn Marino }
18404a238c70SJohn Marino else if (spec.arg_type == MPFR_ARG)
18414a238c70SJohn Marino {
18424a238c70SJohn Marino switch (*fmt)
18434a238c70SJohn Marino {
18444a238c70SJohn Marino case '\0':
18454a238c70SJohn Marino break;
18464a238c70SJohn Marino case '*':
18474a238c70SJohn Marino ++fmt;
18484a238c70SJohn Marino spec.rnd_mode = (mpfr_rnd_t) va_arg (ap, int);
18494a238c70SJohn Marino break;
18504a238c70SJohn Marino case 'D':
18514a238c70SJohn Marino ++fmt;
18524a238c70SJohn Marino spec.rnd_mode = MPFR_RNDD;
18534a238c70SJohn Marino break;
18544a238c70SJohn Marino case 'U':
18554a238c70SJohn Marino ++fmt;
18564a238c70SJohn Marino spec.rnd_mode = MPFR_RNDU;
18574a238c70SJohn Marino break;
18584a238c70SJohn Marino case 'Y':
18594a238c70SJohn Marino ++fmt;
18604a238c70SJohn Marino spec.rnd_mode = MPFR_RNDA;
18614a238c70SJohn Marino break;
18624a238c70SJohn Marino case 'Z':
18634a238c70SJohn Marino ++fmt;
18644a238c70SJohn Marino spec.rnd_mode = MPFR_RNDZ;
18654a238c70SJohn Marino break;
18664a238c70SJohn Marino case 'N':
18674a238c70SJohn Marino ++fmt;
18684a238c70SJohn Marino default:
18694a238c70SJohn Marino spec.rnd_mode = MPFR_RNDN;
18704a238c70SJohn Marino }
18714a238c70SJohn Marino }
18724a238c70SJohn Marino
18734a238c70SJohn Marino spec.spec = *fmt;
18744a238c70SJohn Marino if (!specinfo_is_valid (spec))
18754a238c70SJohn Marino goto error;
18764a238c70SJohn Marino
18774a238c70SJohn Marino if (*fmt)
18784a238c70SJohn Marino fmt++;
18794a238c70SJohn Marino
18804a238c70SJohn Marino /* Format processing */
18814a238c70SJohn Marino if (spec.spec == '\0')
18824a238c70SJohn Marino /* end of the format string */
18834a238c70SJohn Marino break;
18844a238c70SJohn Marino else if (spec.spec == 'n')
18854a238c70SJohn Marino /* put the number of characters written so far in the location pointed
18864a238c70SJohn Marino by the next va_list argument; the types of pointer accepted are the
18874a238c70SJohn Marino same as in GMP (except unsupported quad_t) plus pointer to a mpfr_t
18884a238c70SJohn Marino so as to be able to accept the same format strings. */
18894a238c70SJohn Marino {
18904a238c70SJohn Marino void *p;
18914a238c70SJohn Marino size_t nchar;
18924a238c70SJohn Marino
18934a238c70SJohn Marino p = va_arg (ap, void *);
18944a238c70SJohn Marino FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
18954a238c70SJohn Marino va_end (ap2);
18964a238c70SJohn Marino start = fmt;
18974a238c70SJohn Marino nchar = buf.curr - buf.start;
18984a238c70SJohn Marino
18994a238c70SJohn Marino switch (spec.arg_type)
19004a238c70SJohn Marino {
19014a238c70SJohn Marino case CHAR_ARG:
19024a238c70SJohn Marino *(char *) p = (char) nchar;
19034a238c70SJohn Marino break;
19044a238c70SJohn Marino case SHORT_ARG:
19054a238c70SJohn Marino *(short *) p = (short) nchar;
19064a238c70SJohn Marino break;
19074a238c70SJohn Marino case LONG_ARG:
19084a238c70SJohn Marino *(long *) p = (long) nchar;
19094a238c70SJohn Marino break;
19104a238c70SJohn Marino #ifdef HAVE_LONG_LONG
19114a238c70SJohn Marino case LONG_LONG_ARG:
19124a238c70SJohn Marino *(long long *) p = (long long) nchar;
19134a238c70SJohn Marino break;
19144a238c70SJohn Marino #endif
19154a238c70SJohn Marino #ifdef _MPFR_H_HAVE_INTMAX_T
19164a238c70SJohn Marino case INTMAX_ARG:
19174a238c70SJohn Marino *(intmax_t *) p = (intmax_t) nchar;
19184a238c70SJohn Marino break;
19194a238c70SJohn Marino #endif
19204a238c70SJohn Marino case SIZE_ARG:
19214a238c70SJohn Marino *(size_t *) p = nchar;
19224a238c70SJohn Marino break;
19234a238c70SJohn Marino case PTRDIFF_ARG:
19244a238c70SJohn Marino *(ptrdiff_t *) p = (ptrdiff_t) nchar;
19254a238c70SJohn Marino break;
19264a238c70SJohn Marino case MPF_ARG:
19274a238c70SJohn Marino mpf_set_ui ((mpf_ptr) p, (unsigned long) nchar);
19284a238c70SJohn Marino break;
19294a238c70SJohn Marino case MPQ_ARG:
19304a238c70SJohn Marino mpq_set_ui ((mpq_ptr) p, (unsigned long) nchar, 1L);
19314a238c70SJohn Marino break;
19324a238c70SJohn Marino case MP_LIMB_ARG:
19334a238c70SJohn Marino *(mp_limb_t *) p = (mp_limb_t) nchar;
19344a238c70SJohn Marino break;
19354a238c70SJohn Marino case MP_LIMB_ARRAY_ARG:
19364a238c70SJohn Marino {
19374a238c70SJohn Marino mp_limb_t *q = (mp_limb_t *) p;
19384a238c70SJohn Marino mp_size_t n;
19394a238c70SJohn Marino n = va_arg (ap, mp_size_t);
19404a238c70SJohn Marino if (n < 0)
19414a238c70SJohn Marino n = -n;
19424a238c70SJohn Marino else if (n == 0)
19434a238c70SJohn Marino break;
19444a238c70SJohn Marino
19454a238c70SJohn Marino /* we assume here that mp_limb_t is wider than int */
19464a238c70SJohn Marino *q = (mp_limb_t) nchar;
19474a238c70SJohn Marino while (--n != 0)
19484a238c70SJohn Marino {
19494a238c70SJohn Marino q++;
19504a238c70SJohn Marino *q = (mp_limb_t) 0;
19514a238c70SJohn Marino }
19524a238c70SJohn Marino }
19534a238c70SJohn Marino break;
19544a238c70SJohn Marino case MPZ_ARG:
19554a238c70SJohn Marino mpz_set_ui ((mpz_ptr) p, (unsigned long) nchar);
19564a238c70SJohn Marino break;
19574a238c70SJohn Marino
19584a238c70SJohn Marino case MPFR_ARG:
19594a238c70SJohn Marino mpfr_set_ui ((mpfr_ptr) p, (unsigned long) nchar,
19604a238c70SJohn Marino spec.rnd_mode);
19614a238c70SJohn Marino break;
19624a238c70SJohn Marino
19634a238c70SJohn Marino default:
19644a238c70SJohn Marino *(int *) p = (int) nchar;
19654a238c70SJohn Marino }
19664a238c70SJohn Marino va_copy (ap2, ap); /* after the switch, due to MP_LIMB_ARRAY_ARG
19674a238c70SJohn Marino case */
19684a238c70SJohn Marino }
19694a238c70SJohn Marino else if (spec.arg_type == MPFR_PREC_ARG)
19704a238c70SJohn Marino /* output mpfr_prec_t variable */
19714a238c70SJohn Marino {
19724a238c70SJohn Marino char *s;
19734a238c70SJohn Marino char format[MPFR_PREC_FORMAT_SIZE + 6]; /* see examples below */
19744a238c70SJohn Marino size_t length;
19754a238c70SJohn Marino mpfr_prec_t prec;
19764a238c70SJohn Marino prec = va_arg (ap, mpfr_prec_t);
19774a238c70SJohn Marino
19784a238c70SJohn Marino FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
19794a238c70SJohn Marino va_end (ap2);
19804a238c70SJohn Marino va_copy (ap2, ap);
19814a238c70SJohn Marino start = fmt;
19824a238c70SJohn Marino
19834a238c70SJohn Marino /* construct format string, like "%*.*hu" "%*.*u" or "%*.*lu" */
19844a238c70SJohn Marino format[0] = '%';
19854a238c70SJohn Marino format[1] = '*';
19864a238c70SJohn Marino format[2] = '.';
19874a238c70SJohn Marino format[3] = '*';
19884a238c70SJohn Marino format[4] = '\0';
19894a238c70SJohn Marino strcat (format, MPFR_PREC_FORMAT_TYPE);
19904a238c70SJohn Marino format[4 + MPFR_PREC_FORMAT_SIZE] = spec.spec;
19914a238c70SJohn Marino format[5 + MPFR_PREC_FORMAT_SIZE] = '\0';
19924a238c70SJohn Marino length = gmp_asprintf (&s, format, spec.width, spec.prec, prec);
19934a238c70SJohn Marino if (buf.size <= INT_MAX - length)
19944a238c70SJohn Marino {
19954a238c70SJohn Marino buffer_cat (&buf, s, length);
19964a238c70SJohn Marino mpfr_free_str (s);
19974a238c70SJohn Marino }
19984a238c70SJohn Marino else
19994a238c70SJohn Marino {
20004a238c70SJohn Marino mpfr_free_str (s);
20014a238c70SJohn Marino goto overflow_error;
20024a238c70SJohn Marino }
20034a238c70SJohn Marino }
20044a238c70SJohn Marino else if (spec.arg_type == MPFR_ARG)
20054a238c70SJohn Marino /* output a mpfr_t variable */
20064a238c70SJohn Marino {
20074a238c70SJohn Marino mpfr_srcptr p;
20084a238c70SJohn Marino
20094a238c70SJohn Marino p = va_arg (ap, mpfr_srcptr);
20104a238c70SJohn Marino
20114a238c70SJohn Marino FLUSH (xgmp_fmt_flag, start, end, ap2, &buf);
20124a238c70SJohn Marino va_end (ap2);
20134a238c70SJohn Marino va_copy (ap2, ap);
20144a238c70SJohn Marino start = fmt;
20154a238c70SJohn Marino
20164a238c70SJohn Marino switch (spec.spec)
20174a238c70SJohn Marino {
20184a238c70SJohn Marino case 'a':
20194a238c70SJohn Marino case 'A':
20204a238c70SJohn Marino case 'b':
20214a238c70SJohn Marino case 'e':
20224a238c70SJohn Marino case 'E':
20234a238c70SJohn Marino case 'f':
20244a238c70SJohn Marino case 'F':
20254a238c70SJohn Marino case 'g':
20264a238c70SJohn Marino case 'G':
20274a238c70SJohn Marino if (sprnt_fp (&buf, p, spec) < 0)
20284a238c70SJohn Marino goto overflow_error;
20294a238c70SJohn Marino break;
20304a238c70SJohn Marino
20314a238c70SJohn Marino default:
20324a238c70SJohn Marino /* unsupported specifier */
20334a238c70SJohn Marino goto error;
20344a238c70SJohn Marino }
20354a238c70SJohn Marino }
20364a238c70SJohn Marino else
20374a238c70SJohn Marino /* gmp_printf specification, step forward in the va_list */
20384a238c70SJohn Marino {
20394a238c70SJohn Marino CONSUME_VA_ARG (spec, ap);
20404a238c70SJohn Marino xgmp_fmt_flag = 1;
20414a238c70SJohn Marino }
20424a238c70SJohn Marino }
20434a238c70SJohn Marino
20444a238c70SJohn Marino if (start != fmt)
20454a238c70SJohn Marino FLUSH (xgmp_fmt_flag, start, fmt, ap2, &buf);
20464a238c70SJohn Marino
20474a238c70SJohn Marino va_end (ap2);
20484a238c70SJohn Marino nbchar = buf.curr - buf.start;
20494a238c70SJohn Marino MPFR_ASSERTD (nbchar == strlen (buf.start));
20504a238c70SJohn Marino buf.start =
20514a238c70SJohn Marino (char *) (*__gmp_reallocate_func) (buf.start, buf.size, nbchar + 1);
20524a238c70SJohn Marino buf.size = nbchar + 1; /* update needed for __gmp_free_func below when
20534a238c70SJohn Marino nbchar is too large (overflow_error) */
20544a238c70SJohn Marino *ptr = buf.start;
20554a238c70SJohn Marino
20564a238c70SJohn Marino /* If nbchar is larger than INT_MAX, the ISO C99 standard is silent, but
20574a238c70SJohn Marino POSIX says concerning the snprintf() function:
20584a238c70SJohn Marino "[EOVERFLOW] The value of n is greater than {INT_MAX} or the
20594a238c70SJohn Marino number of bytes needed to hold the output excluding the
20604a238c70SJohn Marino terminating null is greater than {INT_MAX}." See:
20614a238c70SJohn Marino http://www.opengroup.org/onlinepubs/009695399/functions/fprintf.html
20624a238c70SJohn Marino But it doesn't say anything concerning the other printf-like functions.
20634a238c70SJohn Marino A defect report has been submitted to austin-review-l (item 2532).
20644a238c70SJohn Marino So, for the time being, we return a negative value and set the erange
20654a238c70SJohn Marino flag, and set errno to EOVERFLOW in POSIX system. */
20664a238c70SJohn Marino if (nbchar <= INT_MAX)
20674a238c70SJohn Marino {
20684a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
20694a238c70SJohn Marino return nbchar;
20704a238c70SJohn Marino }
20714a238c70SJohn Marino
20724a238c70SJohn Marino overflow_error:
20734a238c70SJohn Marino MPFR_SAVE_EXPO_UPDATE_FLAGS(expo, MPFR_FLAGS_ERANGE);
20744a238c70SJohn Marino #ifdef EOVERFLOW
20754a238c70SJohn Marino errno = EOVERFLOW;
20764a238c70SJohn Marino #endif
20774a238c70SJohn Marino
20784a238c70SJohn Marino error:
20794a238c70SJohn Marino MPFR_SAVE_EXPO_FREE (expo);
20804a238c70SJohn Marino *ptr = NULL;
20814a238c70SJohn Marino (*__gmp_free_func) (buf.start, buf.size);
20824a238c70SJohn Marino
20834a238c70SJohn Marino return -1;
20844a238c70SJohn Marino }
20854a238c70SJohn Marino
20864a238c70SJohn Marino #endif /* HAVE_STDARG */
2087