From 11da511c784eca003deb90c23570f0873954e0de Mon Sep 17 00:00:00 2001 From: Duncan Wilkie Date: Sat, 18 Nov 2023 06:11:09 -0600 Subject: Initial commit. --- gmp-6.3.0/tests/misc/t-scanf.c | 1615 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1615 insertions(+) create mode 100644 gmp-6.3.0/tests/misc/t-scanf.c (limited to 'gmp-6.3.0/tests/misc/t-scanf.c') diff --git a/gmp-6.3.0/tests/misc/t-scanf.c b/gmp-6.3.0/tests/misc/t-scanf.c new file mode 100644 index 0000000..8b82f1e --- /dev/null +++ b/gmp-6.3.0/tests/misc/t-scanf.c @@ -0,0 +1,1615 @@ +/* Test gmp_scanf and related functions. + +Copyright 2001-2004 Free Software Foundation, Inc. + +This file is part of the GNU MP Library test suite. + +The GNU MP Library test suite is free software; you can redistribute it +and/or modify it under the terms of the GNU 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 test suite 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 General +Public License for more details. + +You should have received a copy of the GNU General Public License along with +the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ + + +/* Usage: t-scanf [-s] + + -s Check the data against the system scanf, where possible. This is + only an option since we don't want to fail if the system scanf is + faulty or strange. + + There's some fairly unattractive repetition between check_z, check_q and + check_f, but enough differences to make a common loop or a set of macros + seem like too much trouble. */ + +#include "config.h" /* needed for the HAVE_, could also move gmp incls */ + +#include + +#include /* for ptrdiff_t */ +#include +#include +#include + +#if HAVE_INTTYPES_H +# include /* for intmax_t */ +#endif +#if HAVE_STDINT_H +# include +#endif + +#if HAVE_UNISTD_H +#include /* for unlink */ +#endif + +#include "gmp-impl.h" +#include "tests.h" + + +#define TEMPFILE "t-scanf.tmp" + +int option_libc_scanf = 0; + +typedef int (*fun_t) (const char *, const char *, void *, void *); + + +/* This problem was seen on powerpc7450-apple-darwin7.0.0, sscanf returns 0 + where it should return EOF. A workaround in gmp_sscanf would be a bit + tedious, and since this is a rather obvious libc bug, quite likely + affecting other programs, we'll just suppress affected tests for now. */ +int +test_sscanf_eof_ok (void) +{ + static int result = -1; + + if (result == -1) + { + int x; + if (sscanf ("", "%d", &x) == EOF) + { + result = 1; + } + else + { + printf ("Warning, sscanf(\"\",\"%%d\",&x) doesn't return EOF.\n"); + printf ("This affects gmp_sscanf, tests involving it will be suppressed.\n"); + printf ("You should try to get a fix for your libc.\n"); + result = 0; + } + } + return result; +} + + +/* Convert fmt from a GMP scanf format string to an equivalent for a plain + libc scanf, for example "%Zd" becomes "%ld". Return 1 if this succeeds, + 0 if it cannot (or should not) be done. */ +int +libc_scanf_convert (char *fmt) +{ + char *p = fmt; + + if (! option_libc_scanf) + return 0; + + for ( ; *fmt != '\0'; fmt++) + { + switch (*fmt) { + case 'F': + case 'Q': + case 'Z': + /* transmute */ + *p++ = 'l'; + break; + default: + *p++ = *fmt; + break; + } + } + *p = '\0'; + return 1; +} + + +long got_ftell; +int fromstring_next_c; + +/* Call gmp_fscanf, reading the "input" string data provided. */ +int +fromstring_gmp_fscanf (const char *input, const char *fmt, ...) +{ + va_list ap; + FILE *fp; + int ret; + va_start (ap, fmt); + + fp = fopen (TEMPFILE, "w+"); + ASSERT_ALWAYS (fp != NULL); + ASSERT_ALWAYS (fputs (input, fp) != EOF); + ASSERT_ALWAYS (fflush (fp) == 0); + rewind (fp); + + ret = gmp_vfscanf (fp, fmt, ap); + got_ftell = ftell (fp); + ASSERT_ALWAYS (got_ftell != -1L); + + fromstring_next_c = getc (fp); + + ASSERT_ALWAYS (fclose (fp) == 0); + va_end (ap); + return ret; +} + + +int +fun_gmp_sscanf (const char *input, const char *fmt, void *a1, void *a2) +{ + if (a2 == NULL) + return gmp_sscanf (input, fmt, a1); + else + return gmp_sscanf (input, fmt, a1, a2); +} + +int +fun_gmp_fscanf (const char *input, const char *fmt, void *a1, void *a2) +{ + if (a2 == NULL) + return fromstring_gmp_fscanf (input, fmt, a1); + else + return fromstring_gmp_fscanf (input, fmt, a1, a2); +} + + +int +fun_fscanf (const char *input, const char *fmt, void *a1, void *a2) +{ + FILE *fp; + int ret; + + fp = fopen (TEMPFILE, "w+"); + ASSERT_ALWAYS (fp != NULL); + ASSERT_ALWAYS (fputs (input, fp) != EOF); + ASSERT_ALWAYS (fflush (fp) == 0); + rewind (fp); + + if (a2 == NULL) + ret = fscanf (fp, fmt, a1); + else + ret = fscanf (fp, fmt, a1, a2); + + got_ftell = ftell (fp); + ASSERT_ALWAYS (got_ftell != -1L); + + fromstring_next_c = getc (fp); + + ASSERT_ALWAYS (fclose (fp) == 0); + return ret; +} + + +/* On various old systems, for instance HP-UX 9, the C library sscanf needs + to be able to write into the input string. Ensure that this is possible, + when gcc is putting the test data into a read-only section. + + Actually we ought to only need this under SSCANF_WRITABLE_INPUT from + configure, but it's just as easy to do it unconditionally, and in any + case this code is only executed under the -s option. */ + +int +fun_sscanf (const char *input, const char *fmt, void *a1, void *a2) +{ + char *input_writable; + size_t size; + int ret; + + size = strlen (input) + 1; + input_writable = (char *) (*__gmp_allocate_func) (size); + memcpy (input_writable, input, size); + + if (a2 == NULL) + ret = sscanf (input_writable, fmt, a1); + else + ret = sscanf (input_writable, fmt, a1, a2); + + (*__gmp_free_func) (input_writable, size); + return ret; +} + + +/* whether the format string consists entirely of ignored fields */ +int +fmt_allignore (const char *fmt) +{ + int saw_star = 1; + for ( ; *fmt != '\0'; fmt++) + { + switch (*fmt) { + case '%': + if (! saw_star) + return 0; + saw_star = 0; + break; + case '*': + saw_star = 1; + break; + } + } + return 1; +} + +void +check_z (void) +{ + static const struct { + const char *fmt; + const char *input; + const char *want; + int want_ret; + long want_ftell; + int want_upto; + int not_glibc; + + } data[] = { + + { "%Zd", "0", "0", 1, -1, -1 }, + { "%Zd", "1", "1", 1, -1, -1 }, + { "%Zd", "123", "123", 1, -1, -1 }, + { "%Zd", "+0", "0", 1, -1, -1 }, + { "%Zd", "+1", "1", 1, -1, -1 }, + { "%Zd", "+123", "123", 1, -1, -1 }, + { "%Zd", "-0", "0", 1, -1, -1 }, + { "%Zd", "-1", "-1", 1, -1, -1 }, + { "%Zd", "-123", "-123", 1, -1, -1 }, + + { "%Zo", "0", "0", 1, -1, -1 }, + { "%Zo", "173", "123", 1, -1, -1 }, + { "%Zo", "+0", "0", 1, -1, -1 }, + { "%Zo", "+173", "123", 1, -1, -1 }, + { "%Zo", "-0", "0", 1, -1, -1 }, + { "%Zo", "-173", "-123", 1, -1, -1 }, + + { "%Zx", "0", "0", 1, -1, -1 }, + { "%Zx", "7b", "123", 1, -1, -1 }, + { "%Zx", "7b", "123", 1, -1, -1 }, + { "%Zx", "+0", "0", 1, -1, -1 }, + { "%Zx", "+7b", "123", 1, -1, -1 }, + { "%Zx", "+7b", "123", 1, -1, -1 }, + { "%Zx", "-0", "-0", 1, -1, -1 }, + { "%Zx", "-7b", "-123", 1, -1, -1 }, + { "%Zx", "-7b", "-123", 1, -1, -1 }, + { "%ZX", "0", "0", 1, -1, -1 }, + { "%ZX", "7b", "123", 1, -1, -1 }, + { "%ZX", "7b", "123", 1, -1, -1 }, + { "%ZX", "+0", "0", 1, -1, -1 }, + { "%ZX", "+7b", "123", 1, -1, -1 }, + { "%ZX", "+7b", "123", 1, -1, -1 }, + { "%ZX", "-0", "-0", 1, -1, -1 }, + { "%ZX", "-7b", "-123", 1, -1, -1 }, + { "%ZX", "-7b", "-123", 1, -1, -1 }, + { "%Zx", "0", "0", 1, -1, -1 }, + { "%Zx", "7B", "123", 1, -1, -1 }, + { "%Zx", "7B", "123", 1, -1, -1 }, + { "%Zx", "+0", "0", 1, -1, -1 }, + { "%Zx", "+7B", "123", 1, -1, -1 }, + { "%Zx", "+7B", "123", 1, -1, -1 }, + { "%Zx", "-0", "-0", 1, -1, -1 }, + { "%Zx", "-7B", "-123", 1, -1, -1 }, + { "%Zx", "-7B", "-123", 1, -1, -1 }, + { "%ZX", "0", "0", 1, -1, -1 }, + { "%ZX", "7B", "123", 1, -1, -1 }, + { "%ZX", "7B", "123", 1, -1, -1 }, + { "%ZX", "+0", "0", 1, -1, -1 }, + { "%ZX", "+7B", "123", 1, -1, -1 }, + { "%ZX", "+7B", "123", 1, -1, -1 }, + { "%ZX", "-0", "-0", 1, -1, -1 }, + { "%ZX", "-7B", "-123", 1, -1, -1 }, + { "%ZX", "-7B", "-123", 1, -1, -1 }, + + { "%Zi", "0", "0", 1, -1, -1 }, + { "%Zi", "1", "1", 1, -1, -1 }, + { "%Zi", "123", "123", 1, -1, -1 }, + { "%Zi", "+0", "0", 1, -1, -1 }, + { "%Zi", "+1", "1", 1, -1, -1 }, + { "%Zi", "+123", "123", 1, -1, -1 }, + { "%Zi", "-0", "0", 1, -1, -1 }, + { "%Zi", "-1", "-1", 1, -1, -1 }, + { "%Zi", "-123", "-123", 1, -1, -1 }, + + { "%Zi", "00", "0", 1, -1, -1 }, + { "%Zi", "0173", "123", 1, -1, -1 }, + { "%Zi", "+00", "0", 1, -1, -1 }, + { "%Zi", "+0173", "123", 1, -1, -1 }, + { "%Zi", "-00", "0", 1, -1, -1 }, + { "%Zi", "-0173", "-123", 1, -1, -1 }, + + { "%Zi", "0x0", "0", 1, -1, -1 }, + { "%Zi", "0x7b", "123", 1, -1, -1 }, + { "%Zi", "0x7b", "123", 1, -1, -1 }, + { "%Zi", "+0x0", "0", 1, -1, -1 }, + { "%Zi", "+0x7b", "123", 1, -1, -1 }, + { "%Zi", "+0x7b", "123", 1, -1, -1 }, + { "%Zi", "-0x0", "-0", 1, -1, -1 }, + { "%Zi", "-0x7b", "-123", 1, -1, -1 }, + { "%Zi", "-0x7b", "-123", 1, -1, -1 }, + { "%Zi", "0X0", "0", 1, -1, -1 }, + { "%Zi", "0X7b", "123", 1, -1, -1 }, + { "%Zi", "0X7b", "123", 1, -1, -1 }, + { "%Zi", "+0X0", "0", 1, -1, -1 }, + { "%Zi", "+0X7b", "123", 1, -1, -1 }, + { "%Zi", "+0X7b", "123", 1, -1, -1 }, + { "%Zi", "-0X0", "-0", 1, -1, -1 }, + { "%Zi", "-0X7b", "-123", 1, -1, -1 }, + { "%Zi", "-0X7b", "-123", 1, -1, -1 }, + { "%Zi", "0x0", "0", 1, -1, -1 }, + { "%Zi", "0x7B", "123", 1, -1, -1 }, + { "%Zi", "0x7B", "123", 1, -1, -1 }, + { "%Zi", "+0x0", "0", 1, -1, -1 }, + { "%Zi", "+0x7B", "123", 1, -1, -1 }, + { "%Zi", "+0x7B", "123", 1, -1, -1 }, + { "%Zi", "-0x0", "-0", 1, -1, -1 }, + { "%Zi", "-0x7B", "-123", 1, -1, -1 }, + { "%Zi", "-0x7B", "-123", 1, -1, -1 }, + { "%Zi", "0X0", "0", 1, -1, -1 }, + { "%Zi", "0X7B", "123", 1, -1, -1 }, + { "%Zi", "0X7B", "123", 1, -1, -1 }, + { "%Zi", "+0X0", "0", 1, -1, -1 }, + { "%Zi", "+0X7B", "123", 1, -1, -1 }, + { "%Zi", "+0X7B", "123", 1, -1, -1 }, + { "%Zi", "-0X0", "-0", 1, -1, -1 }, + { "%Zi", "-0X7B", "-123", 1, -1, -1 }, + { "%Zi", "-0X7B", "-123", 1, -1, -1 }, + + { "%Zd", " 0", "0", 1, -1, -1 }, + { "%Zd", " 0", "0", 1, -1, -1 }, + { "%Zd", " 0", "0", 1, -1, -1 }, + { "%Zd", "\t0", "0", 1, -1, -1 }, + { "%Zd", "\t\t0", "0", 1, -1, -1 }, + + { "hello%Zd", "hello0", "0", 1, -1, -1 }, + { "hello%Zd", "hello 0", "0", 1, -1, -1 }, + { "hello%Zd", "hello \t0", "0", 1, -1, -1 }, + { "hello%Zdworld", "hello 0world", "0", 1, -1, -1 }, + + { "hello%*Zd", "hello0", "-999", 0, -1, -1 }, + { "hello%*Zd", "hello 0", "-999", 0, -1, -1 }, + { "hello%*Zd", "hello \t0", "-999", 0, -1, -1 }, + { "hello%*Zdworld", "hello 0world", "-999", 0, -1, -1 }, + + { "%Zd", "", "-999", -1, -1, -555 }, + { "%Zd", " ", "-999", -1, -1, -555 }, + { " %Zd", "", "-999", -1, -1, -555 }, + { "xyz%Zd", "", "-999", -1, -1, -555 }, + + { "%*Zd", "", "-999", -1, -1, -555 }, + { " %*Zd", "", "-999", -1, -1, -555 }, + { "xyz%*Zd", "", "-999", -1, -1, -555 }, + + { "%Zd", "xyz", "0", 0, 0, -555 }, + + /* match something, but invalid */ + { "%Zd", "-", "-999", 0, 1, -555 }, + { "%Zd", "+", "-999", 0, 1, -555 }, + { "xyz%Zd", "xyz-", "-999", 0, 4, -555 }, + { "xyz%Zd", "xyz+", "-999", 0, 4, -555 }, + { "%Zi", "0x", "-999", 0, 2, -555 }, + { "%Zi", "0X", "-999", 0, 2, -555 }, + { "%Zi", "0x-", "-999", 0, 2, -555 }, + { "%Zi", "0X+", "-999", 0, 2, -555 }, + { "%Zi", "-0x", "-999", 0, 3, -555 }, + { "%Zi", "-0X", "-999", 0, 3, -555 }, + { "%Zi", "+0x", "-999", 0, 3, -555 }, + { "%Zi", "+0X", "-999", 0, 3, -555 }, + + { "%1Zi", "1234", "1", 1, 1, 1 }, + { "%2Zi", "1234", "12", 1, 2, 2 }, + { "%3Zi", "1234", "123", 1, 3, 3 }, + { "%4Zi", "1234", "1234", 1, 4, 4 }, + { "%5Zi", "1234", "1234", 1, 4, 4 }, + { "%6Zi", "1234", "1234", 1, 4, 4 }, + + { "%1Zi", "01234", "0", 1, 1, 1 }, + { "%2Zi", "01234", "01", 1, 2, 2 }, + { "%3Zi", "01234", "012", 1, 3, 3 }, + { "%4Zi", "01234", "0123", 1, 4, 4 }, + { "%5Zi", "01234", "01234", 1, 5, 5 }, + { "%6Zi", "01234", "01234", 1, 5, 5 }, + { "%7Zi", "01234", "01234", 1, 5, 5 }, + + { "%1Zi", "0x1234", "0", 1, 1, 1 }, + { "%2Zi", "0x1234", "-999", 0, 2, -555 }, + { "%3Zi", "0x1234", "0x1", 1, 3, 3 }, + { "%4Zi", "0x1234", "0x12", 1, 4, 4 }, + { "%5Zi", "0x1234", "0x123", 1, 5, 5 }, + { "%6Zi", "0x1234", "0x1234", 1, 6, 6 }, + { "%7Zi", "0x1234", "0x1234", 1, 6, 6 }, + { "%8Zi", "0x1234", "0x1234", 1, 6, 6 }, + + { "%%xyz%Zd", "%xyz123", "123", 1, -1, -1 }, + { "12%%34%Zd", "12%34567", "567", 1, -1, -1 }, + { "%%%%%Zd", "%%123", "123", 1, -1, -1 }, + + /* various subtle EOF cases */ + { "x", "", "-999", EOF, 0, -555 }, + { " x", "", "-999", EOF, 0, -555 }, + { "xyz", "", "-999", EOF, 0, -555 }, + { " ", "", "-999", 0, 0, 0 }, + { " ", " ", "-999", 0, 1, 1 }, + { "%*Zd%Zd", "", "-999", EOF, 0, -555 }, + { "%*Zd%Zd", "123", "-999", EOF, 3, -555 }, + { "x", "x", "-999", 0, 1, 1 }, + { "xyz", "x", "-999", EOF, 1, -555 }, + { "xyz", "xy", "-999", EOF, 2, -555 }, + { "xyz", "xyz", "-999", 0, 3, 3 }, + { "%Zn", "", "0", 0, 0, 0 }, + { " %Zn", "", "0", 0, 0, 0 }, + { " x%Zn", "", "-999", EOF, 0, -555 }, + { "xyz%Zn", "", "-999", EOF, 0, -555 }, + { " x%Zn", "", "-999", EOF, 0, -555 }, + { " %Zn x", " ", "-999", EOF, 1, -555 }, + + /* these seem to tickle a bug in glibc 2.2.4 */ + { " x", " ", "-999", EOF, 1, -555, 1 }, + { " xyz", " ", "-999", EOF, 1, -555, 1 }, + { " x%Zn", " ", "-999", EOF, 1, -555, 1 }, + }; + + int i, j, ignore; + int got_ret, want_ret, got_upto, want_upto; + mpz_t got, want; + long got_l, want_ftell; + int error = 0; + fun_t fun; + const char *name; + char fmt[128]; + + mpz_init (got); + mpz_init (want); + + for (i = 0; i < numberof (data); i++) + { + mpz_set_str_or_abort (want, data[i].want, 0); + + ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt)); + strcpy (fmt, data[i].fmt); + strcat (fmt, "%n"); + + ignore = fmt_allignore (fmt); + + for (j = 0; j <= 3; j++) + { + want_ret = data[i].want_ret; + + want_ftell = data[i].want_ftell; + if (want_ftell == -1) + want_ftell = strlen (data[i].input); + + want_upto = data[i].want_upto; + if (want_upto == -1) + want_upto = strlen (data[i].input); + + switch (j) { + case 0: + name = "gmp_sscanf"; + fun = fun_gmp_sscanf; + break; + case 1: + name = "gmp_fscanf"; + fun = fun_gmp_fscanf; + break; + case 2: +#ifdef __GLIBC__ + if (data[i].not_glibc) + continue; +#endif + if (! libc_scanf_convert (fmt)) + continue; + name = "standard sscanf"; + fun = fun_sscanf; + break; + case 3: +#ifdef __GLIBC__ + if (data[i].not_glibc) + continue; +#endif + if (! libc_scanf_convert (fmt)) + continue; + name = "standard fscanf"; + fun = fun_fscanf; + break; + default: + ASSERT_ALWAYS (0); + break; + } + + got_upto = -555; + got_ftell = -1L; + + switch (j) { + case 0: + case 1: + mpz_set_si (got, -999L); + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, got, &got_upto); + break; + case 2: + case 3: + got_l = -999L; + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto); + mpz_set_si (got, got_l); + break; + default: + ASSERT_ALWAYS (0); + break; + } + + MPZ_CHECK_FORMAT (got); + + if (got_ret != want_ret) + { + printf ("%s wrong return value\n", name); + error = 1; + } + if (want_ret == 1 && mpz_cmp (want, got) != 0) + { + printf ("%s wrong result\n", name); + error = 1; + } + if (got_upto != want_upto) + { + printf ("%s wrong upto\n", name); + error = 1; + } + if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell) + { + printf ("%s wrong ftell\n", name); + error = 1; + } + if (error) + { + printf (" fmt \"%s\"\n", data[i].fmt); + printf (" input \"%s\"\n", data[i].input); + printf (" ignore %d\n", ignore); + printf (" ret want=%d\n", want_ret); + printf (" got =%d\n", got_ret); + mpz_trace (" value want", want); + mpz_trace (" got ", got); + printf (" upto want =%d\n", want_upto); + printf (" got =%d\n", got_upto); + if (got_ftell != -1) + { + printf (" ftell want =%ld\n", want_ftell); + printf (" got =%ld\n", got_ftell); + } + abort (); + } + } + } + + mpz_clear (got); + mpz_clear (want); +} + +void +check_q (void) +{ + static const struct { + const char *fmt; + const char *input; + const char *want; + int ret; + long ftell; + + } data[] = { + + { "%Qd", "0", "0", 1, -1 }, + { "%Qd", "1", "1", 1, -1 }, + { "%Qd", "123", "123", 1, -1 }, + { "%Qd", "+0", "0", 1, -1 }, + { "%Qd", "+1", "1", 1, -1 }, + { "%Qd", "+123", "123", 1, -1 }, + { "%Qd", "-0", "0", 1, -1 }, + { "%Qd", "-1", "-1", 1, -1 }, + { "%Qd", "-123", "-123", 1, -1 }, + + { "%Qo", "0", "0", 1, -1 }, + { "%Qo", "173", "123", 1, -1 }, + { "%Qo", "+0", "0", 1, -1 }, + { "%Qo", "+173", "123", 1, -1 }, + { "%Qo", "-0", "0", 1, -1 }, + { "%Qo", "-173", "-123", 1, -1 }, + + { "%Qx", "0", "0", 1, -1 }, + { "%Qx", "7b", "123", 1, -1 }, + { "%Qx", "7b", "123", 1, -1 }, + { "%Qx", "+0", "0", 1, -1 }, + { "%Qx", "+7b", "123", 1, -1 }, + { "%Qx", "+7b", "123", 1, -1 }, + { "%Qx", "-0", "-0", 1, -1 }, + { "%Qx", "-7b", "-123", 1, -1 }, + { "%Qx", "-7b", "-123", 1, -1 }, + { "%QX", "0", "0", 1, -1 }, + { "%QX", "7b", "123", 1, -1 }, + { "%QX", "7b", "123", 1, -1 }, + { "%QX", "+0", "0", 1, -1 }, + { "%QX", "+7b", "123", 1, -1 }, + { "%QX", "+7b", "123", 1, -1 }, + { "%QX", "-0", "-0", 1, -1 }, + { "%QX", "-7b", "-123", 1, -1 }, + { "%QX", "-7b", "-123", 1, -1 }, + { "%Qx", "0", "0", 1, -1 }, + { "%Qx", "7B", "123", 1, -1 }, + { "%Qx", "7B", "123", 1, -1 }, + { "%Qx", "+0", "0", 1, -1 }, + { "%Qx", "+7B", "123", 1, -1 }, + { "%Qx", "+7B", "123", 1, -1 }, + { "%Qx", "-0", "-0", 1, -1 }, + { "%Qx", "-7B", "-123", 1, -1 }, + { "%Qx", "-7B", "-123", 1, -1 }, + { "%QX", "0", "0", 1, -1 }, + { "%QX", "7B", "123", 1, -1 }, + { "%QX", "7B", "123", 1, -1 }, + { "%QX", "+0", "0", 1, -1 }, + { "%QX", "+7B", "123", 1, -1 }, + { "%QX", "+7B", "123", 1, -1 }, + { "%QX", "-0", "-0", 1, -1 }, + { "%QX", "-7B", "-123", 1, -1 }, + { "%QX", "-7B", "-123", 1, -1 }, + + { "%Qi", "0", "0", 1, -1 }, + { "%Qi", "1", "1", 1, -1 }, + { "%Qi", "123", "123", 1, -1 }, + { "%Qi", "+0", "0", 1, -1 }, + { "%Qi", "+1", "1", 1, -1 }, + { "%Qi", "+123", "123", 1, -1 }, + { "%Qi", "-0", "0", 1, -1 }, + { "%Qi", "-1", "-1", 1, -1 }, + { "%Qi", "-123", "-123", 1, -1 }, + + { "%Qi", "00", "0", 1, -1 }, + { "%Qi", "0173", "123", 1, -1 }, + { "%Qi", "+00", "0", 1, -1 }, + { "%Qi", "+0173", "123", 1, -1 }, + { "%Qi", "-00", "0", 1, -1 }, + { "%Qi", "-0173", "-123", 1, -1 }, + + { "%Qi", "0x0", "0", 1, -1 }, + { "%Qi", "0x7b", "123", 1, -1 }, + { "%Qi", "0x7b", "123", 1, -1 }, + { "%Qi", "+0x0", "0", 1, -1 }, + { "%Qi", "+0x7b", "123", 1, -1 }, + { "%Qi", "+0x7b", "123", 1, -1 }, + { "%Qi", "-0x0", "-0", 1, -1 }, + { "%Qi", "-0x7b", "-123", 1, -1 }, + { "%Qi", "-0x7b", "-123", 1, -1 }, + { "%Qi", "0X0", "0", 1, -1 }, + { "%Qi", "0X7b", "123", 1, -1 }, + { "%Qi", "0X7b", "123", 1, -1 }, + { "%Qi", "+0X0", "0", 1, -1 }, + { "%Qi", "+0X7b", "123", 1, -1 }, + { "%Qi", "+0X7b", "123", 1, -1 }, + { "%Qi", "-0X0", "-0", 1, -1 }, + { "%Qi", "-0X7b", "-123", 1, -1 }, + { "%Qi", "-0X7b", "-123", 1, -1 }, + { "%Qi", "0x0", "0", 1, -1 }, + { "%Qi", "0x7B", "123", 1, -1 }, + { "%Qi", "0x7B", "123", 1, -1 }, + { "%Qi", "+0x0", "0", 1, -1 }, + { "%Qi", "+0x7B", "123", 1, -1 }, + { "%Qi", "+0x7B", "123", 1, -1 }, + { "%Qi", "-0x0", "-0", 1, -1 }, + { "%Qi", "-0x7B", "-123", 1, -1 }, + { "%Qi", "-0x7B", "-123", 1, -1 }, + { "%Qi", "0X0", "0", 1, -1 }, + { "%Qi", "0X7B", "123", 1, -1 }, + { "%Qi", "0X7B", "123", 1, -1 }, + { "%Qi", "+0X0", "0", 1, -1 }, + { "%Qi", "+0X7B", "123", 1, -1 }, + { "%Qi", "+0X7B", "123", 1, -1 }, + { "%Qi", "-0X0", "-0", 1, -1 }, + { "%Qi", "-0X7B", "-123", 1, -1 }, + { "%Qi", "-0X7B", "-123", 1, -1 }, + + { "%Qd", " 0", "0", 1, -1 }, + { "%Qd", " 0", "0", 1, -1 }, + { "%Qd", " 0", "0", 1, -1 }, + { "%Qd", "\t0", "0", 1, -1 }, + { "%Qd", "\t\t0", "0", 1, -1 }, + + { "%Qd", "3/2", "3/2", 1, -1 }, + { "%Qd", "+3/2", "3/2", 1, -1 }, + { "%Qd", "-3/2", "-3/2", 1, -1 }, + + { "%Qx", "f/10", "15/16", 1, -1 }, + { "%Qx", "F/10", "15/16", 1, -1 }, + { "%QX", "f/10", "15/16", 1, -1 }, + { "%QX", "F/10", "15/16", 1, -1 }, + + { "%Qo", "20/21", "16/17", 1, -1 }, + { "%Qo", "-20/21", "-16/17", 1, -1 }, + + { "%Qi", "10/11", "10/11", 1, -1 }, + { "%Qi", "+10/11", "10/11", 1, -1 }, + { "%Qi", "-10/11", "-10/11", 1, -1 }, + { "%Qi", "010/11", "8/11", 1, -1 }, + { "%Qi", "+010/11", "8/11", 1, -1 }, + { "%Qi", "-010/11", "-8/11", 1, -1 }, + { "%Qi", "0x10/11", "16/11", 1, -1 }, + { "%Qi", "+0x10/11", "16/11", 1, -1 }, + { "%Qi", "-0x10/11", "-16/11", 1, -1 }, + + { "%Qi", "10/011", "10/9", 1, -1 }, + { "%Qi", "+10/011", "10/9", 1, -1 }, + { "%Qi", "-10/011", "-10/9", 1, -1 }, + { "%Qi", "010/011", "8/9", 1, -1 }, + { "%Qi", "+010/011", "8/9", 1, -1 }, + { "%Qi", "-010/011", "-8/9", 1, -1 }, + { "%Qi", "0x10/011", "16/9", 1, -1 }, + { "%Qi", "+0x10/011", "16/9", 1, -1 }, + { "%Qi", "-0x10/011", "-16/9", 1, -1 }, + + { "%Qi", "10/0x11", "10/17", 1, -1 }, + { "%Qi", "+10/0x11", "10/17", 1, -1 }, + { "%Qi", "-10/0x11", "-10/17", 1, -1 }, + { "%Qi", "010/0x11", "8/17", 1, -1 }, + { "%Qi", "+010/0x11", "8/17", 1, -1 }, + { "%Qi", "-010/0x11", "-8/17", 1, -1 }, + { "%Qi", "0x10/0x11", "16/17", 1, -1 }, + { "%Qi", "+0x10/0x11", "16/17", 1, -1 }, + { "%Qi", "-0x10/0x11", "-16/17", 1, -1 }, + + { "hello%Qd", "hello0", "0", 1, -1 }, + { "hello%Qd", "hello 0", "0", 1, -1 }, + { "hello%Qd", "hello \t0", "0", 1, -1 }, + { "hello%Qdworld", "hello 0world", "0", 1, -1 }, + { "hello%Qd", "hello3/2", "3/2", 1, -1 }, + + { "hello%*Qd", "hello0", "-999/121", 0, -1 }, + { "hello%*Qd", "hello 0", "-999/121", 0, -1 }, + { "hello%*Qd", "hello \t0", "-999/121", 0, -1 }, + { "hello%*Qdworld", "hello 0world", "-999/121", 0, -1 }, + { "hello%*Qdworld", "hello3/2world", "-999/121", 0, -1 }, + + { "%Qd", "", "-999/121", -1, -1 }, + { "%Qd", " ", "-999/121", -1, -1 }, + { " %Qd", "", "-999/121", -1, -1 }, + { "xyz%Qd", "", "-999/121", -1, -1 }, + + { "%*Qd", "", "-999/121", -1, -1 }, + { " %*Qd", "", "-999/121", -1, -1 }, + { "xyz%*Qd", "", "-999/121", -1, -1 }, + + /* match something, but invalid */ + { "%Qd", "-", "-999/121", 0, 1 }, + { "%Qd", "+", "-999/121", 0, 1 }, + { "%Qd", "/-", "-999/121", 0, 1 }, + { "%Qd", "/+", "-999/121", 0, 1 }, + { "%Qd", "-/", "-999/121", 0, 1 }, + { "%Qd", "+/", "-999/121", 0, 1 }, + { "%Qd", "-/-", "-999/121", 0, 1 }, + { "%Qd", "-/+", "-999/121", 0, 1 }, + { "%Qd", "+/+", "-999/121", 0, 1 }, + { "%Qd", "/123", "-999/121", 0, 1 }, + { "%Qd", "-/123", "-999/121", 0, 1 }, + { "%Qd", "+/123", "-999/121", 0, 1 }, + { "%Qd", "123/", "-999/121", 0, 1 }, + { "%Qd", "123/-", "-999/121", 0, 1 }, + { "%Qd", "123/+", "-999/121", 0, 1 }, + { "xyz%Qd", "xyz-", "-999/121", 0, 4 }, + { "xyz%Qd", "xyz+", "-999/121", 0, 4 }, + + { "%1Qi", "12/57", "1", 1, 1 }, + { "%2Qi", "12/57", "12", 1, 2 }, + { "%3Qi", "12/57", "-999/121", 0, -1 }, + { "%4Qi", "12/57", "12/5", 1, 4 }, + { "%5Qi", "12/57", "12/57", 1, 5 }, + { "%6Qi", "12/57", "12/57", 1, 5 }, + { "%7Qi", "12/57", "12/57", 1, 5 }, + + { "%1Qi", "012/057", "0", 1, 1 }, + { "%2Qi", "012/057", "01", 1, 2 }, + { "%3Qi", "012/057", "012", 1, 3 }, + { "%4Qi", "012/057", "-999/121", 0, -1 }, + { "%5Qi", "012/057", "012/0", 1, 5 }, + { "%6Qi", "012/057", "012/5", 1, 6 }, + { "%7Qi", "012/057", "012/057", 1, 7 }, + { "%8Qi", "012/057", "012/057", 1, 7 }, + { "%9Qi", "012/057", "012/057", 1, 7 }, + + { "%1Qi", "0x12/0x57", "0", 1, 1 }, + { "%2Qi", "0x12/0x57", "-999", 0, 2 }, + { "%3Qi", "0x12/0x57", "0x1", 1, 3 }, + { "%4Qi", "0x12/0x57", "0x12", 1, 4 }, + { "%5Qi", "0x12/0x57", "-999/121", 0, 5 }, + { "%6Qi", "0x12/0x57", "0x12/0", 1, 6 }, + { "%7Qi", "0x12/0x57", "-999/121", 0, 7 }, + { "%8Qi", "0x12/0x57", "0x12/0x5", 1, 8 }, + { "%9Qi", "0x12/0x57", "0x12/0x57", 1, 9 }, + { "%10Qi", "0x12/0x57", "0x12/0x57", 1, 9 }, + { "%11Qi", "0x12/0x57", "0x12/0x57", 1, 9 }, + + { "%Qd", "xyz", "0", 0, 0 }, + }; + + int i, j, ignore, got_ret, want_ret, got_upto, want_upto; + mpq_t got, want; + long got_l, want_ftell; + int error = 0; + fun_t fun; + const char *name; + char fmt[128]; + + mpq_init (got); + mpq_init (want); + + for (i = 0; i < numberof (data); i++) + { + mpq_set_str_or_abort (want, data[i].want, 0); + + ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt)); + strcpy (fmt, data[i].fmt); + strcat (fmt, "%n"); + + ignore = (strchr (fmt, '*') != NULL); + + for (j = 0; j <= 3; j++) + { + want_ret = data[i].ret; + + want_ftell = data[i].ftell; + if (want_ftell == -1) + want_ftell = strlen (data[i].input); + want_upto = want_ftell; + + if (want_ret == -1 || (want_ret == 0 && ! ignore)) + { + want_ftell = -1; + want_upto = -555; + } + + switch (j) { + case 0: + name = "gmp_sscanf"; + fun = fun_gmp_sscanf; + break; + case 1: + name = "gmp_fscanf"; + fun = fun_gmp_fscanf; + break; + case 2: + if (strchr (data[i].input, '/') != NULL) + continue; + if (! libc_scanf_convert (fmt)) + continue; + name = "standard sscanf"; + fun = fun_sscanf; + break; + case 3: + if (strchr (data[i].input, '/') != NULL) + continue; + if (! libc_scanf_convert (fmt)) + continue; + name = "standard fscanf"; + fun = fun_fscanf; + break; + default: + ASSERT_ALWAYS (0); + break; + } + + got_upto = -555; + got_ftell = -1; + + switch (j) { + case 0: + case 1: + mpq_set_si (got, -999L, 121L); + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, got, &got_upto); + break; + case 2: + case 3: + got_l = -999L; + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto); + mpq_set_si (got, got_l, (got_l == -999L ? 121L : 1L)); + break; + default: + ASSERT_ALWAYS (0); + break; + } + + MPZ_CHECK_FORMAT (mpq_numref (got)); + MPZ_CHECK_FORMAT (mpq_denref (got)); + + if (got_ret != want_ret) + { + printf ("%s wrong return value\n", name); + error = 1; + } + /* use direct mpz compares, since some of the test data is + non-canonical and can trip ASSERTs in mpq_equal */ + if (want_ret == 1 + && ! (mpz_cmp (mpq_numref(want), mpq_numref(got)) == 0 + && mpz_cmp (mpq_denref(want), mpq_denref(got)) == 0)) + { + printf ("%s wrong result\n", name); + error = 1; + } + if (got_upto != want_upto) + { + printf ("%s wrong upto\n", name); + error = 1; + } + if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell) + { + printf ("%s wrong ftell\n", name); + error = 1; + } + if (error) + { + printf (" fmt \"%s\"\n", data[i].fmt); + printf (" input \"%s\"\n", data[i].input); + printf (" ret want=%d\n", want_ret); + printf (" got =%d\n", got_ret); + mpq_trace (" value want", want); + mpq_trace (" got ", got); + printf (" upto want=%d\n", want_upto); + printf (" got =%d\n", got_upto); + if (got_ftell != -1) + { + printf (" ftell want =%ld\n", want_ftell); + printf (" got =%ld\n", got_ftell); + } + abort (); + } + } + } + + mpq_clear (got); + mpq_clear (want); +} + +void +check_f (void) +{ + static const struct { + const char *fmt; + const char *input; + const char *want; + int ret; + long ftell; /* or -1 for length of input string */ + + } data[] = { + + { "%Ff", "0", "0", 1, -1 }, + { "%Fe", "0", "0", 1, -1 }, + { "%FE", "0", "0", 1, -1 }, + { "%Fg", "0", "0", 1, -1 }, + { "%FG", "0", "0", 1, -1 }, + + { "%Ff", "123", "123", 1, -1 }, + { "%Ff", "+123", "123", 1, -1 }, + { "%Ff", "-123", "-123", 1, -1 }, + { "%Ff", "123.", "123", 1, -1 }, + { "%Ff", "+123.", "123", 1, -1 }, + { "%Ff", "-123.", "-123", 1, -1 }, + { "%Ff", "123.0", "123", 1, -1 }, + { "%Ff", "+123.0", "123", 1, -1 }, + { "%Ff", "-123.0", "-123", 1, -1 }, + { "%Ff", "0123", "123", 1, -1 }, + { "%Ff", "-0123", "-123", 1, -1 }, + + { "%Ff", "123.456e3", "123456", 1, -1 }, + { "%Ff", "-123.456e3", "-123456", 1, -1 }, + { "%Ff", "123.456e+3", "123456", 1, -1 }, + { "%Ff", "-123.456e+3", "-123456", 1, -1 }, + { "%Ff", "123000e-3", "123", 1, -1 }, + { "%Ff", "-123000e-3", "-123", 1, -1 }, + { "%Ff", "123000.e-3", "123", 1, -1 }, + { "%Ff", "-123000.e-3", "-123", 1, -1 }, + + { "%Ff", "123.456E3", "123456", 1, -1 }, + { "%Ff", "-123.456E3", "-123456", 1, -1 }, + { "%Ff", "123.456E+3", "123456", 1, -1 }, + { "%Ff", "-123.456E+3", "-123456", 1, -1 }, + { "%Ff", "123000E-3", "123", 1, -1 }, + { "%Ff", "-123000E-3", "-123", 1, -1 }, + { "%Ff", "123000.E-3", "123", 1, -1 }, + { "%Ff", "-123000.E-3", "-123", 1, -1 }, + + { "%Ff", ".456e3", "456", 1, -1 }, + { "%Ff", "-.456e3", "-456", 1, -1 }, + { "%Ff", ".456e+3", "456", 1, -1 }, + { "%Ff", "-.456e+3", "-456", 1, -1 }, + + { "%Ff", " 0", "0", 1, -1 }, + { "%Ff", " 0", "0", 1, -1 }, + { "%Ff", " 0", "0", 1, -1 }, + { "%Ff", "\t0", "0", 1, -1 }, + { "%Ff", "\t\t0", "0", 1, -1 }, + + { "hello%Fg", "hello0", "0", 1, -1 }, + { "hello%Fg", "hello 0", "0", 1, -1 }, + { "hello%Fg", "hello \t0", "0", 1, -1 }, + { "hello%Fgworld", "hello 0world", "0", 1, -1 }, + { "hello%Fg", "hello3.0", "3.0", 1, -1 }, + + { "hello%*Fg", "hello0", "-999", 0, -1 }, + { "hello%*Fg", "hello 0", "-999", 0, -1 }, + { "hello%*Fg", "hello \t0", "-999", 0, -1 }, + { "hello%*Fgworld", "hello 0world", "-999", 0, -1 }, + { "hello%*Fgworld", "hello3.0world", "-999", 0, -1 }, + + { "%Ff", "", "-999", -1, -1 }, + { "%Ff", " ", "-999", -1, -1 }, + { "%Ff", "\t", "-999", -1, -1 }, + { "%Ff", " \t", "-999", -1, -1 }, + { " %Ff", "", "-999", -1, -1 }, + { "xyz%Ff", "", "-999", -1, -1 }, + + { "%*Ff", "", "-999", -1, -1 }, + { " %*Ff", "", "-999", -1, -1 }, + { "xyz%*Ff", "", "-999", -1, -1 }, + + { "%Ff", "xyz", "0", 0 }, + + /* various non-empty but invalid */ + { "%Ff", "-", "-999", 0, 1 }, + { "%Ff", "+", "-999", 0, 1 }, + { "xyz%Ff", "xyz-", "-999", 0, 4 }, + { "xyz%Ff", "xyz+", "-999", 0, 4 }, + { "%Ff", "-.", "-999", 0, 2 }, + { "%Ff", "+.", "-999", 0, 2 }, + { "%Ff", ".e", "-999", 0, 1 }, + { "%Ff", "-.e", "-999", 0, 2 }, + { "%Ff", "+.e", "-999", 0, 2 }, + { "%Ff", ".E", "-999", 0, 1 }, + { "%Ff", "-.E", "-999", 0, 2 }, + { "%Ff", "+.E", "-999", 0, 2 }, + { "%Ff", ".e123", "-999", 0, 1 }, + { "%Ff", "-.e123", "-999", 0, 2 }, + { "%Ff", "+.e123", "-999", 0, 2 }, + { "%Ff", "123e", "-999", 0, 4 }, + { "%Ff", "-123e", "-999", 0, 5 }, + { "%Ff", "123e-", "-999", 0, 5 }, + { "%Ff", "-123e-", "-999", 0, 6 }, + { "%Ff", "123e+", "-999", 0, 5 }, + { "%Ff", "-123e+", "-999", 0, 6 }, + { "%Ff", "123e-Z", "-999", 0, 5 }, + + /* hex floats */ + { "%Ff", "0x123p0", "291", 1, -1 }, + { "%Ff", "0x123P0", "291", 1, -1 }, + { "%Ff", "0X123p0", "291", 1, -1 }, + { "%Ff", "0X123P0", "291", 1, -1 }, + { "%Ff", "-0x123p0", "-291", 1, -1 }, + { "%Ff", "+0x123p0", "291", 1, -1 }, + { "%Ff", "0x123.p0", "291", 1, -1 }, + { "%Ff", "0x12.3p4", "291", 1, -1 }, + { "%Ff", "-0x12.3p4", "-291", 1, -1 }, + { "%Ff", "+0x12.3p4", "291", 1, -1 }, + { "%Ff", "0x1230p-4", "291", 1, -1 }, + { "%Ff", "-0x1230p-4", "-291", 1, -1 }, + { "%Ff", "+0x1230p-4", "291", 1, -1 }, + { "%Ff", "+0x.1230p12", "291", 1, -1 }, + { "%Ff", "+0x123000p-12", "291", 1, -1 }, + { "%Ff", "0x123 p12", "291", 1, 5 }, + { "%Ff", "0x9 9", "9", 1, 3 }, + { "%Ff", "0x01", "1", 1, 4 }, + { "%Ff", "0x23", "35", 1, 4 }, + { "%Ff", "0x45", "69", 1, 4 }, + { "%Ff", "0x67", "103", 1, 4 }, + { "%Ff", "0x89", "137", 1, 4 }, + { "%Ff", "0xAB", "171", 1, 4 }, + { "%Ff", "0xCD", "205", 1, 4 }, + { "%Ff", "0xEF", "239", 1, 4 }, + { "%Ff", "0xab", "171", 1, 4 }, + { "%Ff", "0xcd", "205", 1, 4 }, + { "%Ff", "0xef", "239", 1, 4 }, + { "%Ff", "0x100p0A", "256", 1, 7 }, + { "%Ff", "0x1p9", "512", 1, -1 }, + + /* invalid hex floats */ + { "%Ff", "0x", "-999", 0, 2 }, + { "%Ff", "-0x", "-999", 0, 3 }, + { "%Ff", "+0x", "-999", 0, 3 }, + { "%Ff", "0x-", "-999", 0, 2 }, + { "%Ff", "0x+", "-999", 0, 2 }, + { "%Ff", "0x.", "-999", 0, 3 }, + { "%Ff", "-0x.", "-999", 0, 4 }, + { "%Ff", "+0x.", "-999", 0, 4 }, + { "%Ff", "0x.p", "-999", 0, 3 }, + { "%Ff", "-0x.p", "-999", 0, 4 }, + { "%Ff", "+0x.p", "-999", 0, 4 }, + { "%Ff", "0x.P", "-999", 0, 3 }, + { "%Ff", "-0x.P", "-999", 0, 4 }, + { "%Ff", "+0x.P", "-999", 0, 4 }, + { "%Ff", ".p123", "-999", 0, 1 }, + { "%Ff", "-.p123", "-999", 0, 2 }, + { "%Ff", "+.p123", "-999", 0, 2 }, + { "%Ff", "0x1p", "-999", 0, 4 }, + { "%Ff", "0x1p-", "-999", 0, 5 }, + { "%Ff", "0x1p+", "-999", 0, 5 }, + { "%Ff", "0x123p 12", "291", 0, 6 }, + { "%Ff", "0x 123p12", "291", 0, 2 }, + + }; + + int i, j, ignore, got_ret, want_ret, got_upto, want_upto; + mpf_t got, want; + double got_d; + long want_ftell; + int error = 0; + fun_t fun; + const char *name; + char fmt[128]; + + mpf_init (got); + mpf_init (want); + + for (i = 0; i < numberof (data); i++) + { + mpf_set_str_or_abort (want, data[i].want, 10); + + ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt)); + strcpy (fmt, data[i].fmt); + strcat (fmt, "%n"); + + ignore = (strchr (fmt, '*') != NULL); + + for (j = 0; j <= 3; j++) + { + want_ret = data[i].ret; + + want_ftell = data[i].ftell; + if (want_ftell == -1) + want_ftell = strlen (data[i].input); + want_upto = want_ftell; + + if (want_ret == -1 || (want_ret == 0 && ! ignore)) + want_upto = -555; + + switch (j) { + case 0: + name = "gmp_sscanf"; + fun = fun_gmp_sscanf; + break; + case 1: + name = "gmp_fscanf"; + fun = fun_gmp_fscanf; + break; + case 2: + if (! libc_scanf_convert (fmt)) + continue; + name = "standard sscanf"; + fun = fun_sscanf; + break; + case 3: + if (! libc_scanf_convert (fmt)) + continue; + name = "standard fscanf"; + fun = fun_fscanf; + break; + default: + ASSERT_ALWAYS (0); + break; + } + + got_upto = -555; + got_ftell = -1; + + switch (j) { + case 0: + case 1: + mpf_set_si (got, -999L); + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, got, &got_upto); + break; + case 2: + case 3: + got_d = -999L; + if (ignore) + got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL); + else + got_ret = (*fun) (data[i].input, fmt, &got_d, &got_upto); + mpf_set_d (got, got_d); + break; + default: + ASSERT_ALWAYS (0); + break; + } + + MPF_CHECK_FORMAT (got); + + if (got_ret != want_ret) + { + printf ("%s wrong return value\n", name); + error = 1; + } + if (want_ret == 1 && mpf_cmp (want, got) != 0) + { + printf ("%s wrong result\n", name); + error = 1; + } + if (got_upto != want_upto) + { + printf ("%s wrong upto\n", name); + error = 1; + } + if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell) + { + printf ("%s wrong ftell\n", name); + error = 1; + } + if (error) + { + printf (" fmt \"%s\"\n", data[i].fmt); + printf (" input \"%s\"\n", data[i].input); + printf (" ret want=%d\n", want_ret); + printf (" got =%d\n", got_ret); + mpf_trace (" value want", want); + mpf_trace (" got ", got); + printf (" upto want=%d\n", want_upto); + printf (" got =%d\n", got_upto); + if (got_ftell != -1) + { + printf (" ftell want =%ld\n", want_ftell); + printf (" got =%ld\n", got_ftell); + } + abort (); + } + } + } + + mpf_clear (got); + mpf_clear (want); +} + + +void +check_n (void) +{ + int ret; + + /* %n suppressed */ + { + int n = 123; + gmp_sscanf (" ", " %*n", &n); + ASSERT_ALWAYS (n == 123); + } + { + int n = 123; + fromstring_gmp_fscanf (" ", " %*n", &n); + ASSERT_ALWAYS (n == 123); + } + + +#define CHECK_N(type, string) \ + do { \ + type x[2]; \ + char fmt[128]; \ + int ret; \ + \ + x[0] = ~ (type) 0; \ + x[1] = ~ (type) 0; \ + sprintf (fmt, "abc%%%sn", string); \ + ret = gmp_sscanf ("abc", fmt, &x[0]); \ + \ + ASSERT_ALWAYS (ret == 0); \ + \ + /* should write whole of x[0] and none of x[1] */ \ + ASSERT_ALWAYS (x[0] == 3); \ + ASSERT_ALWAYS (x[1] == (type) ~ (type) 0); \ + \ + } while (0) + + CHECK_N (char, "hh"); + CHECK_N (long, "l"); +#if HAVE_LONG_LONG + CHECK_N (long long, "L"); +#endif +#if HAVE_INTMAX_T + CHECK_N (intmax_t, "j"); +#endif +#if HAVE_PTRDIFF_T + CHECK_N (ptrdiff_t, "t"); +#endif + CHECK_N (short, "h"); + CHECK_N (size_t, "z"); + + /* %Zn */ + { + mpz_t x[2]; + mpz_init_set_si (x[0], -987L); + mpz_init_set_si (x[1], 654L); + ret = gmp_sscanf ("xyz ", "xyz%Zn", x[0]); + MPZ_CHECK_FORMAT (x[0]); + MPZ_CHECK_FORMAT (x[1]); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0); + ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0); + mpz_clear (x[0]); + mpz_clear (x[1]); + } + { + mpz_t x; + mpz_init (x); + ret = fromstring_gmp_fscanf ("xyz ", "xyz%Zn", x); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpz_cmp_ui (x, 3L) == 0); + mpz_clear (x); + } + + /* %Qn */ + { + mpq_t x[2]; + mpq_init (x[0]); + mpq_init (x[1]); + mpq_set_ui (x[0], 987L, 654L); + mpq_set_ui (x[1], 4115L, 226L); + ret = gmp_sscanf ("xyz ", "xyz%Qn", x[0]); + MPQ_CHECK_FORMAT (x[0]); + MPQ_CHECK_FORMAT (x[1]); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0); + ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0); + mpq_clear (x[0]); + mpq_clear (x[1]); + } + { + mpq_t x; + mpq_init (x); + ret = fromstring_gmp_fscanf ("xyz ", "xyz%Qn", x); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpq_cmp_ui (x, 3L, 1L) == 0); + mpq_clear (x); + } + + /* %Fn */ + { + mpf_t x[2]; + mpf_init (x[0]); + mpf_init (x[1]); + mpf_set_ui (x[0], 987L); + mpf_set_ui (x[1], 654L); + ret = gmp_sscanf ("xyz ", "xyz%Fn", x[0]); + MPF_CHECK_FORMAT (x[0]); + MPF_CHECK_FORMAT (x[1]); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0); + ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0); + mpf_clear (x[0]); + mpf_clear (x[1]); + } + { + mpf_t x; + mpf_init (x); + ret = fromstring_gmp_fscanf ("xyz ", "xyz%Fn", x); + ASSERT_ALWAYS (ret == 0); + ASSERT_ALWAYS (mpf_cmp_ui (x, 3L) == 0); + mpf_clear (x); + } +} + + +void +check_misc (void) +{ + int ret, cmp; + { + int a=9, b=8, c=7, n=66; + mpz_t z; + mpz_init (z); + ret = gmp_sscanf ("1 2 3 4", "%d %d %d %Zd%n", + &a, &b, &c, z, &n); + ASSERT_ALWAYS (ret == 4); + ASSERT_ALWAYS (a == 1); + ASSERT_ALWAYS (b == 2); + ASSERT_ALWAYS (c == 3); + ASSERT_ALWAYS (n == 7); + ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0); + mpz_clear (z); + } + { + int a=9, b=8, c=7, n=66; + mpz_t z; + mpz_init (z); + ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %d %d %Zd%n", + &a, &b, &c, z, &n); + ASSERT_ALWAYS (ret == 4); + ASSERT_ALWAYS (a == 1); + ASSERT_ALWAYS (b == 2); + ASSERT_ALWAYS (c == 3); + ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0); + ASSERT_ALWAYS (n == 7); + ASSERT_ALWAYS (got_ftell == 7); + mpz_clear (z); + } + + { + int a=9, n=8; + mpz_t z; + mpz_init (z); + ret = gmp_sscanf ("1 2 3 4", "%d %*d %*d %Zd%n", &a, z, &n); + ASSERT_ALWAYS (ret == 2); + ASSERT_ALWAYS (a == 1); + ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0); + ASSERT_ALWAYS (n == 7); + mpz_clear (z); + } + { + int a=9, n=8; + mpz_t z; + mpz_init (z); + ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %*d %*d %Zd%n", + &a, z, &n); + ASSERT_ALWAYS (ret == 2); + ASSERT_ALWAYS (a == 1); + ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0); + ASSERT_ALWAYS (n == 7); + ASSERT_ALWAYS (got_ftell == 7); + mpz_clear (z); + } + + /* EOF for no matching */ + { + char buf[128]; + ret = gmp_sscanf (" ", "%s", buf); + ASSERT_ALWAYS (ret == EOF); + ret = fromstring_gmp_fscanf (" ", "%s", buf); + ASSERT_ALWAYS (ret == EOF); + if (option_libc_scanf) + { + ret = sscanf (" ", "%s", buf); + ASSERT_ALWAYS (ret == EOF); + ret = fun_fscanf (" ", "%s", buf, NULL); + ASSERT_ALWAYS (ret == EOF); + } + } + + /* suppressed field, then eof */ + { + int x; + if (test_sscanf_eof_ok ()) + { + ret = gmp_sscanf ("123", "%*d%d", &x); + ASSERT_ALWAYS (ret == EOF); + } + ret = fromstring_gmp_fscanf ("123", "%*d%d", &x); + ASSERT_ALWAYS (ret == EOF); + if (option_libc_scanf) + { + ret = sscanf ("123", "%*d%d", &x); + ASSERT_ALWAYS (ret == EOF); + ret = fun_fscanf ("123", "%*d%d", &x, NULL); + ASSERT_ALWAYS (ret == EOF); + } + } + { + mpz_t x; + mpz_init (x); + ret = gmp_sscanf ("123", "%*Zd%Zd", x); + ASSERT_ALWAYS (ret == EOF); + ret = fromstring_gmp_fscanf ("123", "%*Zd%Zd", x); + ASSERT_ALWAYS (ret == EOF); + mpz_clear (x); + } + + /* %[...], glibc only */ +#ifdef __GLIBC__ + { + char buf[128]; + int n = -1; + buf[0] = '\0'; + ret = gmp_sscanf ("abcdefgh", "%[a-d]ef%n", buf, &n); + ASSERT_ALWAYS (ret == 1); + cmp = strcmp (buf, "abcd"); + ASSERT_ALWAYS (cmp == 0); + ASSERT_ALWAYS (n == 6); + } + { + char buf[128]; + int n = -1; + buf[0] = '\0'; + ret = gmp_sscanf ("xyza", "%[^a]a%n", buf, &n); + ASSERT_ALWAYS (ret == 1); + cmp = strcmp (buf, "xyz"); + ASSERT_ALWAYS (cmp == 0); + ASSERT_ALWAYS (n == 4); + } + { + char buf[128]; + int n = -1; + buf[0] = '\0'; + ret = gmp_sscanf ("ab]ab]", "%[]ab]%n", buf, &n); + ASSERT_ALWAYS (ret == 1); + cmp = strcmp (buf, "ab]ab]"); + ASSERT_ALWAYS (cmp == 0); + ASSERT_ALWAYS (n == 6); + } + { + char buf[128]; + int n = -1; + buf[0] = '\0'; + ret = gmp_sscanf ("xyzb", "%[^]ab]b%n", buf, &n); + ASSERT_ALWAYS (ret == 1); + cmp = strcmp (buf, "xyz"); + ASSERT_ALWAYS (cmp == 0); + ASSERT_ALWAYS (n == 4); + } +#endif + + /* %zd etc won't be accepted by sscanf on old systems, and running + something to see if they work might be bad, so only try it on glibc, + and only on a new enough version (glibc 2.0 doesn't have %zd) */ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0) + { + mpz_t z; + size_t s = -1; + mpz_init (z); + ret = gmp_sscanf ("456 789", "%zd %Zd", &s, z); + ASSERT_ALWAYS (ret == 2); + ASSERT_ALWAYS (s == 456); + ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0); + mpz_clear (z); + } + { + mpz_t z; + ptrdiff_t d = -1; + mpz_init (z); + ret = gmp_sscanf ("456 789", "%td %Zd", &d, z); + ASSERT_ALWAYS (ret == 2); + ASSERT_ALWAYS (d == 456); + ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0); + mpz_clear (z); + } + { + mpz_t z; + long long ll = -1; + mpz_init (z); + ret = gmp_sscanf ("456 789", "%Ld %Zd", &ll, z); + ASSERT_ALWAYS (ret == 2); + ASSERT_ALWAYS (ll == 456); + ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0); + mpz_clear (z); + } +#endif +} + +int +main (int argc, char *argv[]) +{ + if (argc > 1 && strcmp (argv[1], "-s") == 0) + option_libc_scanf = 1; + + tests_start (); + + mp_trace_base = 16; + + check_z (); + check_q (); + check_f (); + check_n (); + check_misc (); + + unlink (TEMPFILE); + tests_end (); + exit (0); +} -- cgit v1.2.3