Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Unified Diff: gcc/gmp/scanf/doscan.c

Issue 3050029: [gcc] GCC 4.5.0=>4.5.1 (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/nacl-toolchain.git
Patch Set: Created 10 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « gcc/gmp/randsdui.c ('k') | gcc/gmp/scanf/fscanf.c » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, &param,
- 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;
-}
« no previous file with comments | « gcc/gmp/randsdui.c ('k') | gcc/gmp/scanf/fscanf.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698