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