|
Packit |
5c3484 |
/* __gmp_doscan -- formatted input internals.
|
|
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 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>
|
|
Packit |
5c3484 |
#include <stddef.h> /* for ptrdiff_t */
|
|
Packit |
5c3484 |
#include <stdio.h>
|
|
Packit |
5c3484 |
#include <stdlib.h> /* for strtol */
|
|
Packit |
5c3484 |
#include <string.h>
|
|
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_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_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 some traces. */
|
|
Packit |
5c3484 |
#define TRACE(x)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* General:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
It's necessary to parse up the format string to recognise the GMP
|
|
Packit |
5c3484 |
extra types F, Q and Z. Other types and conversions are passed
|
|
Packit |
5c3484 |
across to the standard sscanf or fscanf via funs->scan, for ease of
|
|
Packit |
5c3484 |
implementation. This is essential in the case of something like glibc
|
|
Packit |
5c3484 |
%p where the pointer format isn't actually documented.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Because funs->scan doesn't get the whole input it can't put the right
|
|
Packit |
5c3484 |
values in for %n, so that's handled in __gmp_doscan. Neither sscanf
|
|
Packit |
5c3484 |
nor fscanf directly indicate how many characters were read, so an
|
|
Packit |
5c3484 |
extra %n is appended to each run for that. For fscanf this merely
|
|
Packit |
5c3484 |
supports our %n output, but for sscanf it lets funs->step move us
|
|
Packit |
5c3484 |
along the input string.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Whitespace and literal matches in the format string, including %%,
|
|
Packit |
5c3484 |
are handled directly within __gmp_doscan. This is reasonably
|
|
Packit |
5c3484 |
efficient, and avoids some suspicious behaviour observed in various
|
|
Packit |
5c3484 |
system libc's. GLIBC 2.2.4 for instance returns 0 on
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
sscanf(" ", " x")
|
|
Packit |
5c3484 |
or
|
|
Packit |
5c3484 |
sscanf(" ", " x%d",&n)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
whereas we think they should return EOF, since end-of-string is
|
|
Packit |
5c3484 |
reached when a match of "x" is required.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
For standard % conversions, funs->scan is called once for each
|
|
Packit |
5c3484 |
conversion. If we had vfscanf and vsscanf and could rely on their
|
|
Packit |
5c3484 |
fixed text matching behaviour then we could call them with multiple
|
|
Packit |
5c3484 |
consecutive standard conversions. But plain fscanf and sscanf work
|
|
Packit |
5c3484 |
fine, and parsing one field at a time shouldn't be too much of a
|
|
Packit |
5c3484 |
slowdown.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
gmpscan:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
gmpscan reads a gmp type. It's only used from one place, but is a
|
|
Packit |
5c3484 |
separate subroutine to avoid a big chunk of complicated code in the
|
|
Packit |
5c3484 |
middle of __gmp_doscan. Within gmpscan a couple of loopbacks make it
|
|
Packit |
5c3484 |
possible to share code for parsing integers, rationals and floats.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
In gmpscan normally one char of lookahead is maintained, but when width
|
|
Packit |
5c3484 |
is reached that stops, on the principle that an fgetc/ungetc of a char
|
|
Packit |
5c3484 |
past where we're told to stop would be undesirable. "chars" is how many
|
|
Packit |
5c3484 |
characters have been read so far, including the current c. When
|
|
Packit |
5c3484 |
chars==width and another character is desired then a jump is done to the
|
|
Packit |
5c3484 |
"convert" stage. c is invalid and mustn't be unget'ed in this case;
|
|
Packit |
5c3484 |
chars is set to width+1 to indicate that.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
gmpscan normally returns the number of characters read. -1 means an
|
|
Packit |
5c3484 |
invalid field, -2 means EOF reached before any matching characters
|
|
Packit |
5c3484 |
were read.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
For hex floats, the mantissa part is passed to mpf_set_str, then the
|
|
Packit |
5c3484 |
exponent is applied with mpf_mul_exp or mpf_div_2exp. This is easier
|
|
Packit |
5c3484 |
than teaching mpf_set_str about an exponent factor (ie. 2) differing
|
|
Packit |
5c3484 |
from the mantissa radix point factor (ie. 16). mpf_mul_exp and
|
|
Packit |
5c3484 |
mpf_div_2exp will preserve the application requested precision, so
|
|
Packit |
5c3484 |
nothing in that respect is lost by making this a two-step process.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Matching and errors:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
C99 7.19.6.2 paras 9 and 10 say an input item is read as the longest
|
|
Packit |
5c3484 |
string which is a match for the appropriate type, or a prefix of a
|
|
Packit |
5c3484 |
match. With that done, if it's only a prefix then the result is a
|
|
Packit |
5c3484 |
matching failure, ie. invalid input.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
This rule seems fairly clear, but doesn't seem to be universally
|
|
Packit |
5c3484 |
applied in system C libraries. Even GLIBC doesn't seem to get it
|
|
Packit |
5c3484 |
right, insofar as it seems to accept some apparently invalid forms.
|
|
Packit |
5c3484 |
Eg. glibc 2.3.1 accepts "0x" for a "%i", where a reading of the
|
|
Packit |
5c3484 |
standard would suggest a non-empty sequence of digits should be
|
|
Packit |
5c3484 |
required after an "0x".
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
A footnote to 7.19.6.2 para 17 notes how this input item reading can
|
|
Packit |
5c3484 |
mean inputs acceptable to strtol are not acceptable to fscanf. We
|
|
Packit |
5c3484 |
think this confirms our reading of "0x" as invalid.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Clearly gmp_sscanf could backtrack to a longest input which was a
|
|
Packit |
5c3484 |
valid match for a given item, but this is not done, since C99 says
|
|
Packit |
5c3484 |
sscanf is identical to fscanf, so we make gmp_sscanf identical to
|
|
Packit |
5c3484 |
gmp_fscanf.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Types:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
C99 says "ll" is for long long, and "L" is for long double floats.
|
|
Packit |
5c3484 |
Unfortunately in GMP 4.1.1 we documented the two as equivalent. This
|
|
Packit |
5c3484 |
doesn't affect us directly, since both are passed through to plain
|
|
Packit |
5c3484 |
scanf. It seems wisest not to try to enforce the C99 rule. This is
|
|
Packit |
5c3484 |
consistent with what we said before, though whether it actually
|
|
Packit |
5c3484 |
worked was always up to the C library.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Alternatives:
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Consideration was given to using separate code for gmp_fscanf and
|
|
Packit |
5c3484 |
gmp_sscanf. The sscanf case could zip across a string doing literal
|
|
Packit |
5c3484 |
matches or recognising digits in gmpscan, rather than making a
|
|
Packit |
5c3484 |
function call fun->get per character. The fscanf could use getc
|
|
Packit |
5c3484 |
rather than fgetc too, which might help those systems where getc is a
|
|
Packit |
5c3484 |
macro or otherwise inlined. But none of this scanning and converting
|
|
Packit |
5c3484 |
will be particularly fast, so the two are done together to keep it a
|
|
Packit |
5c3484 |
little simpler for now.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
Various multibyte string issues are not addressed, for a start C99
|
|
Packit |
5c3484 |
scanf says the format string is multibyte. Since we pass %c, %s and
|
|
Packit |
5c3484 |
%[ to the system scanf, they might do multibyte reads already, but
|
|
Packit |
5c3484 |
it's another matter whether or not that can be used, since our digit
|
|
Packit |
5c3484 |
and whitespace parsing is only unibyte. The plan is to quietly
|
|
Packit |
5c3484 |
ignore multibyte locales for now. This is not as bad as it sounds,
|
|
Packit |
5c3484 |
since GMP is presumably used mostly on numbers, which can be
|
|
Packit |
5c3484 |
perfectly adequately treated in plain ASCII.
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
*/
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
struct gmp_doscan_params_t {
|
|
Packit |
5c3484 |
int base;
|
|
Packit |
5c3484 |
int ignore;
|
|
Packit |
5c3484 |
char type;
|
|
Packit |
5c3484 |
int width;
|
|
Packit |
5c3484 |
};
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#define GET(c) \
|
|
Packit |
5c3484 |
do { \
|
|
Packit |
5c3484 |
ASSERT (chars <= width); \
|
|
Packit |
5c3484 |
chars++; \
|
|
Packit |
5c3484 |
if (chars > width) \
|
|
Packit |
5c3484 |
goto convert; \
|
|
Packit |
5c3484 |
(c) = (*funs->get) (data); \
|
|
Packit |
5c3484 |
} while (0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* store into "s", extending if necessary */
|
|
Packit |
5c3484 |
#define STORE(c) \
|
|
Packit |
5c3484 |
do { \
|
|
Packit |
5c3484 |
ASSERT (s_upto <= s_alloc); \
|
|
Packit |
5c3484 |
if (s_upto >= s_alloc) \
|
|
Packit |
5c3484 |
{ \
|
|
Packit |
5c3484 |
size_t s_alloc_new = s_alloc + S_ALLOC_STEP; \
|
|
Packit |
5c3484 |
s = __GMP_REALLOCATE_FUNC_TYPE (s, s_alloc, s_alloc_new, char); \
|
|
Packit |
5c3484 |
s_alloc = s_alloc_new; \
|
|
Packit |
5c3484 |
} \
|
|
Packit |
5c3484 |
s[s_upto++] = c; \
|
|
Packit |
5c3484 |
} while (0)
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
#define S_ALLOC_STEP 512
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
static int
|
|
Packit |
5c3484 |
gmpscan (const struct gmp_doscan_funs_t *funs, void *data,
|
|
Packit |
5c3484 |
const struct gmp_doscan_params_t *p, void *dst)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int chars, c, base, first, width, seen_point, seen_digit, hexfloat;
|
|
Packit |
5c3484 |
size_t s_upto, s_alloc, hexexp;
|
|
Packit |
5c3484 |
char *s;
|
|
Packit |
5c3484 |
int invalid = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf ("gmpscan\n"));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ASSERT (p->type == 'F' || p->type == 'Q' || p->type == 'Z');
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
c = (*funs->get) (data);
|
|
Packit |
5c3484 |
if (c == EOF)
|
|
Packit |
5c3484 |
return -2;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
chars = 1;
|
|
Packit |
5c3484 |
first = 1;
|
|
Packit |
5c3484 |
seen_point = 0;
|
|
Packit |
5c3484 |
width = (p->width == 0 ? INT_MAX-1 : p->width);
|
|
Packit |
5c3484 |
base = p->base;
|
|
Packit |
5c3484 |
s_alloc = S_ALLOC_STEP;
|
|
Packit |
5c3484 |
s = __GMP_ALLOCATE_FUNC_TYPE (s_alloc, char);
|
|
Packit |
5c3484 |
s_upto = 0;
|
|
Packit |
5c3484 |
hexfloat = 0;
|
|
Packit |
5c3484 |
hexexp = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
another:
|
|
Packit |
5c3484 |
seen_digit = 0;
|
|
Packit |
5c3484 |
if (c == '-')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
goto get_for_sign;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (c == '+')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* don't store '+', it's not accepted by mpz_set_str etc */
|
|
Packit |
5c3484 |
get_for_sign:
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (base == 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
base = 10; /* decimal if no base indicator */
|
|
Packit |
5c3484 |
if (c == '0')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
seen_digit = 1; /* 0 alone is a valid number */
|
|
Packit |
5c3484 |
if (p->type != 'F')
|
|
Packit |
5c3484 |
base = 8; /* leading 0 is octal, for non-floats */
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
if (c == 'x' || c == 'X')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
base = 16;
|
|
Packit |
5c3484 |
seen_digit = 0; /* must have digits after an 0x */
|
|
Packit |
5c3484 |
if (p->type == 'F') /* don't pass 'x' to mpf_set_str_point */
|
|
Packit |
5c3484 |
hexfloat = 1;
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
digits:
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (base == 16)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (! isxdigit (c))
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (! isdigit (c))
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
if (base == 8 && (c == '8' || c == '9'))
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
seen_digit = 1;
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (first)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* decimal point */
|
|
Packit |
5c3484 |
if (p->type == 'F' && ! seen_point)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* For a multi-character decimal point, if the first character is
|
|
Packit |
5c3484 |
present then all of it must be, otherwise the input is
|
|
Packit |
5c3484 |
considered invalid. */
|
|
Packit |
5c3484 |
const char *point = GMP_DECIMAL_POINT;
|
|
Packit |
5c3484 |
int pc = (unsigned char) *point++;
|
|
Packit |
5c3484 |
if (c == pc)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
pc = (unsigned char) *point++;
|
|
Packit |
5c3484 |
if (pc == '\0')
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
if (c != pc)
|
|
Packit |
5c3484 |
goto set_invalid;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
seen_point = 1;
|
|
Packit |
5c3484 |
goto digits;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* exponent */
|
|
Packit |
5c3484 |
if (p->type == 'F')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
if (hexfloat && (c == 'p' || c == 'P'))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
hexexp = s_upto; /* exponent location */
|
|
Packit |
5c3484 |
base = 10; /* exponent in decimal */
|
|
Packit |
5c3484 |
goto exponent;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else if (! hexfloat && (c == 'e' || c == 'E'))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
exponent:
|
|
Packit |
5c3484 |
/* must have at least one digit in the mantissa, just an exponent
|
|
Packit |
5c3484 |
is not good enough */
|
|
Packit |
5c3484 |
if (! seen_digit)
|
|
Packit |
5c3484 |
goto set_invalid;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
do_second:
|
|
Packit |
5c3484 |
first = 0;
|
|
Packit |
5c3484 |
STORE (c);
|
|
Packit |
5c3484 |
GET (c);
|
|
Packit |
5c3484 |
goto another;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* denominator */
|
|
Packit |
5c3484 |
if (p->type == 'Q' && c == '/')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* must have at least one digit in the numerator */
|
|
Packit |
5c3484 |
if (! seen_digit)
|
|
Packit |
5c3484 |
goto set_invalid;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* now look for at least one digit in the denominator */
|
|
Packit |
5c3484 |
seen_digit = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* allow the base to be redetermined for "%i" */
|
|
Packit |
5c3484 |
base = p->base;
|
|
Packit |
5c3484 |
goto do_second;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
convert:
|
|
Packit |
5c3484 |
if (! seen_digit)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
set_invalid:
|
|
Packit |
5c3484 |
invalid = 1;
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (! p->ignore)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
STORE ('\0');
|
|
Packit |
5c3484 |
TRACE (printf (" convert \"%s\"\n", s));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* We ought to have parsed out a valid string above, so just test
|
|
Packit |
5c3484 |
mpz_set_str etc with an ASSERT. */
|
|
Packit |
5c3484 |
switch (p->type) {
|
|
Packit |
5c3484 |
case 'F':
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
mpf_ptr f = (mpf_ptr) dst;
|
|
Packit |
5c3484 |
if (hexexp != 0)
|
|
Packit |
5c3484 |
s[hexexp] = '\0';
|
|
Packit |
5c3484 |
ASSERT_NOCARRY (mpf_set_str (f, s, hexfloat ? 16 : 10));
|
|
Packit |
5c3484 |
if (hexexp != 0)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
char *dummy;
|
|
Packit |
5c3484 |
long exp;
|
|
Packit |
5c3484 |
exp = strtol (s + hexexp + 1, &dummy, 10);
|
|
Packit |
5c3484 |
if (exp >= 0)
|
|
Packit |
5c3484 |
mpf_mul_2exp (f, f, (unsigned long) exp);
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
mpf_div_2exp (f, f, - (unsigned long) exp);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'Q':
|
|
Packit |
5c3484 |
ASSERT_NOCARRY (mpq_set_str ((mpq_ptr) dst, s, p->base));
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
case 'Z':
|
|
Packit |
5c3484 |
ASSERT_NOCARRY (mpz_set_str ((mpz_ptr) dst, s, p->base));
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
ASSERT (0);
|
|
Packit |
5c3484 |
/*FALLTHRU*/
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
done:
|
|
Packit |
5c3484 |
ASSERT (chars <= width+1);
|
|
Packit |
5c3484 |
if (chars != width+1)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
(*funs->unget) (c, data);
|
|
Packit |
5c3484 |
TRACE (printf (" ungetc %d, to give %d chars\n", c, chars-1));
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
chars--;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
(*__gmp_free_func) (s, s_alloc);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (invalid)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
TRACE (printf (" invalid\n"));
|
|
Packit |
5c3484 |
return -1;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf (" return %d chars (cf width %d)\n", chars, width));
|
|
Packit |
5c3484 |
return chars;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Read and discard whitespace, if any. Return number of chars skipped.
|
|
Packit |
5c3484 |
Whitespace skipping never provokes the EOF return from __gmp_doscan, so
|
|
Packit |
5c3484 |
it's not necessary to watch for EOF from funs->get, */
|
|
Packit |
5c3484 |
static int
|
|
Packit |
5c3484 |
skip_white (const struct gmp_doscan_funs_t *funs, void *data)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int c;
|
|
Packit |
5c3484 |
int ret = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
do
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
c = (funs->get) (data);
|
|
Packit |
5c3484 |
ret++;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
while (isspace (c));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
(funs->unget) (c, data);
|
|
Packit |
5c3484 |
ret--;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf (" skip white %d\n", ret));
|
|
Packit |
5c3484 |
return ret;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
int
|
|
Packit |
5c3484 |
__gmp_doscan (const struct gmp_doscan_funs_t *funs, void *data,
|
|
Packit |
5c3484 |
const char *orig_fmt, va_list orig_ap)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
struct gmp_doscan_params_t param;
|
|
Packit |
5c3484 |
va_list ap;
|
|
Packit |
5c3484 |
char *alloc_fmt;
|
|
Packit |
5c3484 |
const char *fmt, *this_fmt, *end_fmt;
|
|
Packit |
5c3484 |
size_t orig_fmt_len, alloc_fmt_size, len;
|
|
Packit |
5c3484 |
int new_fields, new_chars;
|
|
Packit |
5c3484 |
char fchar;
|
|
Packit |
5c3484 |
int fields = 0;
|
|
Packit |
5c3484 |
int chars = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf ("__gmp_doscan \"%s\"\n", orig_fmt);
|
|
Packit |
5c3484 |
if (funs->scan == (gmp_doscan_scan_t) sscanf)
|
|
Packit |
5c3484 |
printf (" s=\"%s\"\n", * (const char **) data));
|
|
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
|
|
Packit |
5c3484 |
callers to make a copy if they care, 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 |
/* Parts of the format string are going to be copied so that a " %n" can
|
|
Packit |
5c3484 |
be appended. alloc_fmt is some space for that. orig_fmt_len+4 will be
|
|
Packit |
5c3484 |
needed if fmt consists of a single "%" specifier, but otherwise is an
|
|
Packit |
5c3484 |
overestimate. We're not going to be very fast here, so use
|
|
Packit |
5c3484 |
__gmp_allocate_func rather than TMP_ALLOC. */
|
|
Packit |
5c3484 |
orig_fmt_len = strlen (orig_fmt);
|
|
Packit |
5c3484 |
alloc_fmt_size = orig_fmt_len + 4;
|
|
Packit |
5c3484 |
alloc_fmt = __GMP_ALLOCATE_FUNC_TYPE (alloc_fmt_size, char);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
fmt = orig_fmt;
|
|
Packit |
5c3484 |
end_fmt = orig_fmt + orig_fmt_len;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
next:
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (fchar == '\0')
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (isspace (fchar))
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
chars += skip_white (funs, data);
|
|
Packit |
5c3484 |
continue;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (fchar != '%')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
int c;
|
|
Packit |
5c3484 |
literal:
|
|
Packit |
5c3484 |
c = (funs->get) (data);
|
|
Packit |
5c3484 |
if (c != fchar)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
(funs->unget) (c, data);
|
|
Packit |
5c3484 |
if (c == EOF)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
eof_no_match:
|
|
Packit |
5c3484 |
if (fields == 0)
|
|
Packit |
5c3484 |
fields = EOF;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
chars++;
|
|
Packit |
5c3484 |
continue;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
param.type = '\0';
|
|
Packit |
5c3484 |
param.base = 0; /* for e,f,g,i */
|
|
Packit |
5c3484 |
param.ignore = 0;
|
|
Packit |
5c3484 |
param.width = 0;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
this_fmt = fmt-1;
|
|
Packit |
5c3484 |
TRACE (printf (" this_fmt \"%s\"\n", this_fmt));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
ASSERT (fmt <= end_fmt);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
switch (fchar) {
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '\0': /* unterminated % sequence */
|
|
Packit |
5c3484 |
ASSERT (0);
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '%': /* literal % */
|
|
Packit |
5c3484 |
goto literal;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '[': /* character range */
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
if (fchar == '^')
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
/* ']' allowed as the first char (possibly after '^') */
|
|
Packit |
5c3484 |
if (fchar == ']')
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
for (;;)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
ASSERT (fmt <= end_fmt);
|
|
Packit |
5c3484 |
if (fchar == '\0')
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
/* unterminated % sequence */
|
|
Packit |
5c3484 |
ASSERT (0);
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
if (fchar == ']')
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
/*FALLTHRU*/
|
|
Packit |
5c3484 |
case 'c': /* characters */
|
|
Packit |
5c3484 |
case 's': /* string of non-whitespace */
|
|
Packit |
5c3484 |
case 'p': /* pointer */
|
|
Packit |
5c3484 |
libc_type:
|
|
Packit |
5c3484 |
len = fmt - this_fmt;
|
|
Packit |
5c3484 |
memcpy (alloc_fmt, this_fmt, len);
|
|
Packit |
5c3484 |
alloc_fmt[len++] = '%';
|
|
Packit |
5c3484 |
alloc_fmt[len++] = 'n';
|
|
Packit |
5c3484 |
alloc_fmt[len] = '\0';
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
TRACE (printf (" scan \"%s\"\n", alloc_fmt);
|
|
Packit |
5c3484 |
if (funs->scan == (gmp_doscan_scan_t) sscanf)
|
|
Packit |
5c3484 |
printf (" s=\"%s\"\n", * (const char **) data));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
new_chars = -1;
|
|
Packit |
5c3484 |
if (param.ignore)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
new_fields = (*funs->scan) (data, alloc_fmt, &new_chars, NULL);
|
|
Packit |
5c3484 |
ASSERT (new_fields == 0 || new_fields == EOF);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
else
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
void *arg = va_arg (ap, void *);
|
|
Packit |
5c3484 |
new_fields = (*funs->scan) (data, alloc_fmt, arg, &new_chars);
|
|
Packit |
5c3484 |
ASSERT (new_fields==0 || new_fields==1 || new_fields==EOF);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (new_fields == 0)
|
|
Packit |
5c3484 |
goto done; /* invalid input */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (new_fields == 1)
|
|
Packit |
5c3484 |
ASSERT (new_chars != -1);
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
TRACE (printf (" new_fields %d new_chars %d\n",
|
|
Packit |
5c3484 |
new_fields, new_chars));
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
if (new_fields == -1)
|
|
Packit |
5c3484 |
goto eof_no_match; /* EOF before anything matched */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
/* Under param.ignore, when new_fields==0 we don't know if
|
|
Packit |
5c3484 |
it's a successful match or an invalid field. new_chars
|
|
Packit |
5c3484 |
won't have been assigned if it was an invalid field. */
|
|
Packit |
5c3484 |
if (new_chars == -1)
|
|
Packit |
5c3484 |
goto done; /* invalid input */
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
chars += new_chars;
|
|
Packit |
5c3484 |
(*funs->step) (data, new_chars);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
increment_fields:
|
|
Packit |
5c3484 |
if (! param.ignore)
|
|
Packit |
5c3484 |
fields++;
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'd': /* decimal */
|
|
Packit |
5c3484 |
case 'u': /* decimal */
|
|
Packit |
5c3484 |
param.base = 10;
|
|
Packit |
5c3484 |
goto numeric;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'e': /* float */
|
|
Packit |
5c3484 |
case 'E': /* float */
|
|
Packit |
5c3484 |
case 'f': /* float */
|
|
Packit |
5c3484 |
case 'g': /* float */
|
|
Packit |
5c3484 |
case 'G': /* float */
|
|
Packit |
5c3484 |
case 'i': /* integer with base marker */
|
|
Packit |
5c3484 |
numeric:
|
|
Packit |
5c3484 |
if (param.type != 'F' && param.type != 'Q' && param.type != 'Z')
|
|
Packit |
5c3484 |
goto libc_type;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
chars += skip_white (funs, data);
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
new_chars = gmpscan (funs, data, ¶m,
|
|
Packit |
5c3484 |
param.ignore ? NULL : va_arg (ap, void*));
|
|
Packit |
5c3484 |
if (new_chars == -2)
|
|
Packit |
5c3484 |
goto eof_no_match;
|
|
Packit |
5c3484 |
if (new_chars == -1)
|
|
Packit |
5c3484 |
goto done;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
ASSERT (new_chars >= 0);
|
|
Packit |
5c3484 |
chars += new_chars;
|
|
Packit |
5c3484 |
goto increment_fields;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'a': /* glibc allocate string */
|
|
Packit |
5c3484 |
case '\'': /* glibc digit groupings */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'F': /* mpf_t */
|
|
Packit |
5c3484 |
case 'j': /* intmax_t */
|
|
Packit |
5c3484 |
case 'L': /* long long */
|
|
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 |
param.type = fchar;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'h': /* short or char */
|
|
Packit |
5c3484 |
if (param.type != 'h')
|
|
Packit |
5c3484 |
goto set_type;
|
|
Packit |
5c3484 |
param.type = 'H'; /* internal code for "hh" */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
goto numeric;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'l': /* long, long long, double or long double */
|
|
Packit |
5c3484 |
if (param.type != 'l')
|
|
Packit |
5c3484 |
goto set_type;
|
|
Packit |
5c3484 |
param.type = 'L'; /* "ll" means "L" */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'n':
|
|
Packit |
5c3484 |
if (! param.ignore)
|
|
Packit |
5c3484 |
{
|
|
Packit |
5c3484 |
void *p;
|
|
Packit |
5c3484 |
p = va_arg (ap, void *);
|
|
Packit |
5c3484 |
TRACE (printf (" store %%n to %p\n", p));
|
|
Packit |
5c3484 |
switch (param.type) {
|
|
Packit |
5c3484 |
case '\0': * (int *) p = chars; break;
|
|
Packit |
5c3484 |
case 'F': mpf_set_si ((mpf_ptr) p, (long) chars); break;
|
|
Packit |
5c3484 |
case 'H': * (char *) p = chars; break;
|
|
Packit |
5c3484 |
case 'h': * (short *) p = chars; break;
|
|
Packit |
5c3484 |
#if HAVE_INTMAX_T
|
|
Packit |
5c3484 |
case 'j': * (intmax_t *) p = chars; break;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 'j': ASSERT_FAIL (intmax_t not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case 'l': * (long *) p = chars; 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 = chars; break;
|
|
Packit |
5c3484 |
#else
|
|
Packit |
5c3484 |
case 'L': ASSERT_FAIL (long long not available); break;
|
|
Packit |
5c3484 |
#endif
|
|
Packit |
5c3484 |
case 'Q': mpq_set_si ((mpq_ptr) p, (long) chars, 1L); break;
|
|
Packit |
5c3484 |
#if HAVE_PTRDIFF_T
|
|
Packit |
5c3484 |
case 't': * (ptrdiff_t *) p = chars; 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 = chars; break;
|
|
Packit |
5c3484 |
case 'Z': mpz_set_si ((mpz_ptr) p, (long) chars); break;
|
|
Packit |
5c3484 |
default: ASSERT (0); break;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'o':
|
|
Packit |
5c3484 |
param.base = 8;
|
|
Packit |
5c3484 |
goto numeric;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case 'x':
|
|
Packit |
5c3484 |
case 'X':
|
|
Packit |
5c3484 |
param.base = 16;
|
|
Packit |
5c3484 |
goto numeric;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '0': case '1': case '2': case '3': case '4':
|
|
Packit |
5c3484 |
case '5': case '6': case '7': case '8': case '9':
|
|
Packit |
5c3484 |
param.width = 0;
|
|
Packit |
5c3484 |
do {
|
|
Packit |
5c3484 |
param.width = param.width * 10 + (fchar-'0');
|
|
Packit |
5c3484 |
fchar = *fmt++;
|
|
Packit |
5c3484 |
} while (isdigit (fchar));
|
|
Packit |
5c3484 |
fmt--; /* unget the non-digit */
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
case '*':
|
|
Packit |
5c3484 |
param.ignore = 1;
|
|
Packit |
5c3484 |
break;
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
default:
|
|
Packit |
5c3484 |
/* something invalid in a % sequence */
|
|
Packit |
5c3484 |
ASSERT (0);
|
|
Packit |
5c3484 |
goto next;
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
}
|
|
Packit |
5c3484 |
|
|
Packit |
5c3484 |
done:
|
|
Packit |
5c3484 |
(*__gmp_free_func) (alloc_fmt, alloc_fmt_size);
|
|
Packit |
5c3484 |
return fields;
|
|
Packit |
5c3484 |
}
|