|
Packit |
5c3484 |
/* __gmp_doprnt -- printf style formatted output.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
THE FUNCTIONS IN THIS FILE ARE FOR INTERNAL USE ONLY. THEY'RE ALMOST
|
|
Packit |
5c3484 |
CERTAIN TO BE SUBJECT TO INCOMPATIBLE CHANGES OR DISAPPEAR COMPLETELY IN
|
|
Packit |
5c3484 |
FUTURE GNU MP RELEASES.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Copyright 2001-2003 Free Software Foundation, Inc.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This file is part of the GNU MP Library.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The GNU MP Library is free software; you can redistribute it and/or modify
|
|
Packit |
5c3484 |
it under the terms of either:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
* the GNU Lesser General Public License as published by the Free
|
|
Packit |
5c3484 |
Software Foundation; either version 3 of the License, or (at your
|
|
Packit |
5c3484 |
option) any later version.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
or
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
* the GNU General Public License as published by the Free Software
|
|
Packit |
5c3484 |
Foundation; either version 2 of the License, or (at your option) any
|
|
Packit |
5c3484 |
later version.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
or both in parallel, as here.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
The GNU MP Library is distributed in the hope that it will be useful, but
|
|
Packit |
5c3484 |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
Packit |
5c3484 |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
Packit |
5c3484 |
for more details.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
You should have received copies of the GNU General Public License and the
|
|
Packit |
5c3484 |
GNU Lesser General Public License along with the GNU MP Library. If not,
|
|
Packit |
5c3484 |
see https://www.gnu.org/licenses/. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#define _GNU_SOURCE /* for DECIMAL_POINT in glibc langinfo.h */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include "config.h" /* needed for the HAVE_, could also move gmp incls */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include <stdarg.h>
|
|
Packit |
5c3484 |
#include <ctype.h> /* for isdigit */
|
|
Packit |
5c3484 |
#include <stddef.h> /* for ptrdiff_t */
|
|
Packit |
5c3484 |
#include <string.h>
|
|
Packit |
5c3484 |
#include <stdio.h> /* for NULL */
|
|
Packit |
5c3484 |
#include <stdlib.h>
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#if HAVE_INTTYPES_H
|
|
Packit |
5c3484 |
# include <inttypes.h> /* for intmax_t */
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
# if HAVE_STDINT_H
|
|
Packit |
5c3484 |
# include <stdint.h>
|
|
Packit |
5c3484 |
# endif
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#if HAVE_LANGINFO_H
|
|
Packit |
5c3484 |
#include <langinfo.h> /* for nl_langinfo */
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#if HAVE_LOCALE_H
|
|
Packit |
5c3484 |
#include <locale.h> /* for localeconv */
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#if HAVE_SYS_TYPES_H
|
|
Packit |
5c3484 |
#include <sys/types.h> /* for quad_t */
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#include "gmp.h"
|
|
Packit |
5c3484 |
#include "gmp-impl.h"
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* change this to "#define TRACE(x) x" for diagnostics */
|
|
Packit |
5c3484 |
#define TRACE(x)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Should be portable, but in any case this is only used under some ASSERTs. */
|
|
Packit |
5c3484 |
#define va_equal(x, y) \
|
|
Packit |
5c3484 |
(memcmp (&(x), &(y), sizeof(va_list)) == 0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* printf is convenient because it allows various types to be printed in one
|
|
Packit |
5c3484 |
fairly compact call, so having gmp_printf support the standard types as
|
|
Packit |
5c3484 |
well as the gmp ones is important. This ends up meaning all the standard
|
|
Packit |
5c3484 |
parsing must be duplicated, to get a new routine recognising the gmp
|
|
Packit |
5c3484 |
extras.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
With the currently favoured handling of mpz etc as Z, Q and F type
|
|
Packit |
5c3484 |
markers, it's not possible to use glibc register_printf_function since
|
|
Packit |
5c3484 |
that only accepts new conversion characters, not new types. If Z was a
|
|
Packit |
5c3484 |
conversion there'd be no way to specify hex, decimal or octal, or
|
|
Packit |
5c3484 |
similarly with F no way to specify fixed point or scientific format.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
It seems wisest to pass conversions %f, %e and %g of float, double and
|
|
Packit |
5c3484 |
long double over to the standard printf. It'd be hard to be sure of
|
|
Packit |
5c3484 |
getting the right handling for NaNs, rounding, etc. Integer conversions
|
|
Packit |
5c3484 |
%d etc and string conversions %s on the other hand could be easily enough
|
|
Packit |
5c3484 |
handled within gmp_doprnt, but if floats are going to libc then it's just
|
|
Packit |
5c3484 |
as easy to send all non-gmp types there.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
"Z" was a type marker for size_t in old glibc, but there seems no need to
|
|
Packit |
5c3484 |
provide access to that now "z" is standard.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
In GMP 4.1.1 we documented "ll" and "L" as being equivalent, but in C99
|
|
Packit |
5c3484 |
in fact "ll" is just for long long and "L" just for long double.
|
|
Packit |
5c3484 |
Apparently GLIBC allows "L" for long long though. This doesn't affect
|
|
Packit |
5c3484 |
us as such, since both are passed through to the C library. To be
|
|
Packit |
5c3484 |
consistent with what we said before, the two are treated equivalently
|
|
Packit |
5c3484 |
here, and it's left to the C library to do what it thinks with them.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Possibilities:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
"b" might be nice for binary output, and could even be supported for the
|
|
Packit |
5c3484 |
standard C types too if desired.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
POSIX style "%n$" parameter numbering would be possible, but would need
|
|
Packit |
5c3484 |
to be handled completely within gmp_doprnt, since the numbering will be
|
|
Packit |
5c3484 |
all different once the format string it cut into pieces.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Some options for mpq formatting would be good. Perhaps a non-zero
|
|
Packit |
5c3484 |
precision field could give a width for the denominator and mean always
|
|
Packit |
5c3484 |
put a "/". A form "n+p/q" might interesting too, though perhaps that's
|
|
Packit |
5c3484 |
better left to applications.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Right now there's no way for an application to know whether types like
|
|
Packit |
5c3484 |
intmax_t are supported here. If configure is doing its job and the same
|
|
Packit |
5c3484 |
compiler is used for gmp as for the application then there shouldn't be
|
|
Packit |
5c3484 |
any problem, but perhaps gmp.h should have some preprocessor symbols to
|
|
Packit |
5c3484 |
say what libgmp can do. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* If a gmp format is the very first thing or there are two gmp formats with
|
|
Packit |
5c3484 |
nothing in between then we'll reach here with this_fmt == last_fmt and we
|
|
Packit |
5c3484 |
can do nothing in that case.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
last_ap is always replaced after a FLUSH, so it doesn't matter if va_list
|
|
Packit |
5c3484 |
is a call-by-reference and the funs->format routine modifies it. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#define FLUSH() \
|
|
Packit |
5c3484 |
do { \
|
|
Packit |
5c3484 |
if (this_fmt == last_fmt) \
|
|
Packit |
5c3484 |
{ \
|
|
Packit |
5c3484 |
TRACE (printf ("nothing to flush\n")); \
|
|
Packit |
5c3484 |
ASSERT (va_equal (this_ap, last_ap)); \
|
|
Packit |
5c3484 |
} \
|
|
Packit |
5c3484 |
else \
|
|
Packit |
5c3484 |
{ \
|
|
Packit |
5c3484 |
ASSERT (*this_fmt == '%'); \
|
|
Packit |
5c3484 |
*this_fmt = '\0'; \
|
|
Packit |
5c3484 |
TRACE (printf ("flush \"%s\"\n", last_fmt)); \
|
|
Packit |
5c3484 |
DOPRNT_FORMAT (last_fmt, last_ap); \
|
|
Packit |
5c3484 |
} \
|
|
Packit |
5c3484 |
} while (0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Parse up the given format string and do the appropriate output using the
|
|
Packit |
5c3484 |
given "funs" routines. The data parameter is passed through to those
|
|
Packit |
5c3484 |
routines. */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
__gmp_doprnt (const struct doprnt_funs_t *funs, void *data,
|
|
Packit |
5c3484 |
const char *orig_fmt, va_list orig_ap)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
va_list ap, this_ap, last_ap;
|
|
Packit |
5c3484 |
size_t alloc_fmt_size, orig_fmt_size;
|
|
Packit |
5c3484 |
char *fmt, *alloc_fmt, *last_fmt, *this_fmt, *gmp_str;
|
|
Packit |
5c3484 |
int retval = 0;
|
|
Packit |
5c3484 |
int type, fchar, *value, seen_precision;
|
|
Packit |
5c3484 |
struct doprnt_params_t param;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf ("gmp_doprnt \"%s\"\n", orig_fmt));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Don't modify orig_ap, if va_list is actually an array and hence call by
|
|
Packit |
5c3484 |
reference. It could be argued that it'd be more efficient to leave the
|
|
Packit |
5c3484 |
caller to make a copy if it cared, but doing so here is going to be a
|
|
Packit |
5c3484 |
very small part of the total work, and we may as well keep applications
|
|
Packit |
5c3484 |
out of trouble. */
|
|
Packit |
5c3484 |
va_copy (ap, orig_ap);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* The format string is chopped up into pieces to be passed to
|
|
Packit |
5c3484 |
funs->format. Unfortunately that means it has to be copied so each
|
|
Packit |
5c3484 |
piece can be null-terminated. We're not going to be very fast here, so
|
|
Packit |
5c3484 |
use __gmp_allocate_func rather than TMP_ALLOC, to avoid overflowing the
|
|
Packit |
5c3484 |
stack if a long output string is given. */
|
|
Packit |
5c3484 |
alloc_fmt_size = orig_fmt_size = strlen (orig_fmt) + 1;
|
|
Packit |
5c3484 |
#if _LONG_LONG_LIMB
|
|
Packit |
5c3484 |
/* for a long long limb we change %Mx to %llx, so could need an extra 1
|
|
Packit |
5c3484 |
char for every 3 existing */
|
|
Packit |
5c3484 |
alloc_fmt_size += alloc_fmt_size / 3;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
|
|
Packit |
5c3484 |
fmt = alloc_fmt;
|
|
Packit |
5c3484 |
memcpy (fmt, orig_fmt, orig_fmt_size);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* last_fmt and last_ap are just after the last output, and hence where
|
|
Packit |
5c3484 |
the next output will begin, when that's done */
|
|
Packit |
5c3484 |
last_fmt = fmt;
|
|
Packit |
5c3484 |
va_copy (last_ap, ap);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
TRACE (printf ("next: \"%s\"\n", fmt));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
fmt = strchr (fmt, '%');
|
|
Packit |
5c3484 |
if (fmt == NULL)
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* this_fmt and this_ap are the current '%' sequence being considered */
|
|
Packit |
5c3484 |
this_fmt = fmt;
|
|
Packit |
5c3484 |
va_copy (this_ap, ap);
|
|
Packit |
5c3484 |
fmt++; /* skip the '%' */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf ("considering\n");
|
|
Packit |
5c3484 |
printf (" last: \"%s\"\n", last_fmt);
|
|
Packit |
5c3484 |
printf (" this: \"%s\"\n", this_fmt));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
type = '\0';
|
|
Packit |
5c3484 |
value = ¶m.width;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
param.base = 10;
|
|
Packit |
5c3484 |
param.conv = 0;
|
|
Packit |
5c3484 |
param.expfmt = "e%c%02ld";
|
|
Packit |
5c3484 |
param.exptimes4 = 0;
|
|
Packit |
5c3484 |
param.fill = ' ';
|
|
Packit |
5c3484 |
param.justify = DOPRNT_JUSTIFY_RIGHT;
|
|
Packit |
5c3484 |
param.prec = 6;
|
|
Packit |
5c3484 |
param.showbase = DOPRNT_SHOWBASE_NO;
|
|
Packit |
5c3484 |
param.showpoint = 0;
|
|
Packit |
5c3484 |
param.showtrailing = 1;
|
|
Packit |
5c3484 |
param.sign = '\0';
|
|
Packit |
5c3484 |
param.width = 0;
|
|
Packit |
5c3484 |
seen_precision = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* This loop parses a single % sequence. "break" from the switch
|
|
Packit |
5c3484 |
means continue with this %, "goto next" means the conversion
|
|
Packit |
5c3484 |
character has been seen and a new % should be sought. */
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
if (fchar == '\0')
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
switch (fchar) {
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'a':
|
|
Packit |
5c3484 |
/* %a behaves like %e, but defaults to all significant digits,
|
|
Packit |
5c3484 |
and there's no leading zeros on the exponent (which is in
|
|
Packit |
5c3484 |
fact bit-based) */
|
|
Packit |
5c3484 |
param.base = 16;
|
|
Packit |
5c3484 |
param.expfmt = "p%c%ld";
|
|
Packit |
5c3484 |
goto conv_a;
|
|
Packit |
5c3484 |
case 'A':
|
|
Packit |
5c3484 |
param.base = -16;
|
|
Packit |
5c3484 |
param.expfmt = "P%c%ld";
|
|
Packit |
5c3484 |
conv_a:
|
|
Packit |
5c3484 |
param.conv = DOPRNT_CONV_SCIENTIFIC;
|
|
Packit |
5c3484 |
param.exptimes4 = 1;
|
|
Packit |
5c3484 |
if (! seen_precision)
|
|
Packit |
5c3484 |
param.prec = -1; /* default to all digits */
|
|
Packit |
5c3484 |
param.showbase = DOPRNT_SHOWBASE_YES;
|
|
Packit |
5c3484 |
param.showtrailing = 1;
|
|
Packit |
5c3484 |
goto floating_a;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'c':
|
|
Packit |
5c3484 |
/* Let's assume wchar_t will be promoted to "int" in the call,
|
|
Packit |
5c3484 |
the same as char will be. */
|
|
Packit |
5c3484 |
(void) va_arg (ap, int);
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'd':
|
|
Packit |
5c3484 |
case 'i':
|
|
Packit |
5c3484 |
case 'u':
|
|
Packit |
5c3484 |
integer:
|
|
Packit |
5c3484 |
TRACE (printf ("integer, base=%d\n", param.base));
|
|
Packit |
5c3484 |
if (! seen_precision)
|
|
Packit |
5c3484 |
param.prec = -1;
|
|
Packit |
5c3484 |
switch (type) {
|
|
Packit |
5c3484 |
case 'j':
|
|
Packit |
5c3484 |
/* Let's assume uintmax_t is the same size as intmax_t. */
|
|
Packit |
5c3484 |
#if HAVE_INTMAX_T
|
|
Packit |
5c3484 |
(void) va_arg (ap, intmax_t);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
ASSERT_FAIL (intmax_t not available);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'l':
|
|
Packit |
5c3484 |
(void) va_arg (ap, long);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'L':
|
|
Packit |
5c3484 |
#if HAVE_LONG_LONG
|
|
Packit |
5c3484 |
(void) va_arg (ap, long long);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
ASSERT_FAIL (long long not available);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'N':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mp_ptr xp;
|
|
Packit |
5c3484 |
mp_size_t xsize, abs_xsize;
|
|
Packit |
5c3484 |
mpz_t z;
|
|
Packit |
5c3484 |
FLUSH ();
|
|
Packit |
5c3484 |
xp = va_arg (ap, mp_ptr);
|
|
Packit |
5c3484 |
PTR(z) = xp;
|
|
Packit |
5c3484 |
xsize = (int) va_arg (ap, mp_size_t);
|
|
Packit |
5c3484 |
abs_xsize = ABS (xsize);
|
|
Packit |
5c3484 |
MPN_NORMALIZE (xp, abs_xsize);
|
|
Packit |
5c3484 |
SIZ(z) = (xsize >= 0 ? abs_xsize : -abs_xsize);
|
|
Packit |
5c3484 |
ASSERT_CODE (ALLOC(z) = abs_xsize);
|
|
Packit |
5c3484 |
gmp_str = mpz_get_str (NULL, param.base, z);
|
|
Packit |
5c3484 |
goto gmp_integer;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
/* break; */
|
|
Packit |
5c3484 |
case 'q':
|
|
Packit |
5c3484 |
/* quad_t is probably the same as long long, but let's treat
|
|
Packit |
5c3484 |
it separately just to be sure. Also let's assume u_quad_t
|
|
Packit |
5c3484 |
will be the same size as quad_t. */
|
|
Packit |
5c3484 |
#if HAVE_QUAD_T
|
|
Packit |
5c3484 |
(void) va_arg (ap, quad_t);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
ASSERT_FAIL (quad_t not available);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'Q':
|
|
Packit |
5c3484 |
FLUSH ();
|
|
Packit |
5c3484 |
gmp_str = mpq_get_str (NULL, param.base, va_arg(ap, mpq_srcptr));
|
|
Packit |
5c3484 |
goto gmp_integer;
|
|
Packit |
5c3484 |
case 't':
|
|
Packit |
5c3484 |
#if HAVE_PTRDIFF_T
|
|
Packit |
5c3484 |
(void) va_arg (ap, ptrdiff_t);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
ASSERT_FAIL (ptrdiff_t not available);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'z':
|
|
Packit |
5c3484 |
(void) va_arg (ap, size_t);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'Z':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int ret;
|
|
Packit |
5c3484 |
FLUSH ();
|
|
Packit |
5c3484 |
gmp_str = mpz_get_str (NULL, param.base,
|
|
Packit |
5c3484 |
va_arg (ap, mpz_srcptr));
|
|
Packit |
5c3484 |
gmp_integer:
|
|
Packit |
5c3484 |
ret = __gmp_doprnt_integer (funs, data, ¶m, gmp_str);
|
|
Packit |
5c3484 |
(*__gmp_free_func) (gmp_str, strlen(gmp_str)+1);
|
|
Packit |
5c3484 |
DOPRNT_ACCUMULATE (ret);
|
|
Packit |
5c3484 |
va_copy (last_ap, ap);
|
|
Packit |
5c3484 |
last_fmt = fmt;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
/* default is an "int", and this includes h=short and hh=char
|
|
Packit |
5c3484 |
since they're promoted to int in a function call */
|
|
Packit |
5c3484 |
(void) va_arg (ap, int);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'E':
|
|
Packit |
5c3484 |
param.base = -10;
|
|
Packit |
5c3484 |
param.expfmt = "E%c%02ld";
|
|
Packit |
5c3484 |
/*FALLTHRU*/
|
|
Packit |
5c3484 |
case 'e':
|
|
Packit |
5c3484 |
param.conv = DOPRNT_CONV_SCIENTIFIC;
|
|
Packit |
5c3484 |
floating:
|
|
Packit |
5c3484 |
if (param.showbase == DOPRNT_SHOWBASE_NONZERO)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* # in %e, %f and %g */
|
|
Packit |
5c3484 |
param.showpoint = 1;
|
|
Packit |
5c3484 |
param.showtrailing = 1;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
floating_a:
|
|
Packit |
5c3484 |
switch (type) {
|
|
Packit |
5c3484 |
case 'F':
|
|
Packit |
5c3484 |
FLUSH ();
|
|
Packit |
5c3484 |
DOPRNT_ACCUMULATE (__gmp_doprnt_mpf (funs, data, ¶m,
|
|
Packit |
5c3484 |
GMP_DECIMAL_POINT,
|
|
Packit |
5c3484 |
va_arg (ap, mpf_srcptr)));
|
|
Packit |
5c3484 |
va_copy (last_ap, ap);
|
|
Packit |
5c3484 |
last_fmt = fmt;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'L':
|
|
Packit |
5c3484 |
#if HAVE_LONG_DOUBLE
|
|
Packit |
5c3484 |
(void) va_arg (ap, long double);
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
ASSERT_FAIL (long double not available);
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
(void) va_arg (ap, double);
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'f':
|
|
Packit |
5c3484 |
param.conv = DOPRNT_CONV_FIXED;
|
|
Packit |
5c3484 |
goto floating;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'F': /* mpf_t */
|
|
Packit |
5c3484 |
case 'j': /* intmax_t */
|
|
Packit |
5c3484 |
case 'L': /* long long */
|
|
Packit |
5c3484 |
case 'N': /* mpn */
|
|
Packit |
5c3484 |
case 'q': /* quad_t */
|
|
Packit |
5c3484 |
case 'Q': /* mpq_t */
|
|
Packit |
5c3484 |
case 't': /* ptrdiff_t */
|
|
Packit |
5c3484 |
case 'z': /* size_t */
|
|
Packit |
5c3484 |
case 'Z': /* mpz_t */
|
|
Packit |
5c3484 |
set_type:
|
|
Packit |
5c3484 |
type = fchar;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'G':
|
|
Packit |
5c3484 |
param.base = -10;
|
|
Packit |
5c3484 |
param.expfmt = "E%c%02ld";
|
|
Packit |
5c3484 |
/*FALLTHRU*/
|
|
Packit |
5c3484 |
case 'g':
|
|
Packit |
5c3484 |
param.conv = DOPRNT_CONV_GENERAL;
|
|
Packit |
5c3484 |
param.showtrailing = 0;
|
|
Packit |
5c3484 |
goto floating;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'h':
|
|
Packit |
5c3484 |
if (type != 'h')
|
|
Packit |
5c3484 |
goto set_type;
|
|
Packit |
5c3484 |
type = 'H'; /* internal code for "hh" */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'l':
|
|
Packit |
5c3484 |
if (type != 'l')
|
|
Packit |
5c3484 |
goto set_type;
|
|
Packit |
5c3484 |
type = 'L'; /* "ll" means "L" */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'm':
|
|
Packit |
5c3484 |
/* glibc strerror(errno), no argument */
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'M': /* mp_limb_t */
|
|
Packit |
5c3484 |
/* mung format string to l or ll and let plain printf handle it */
|
|
Packit |
5c3484 |
#if _LONG_LONG_LIMB
|
|
Packit |
5c3484 |
memmove (fmt+1, fmt, strlen (fmt)+1);
|
|
Packit |
5c3484 |
fmt[-1] = 'l';
|
|
Packit |
5c3484 |
fmt[0] = 'l';
|
|
Packit |
5c3484 |
fmt++;
|
|
Packit |
5c3484 |
type = 'L';
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
fmt[-1] = 'l';
|
|
Packit |
5c3484 |
type = 'l';
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'n':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
void *p;
|
|
Packit |
5c3484 |
FLUSH ();
|
|
Packit |
5c3484 |
p = va_arg (ap, void *);
|
|
Packit |
5c3484 |
switch (type) {
|
|
Packit |
5c3484 |
case '\0': * (int *) p = retval; break;
|
|
Packit |
5c3484 |
case 'F': mpf_set_si ((mpf_ptr) p, (long) retval); break;
|
|
Packit |
5c3484 |
case 'H': * (char *) p = retval; break;
|
|
Packit |
5c3484 |
case 'h': * (short *) p = retval; break;
|
|
Packit |
5c3484 |
#if HAVE_INTMAX_T
|
|
Packit |
5c3484 |
case 'j': * (intmax_t *) p = retval; break;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 'j': ASSERT_FAIL (intmax_t not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case 'l': * (long *) p = retval; break;
|
|
Packit |
5c3484 |
#if HAVE_QUAD_T && HAVE_LONG_LONG
|
|
Packit |
5c3484 |
case 'q':
|
|
Packit |
5c3484 |
ASSERT_ALWAYS (sizeof (quad_t) == sizeof (long long));
|
|
Packit |
5c3484 |
/*FALLTHRU*/
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 'q': ASSERT_FAIL (quad_t not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
#if HAVE_LONG_LONG
|
|
Packit |
5c3484 |
case 'L': * (long long *) p = retval; break;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 'L': ASSERT_FAIL (long long not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case 'N':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mp_size_t n;
|
|
Packit |
5c3484 |
n = va_arg (ap, mp_size_t);
|
|
Packit |
5c3484 |
n = ABS (n);
|
|
Packit |
5c3484 |
if (n != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
* (mp_ptr) p = retval;
|
|
Packit |
5c3484 |
MPN_ZERO ((mp_ptr) p + 1, n - 1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'Q': mpq_set_si ((mpq_ptr) p, (long) retval, 1L); break;
|
|
Packit |
5c3484 |
#if HAVE_PTRDIFF_T
|
|
Packit |
5c3484 |
case 't': * (ptrdiff_t *) p = retval; break;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 't': ASSERT_FAIL (ptrdiff_t not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case 'z': * (size_t *) p = retval; break;
|
|
Packit |
5c3484 |
case 'Z': mpz_set_si ((mpz_ptr) p, (long) retval); break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
va_copy (last_ap, ap);
|
|
Packit |
5c3484 |
last_fmt = fmt;
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'o':
|
|
Packit |
5c3484 |
param.base = 8;
|
|
Packit |
5c3484 |
goto integer;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'p':
|
|
Packit |
5c3484 |
case 's':
|
|
Packit |
5c3484 |
/* "void *" will be good enough for "char *" or "wchar_t *", no
|
|
Packit |
5c3484 |
need for separate code. */
|
|
Packit |
5c3484 |
(void) va_arg (ap, const void *);
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'x':
|
|
Packit |
5c3484 |
param.base = 16;
|
|
Packit |
5c3484 |
goto integer;
|
|
Packit |
5c3484 |
case 'X':
|
|
Packit |
5c3484 |
param.base = -16;
|
|
Packit |
5c3484 |
goto integer;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '%':
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '#':
|
|
Packit |
5c3484 |
param.showbase = DOPRNT_SHOWBASE_NONZERO;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '\'':
|
|
Packit |
5c3484 |
/* glibc digit grouping, just pass it through, no support for it
|
|
Packit |
5c3484 |
on gmp types */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '+':
|
|
Packit |
5c3484 |
case ' ':
|
|
Packit |
5c3484 |
param.sign = fchar;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '-':
|
|
Packit |
5c3484 |
param.justify = DOPRNT_JUSTIFY_LEFT;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case '.':
|
|
Packit |
5c3484 |
seen_precision = 1;
|
|
Packit |
5c3484 |
param.prec = -1; /* "." alone means all necessary digits */
|
|
Packit |
5c3484 |
value = ¶m.prec;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '*':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int n = va_arg (ap, int);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (value == ¶m.width)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* negative width means left justify */
|
|
Packit |
5c3484 |
if (n < 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
param.justify = DOPRNT_JUSTIFY_LEFT;
|
|
Packit |
5c3484 |
n = -n;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
param.width = n;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* don't allow negative precision */
|
|
Packit |
5c3484 |
param.prec = MAX (0, n);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '0':
|
|
Packit |
5c3484 |
if (value == ¶m.width)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* in width field, set fill */
|
|
Packit |
5c3484 |
param.fill = '0';
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* for right justify, put the fill after any minus sign */
|
|
Packit |
5c3484 |
if (param.justify == DOPRNT_JUSTIFY_RIGHT)
|
|
Packit |
5c3484 |
param.justify = DOPRNT_JUSTIFY_INTERNAL;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* in precision field, set value */
|
|
Packit |
5c3484 |
*value = 0;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '1': case '2': case '3': case '4': case '5':
|
|
Packit |
5c3484 |
case '6': case '7': case '8': case '9':
|
|
Packit |
5c3484 |
/* process all digits to form a value */
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int n = 0;
|
|
Packit |
5c3484 |
do {
|
|
Packit |
5c3484 |
n = n * 10 + (fchar-'0');
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
} while (isascii (fchar) && isdigit (fchar));
|
|
Packit |
5c3484 |
fmt--; /* unget the non-digit */
|
|
Packit |
5c3484 |
*value = n;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
/* something invalid */
|
|
Packit |
5c3484 |
ASSERT (0);
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
next:
|
|
Packit |
5c3484 |
/* Stop parsing the current "%" format, look for a new one. */
|
|
Packit |
5c3484 |
;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf ("remainder: \"%s\"\n", last_fmt));
|
|
Packit |
5c3484 |
if (*last_fmt != '\0')
|
|
Packit |
5c3484 |
DOPRNT_FORMAT (last_fmt, last_ap);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (funs->final != NULL)
|
|
Packit |
5c3484 |
if ((*funs->final) (data) == -1)
|
|
Packit |
5c3484 |
goto error;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
done:
|
|
Packit |
5c3484 |
(*__gmp_free_func) (alloc_fmt, alloc_fmt_size);
|
|
Packit |
5c3484 |
return retval;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
error:
|
|
Packit |
5c3484 |
retval = -1;
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
}
|