mpir/tests/misc/t-scanf.c
2008-04-17 21:03:07 +00:00

1638 lines
50 KiB
C

/* Test gmp_scanf and related functions.
Copyright 2001, 2002, 2003, 2004 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 2.1 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; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA. */
/* 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"
#if HAVE_STDARG
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include <stddef.h> /* for ptrdiff_t */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_INTTYPES_H
# include <inttypes.h> /* for intmax_t */
#else
# if HAVE_STDINT_H
# include <stdint.h>
# endif
#endif
#if HAVE_UNISTD_H
#include <unistd.h> /* for unlink */
#endif
#include "gmp.h"
#include "gmp-impl.h"
#include "tests.h"
#define TEMPFILE "t-scanf.tmp"
int option_libc_scanf = 0;
typedef int (*fun_t) _PROTO ((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
#if HAVE_STDARG
fromstring_gmp_fscanf (const char *input, const char *fmt, ...)
#else
fromstring_gmp_fscanf (va_alist)
va_dcl
#endif
{
va_list ap;
FILE *fp;
int ret;
#if HAVE_STDARG
va_start (ap, fmt);
#else
const char *input;
const char *fmt;
va_start (ap);
input = va_arg (ap, const char *);
fmt = va_arg (ap, const char *);
#endif
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 = (*__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);
}