1/* Test gmp_scanf and related functions.
2
3Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20
21/* Usage: t-scanf [-s]
22
23   -s  Check the data against the system scanf, where possible.  This is
24       only an option since we don't want to fail if the system scanf is
25       faulty or strange.
26
27   There's some fairly unattractive repetition between check_z, check_q and
28   check_f, but enough differences to make a common loop or a set of macros
29   seem like too much trouble. */
30
31
32#include "config.h"
33
34#if HAVE_STDARG
35#include <stdarg.h>
36#else
37#include <varargs.h>
38#endif
39
40#include <stddef.h>    /* for ptrdiff_t */
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44
45#if HAVE_INTTYPES_H
46# include <inttypes.h> /* for intmax_t */
47#else
48# if HAVE_STDINT_H
49#  include <stdint.h>
50# endif
51#endif
52
53#if HAVE_UNISTD_H
54#include <unistd.h>  /* for unlink */
55#endif
56
57#include "gmp.h"
58#include "gmp-impl.h"
59#include "tests.h"
60
61
62#define TEMPFILE  "t-scanf.tmp"
63
64int   option_libc_scanf = 0;
65
66typedef int (*fun_t) __GMP_PROTO ((const char *, const char *, void *, void *));
67
68
69/* This problem was seen on powerpc7450-apple-darwin7.0.0, sscanf returns 0
70   where it should return EOF.  A workaround in gmp_sscanf would be a bit
71   tedious, and since this is a rather obvious libc bug, quite likely
72   affecting other programs, we'll just suppress affected tests for now.  */
73int
74test_sscanf_eof_ok (void)
75{
76  static int  result = -1;
77
78  if (result == -1)
79    {
80      int  x;
81      if (sscanf ("", "%d", &x) == EOF)
82        {
83          result = 1;
84        }
85      else
86        {
87          printf ("Warning, sscanf(\"\",\"%%d\",&x) doesn't return EOF.\n");
88          printf ("This affects gmp_sscanf, tests involving it will be suppressed.\n");
89          printf ("You should try to get a fix for your libc.\n");
90          result = 0;
91        }
92    }
93  return result;
94}
95
96
97/* Convert fmt from a GMP scanf format string to an equivalent for a plain
98   libc scanf, for example "%Zd" becomes "%ld".  Return 1 if this succeeds,
99   0 if it cannot (or should not) be done.  */
100int
101libc_scanf_convert (char *fmt)
102{
103  char  *p = fmt;
104
105  if (! option_libc_scanf)
106    return 0;
107
108  for ( ; *fmt != '\0'; fmt++)
109    {
110      switch (*fmt) {
111      case 'F':
112      case 'Q':
113      case 'Z':
114        /* transmute */
115        *p++ = 'l';
116        break;
117      default:
118        *p++ = *fmt;
119        break;
120      }
121    }
122  *p = '\0';
123  return 1;
124}
125
126
127long  got_ftell;
128int   fromstring_next_c;
129
130/* Call gmp_fscanf, reading the "input" string data provided. */
131int
132#if HAVE_STDARG
133fromstring_gmp_fscanf (const char *input, const char *fmt, ...)
134#else
135fromstring_gmp_fscanf (va_alist)
136     va_dcl
137#endif
138{
139  va_list  ap;
140  FILE     *fp;
141  int      ret;
142#if HAVE_STDARG
143  va_start (ap, fmt);
144#else
145  const char    *input;
146  const char    *fmt;
147  va_start (ap);
148  input = va_arg (ap, const char *);
149  fmt = va_arg (ap, const char *);
150#endif
151
152  fp = fopen (TEMPFILE, "w+");
153  ASSERT_ALWAYS (fp != NULL);
154  ASSERT_ALWAYS (fputs (input, fp) != EOF);
155  ASSERT_ALWAYS (fflush (fp) == 0);
156  rewind (fp);
157
158  ret = gmp_vfscanf (fp, fmt, ap);
159  got_ftell = ftell (fp);
160  ASSERT_ALWAYS (got_ftell != -1L);
161
162  fromstring_next_c = getc (fp);
163
164  ASSERT_ALWAYS (fclose (fp) == 0);
165  va_end (ap);
166  return ret;
167}
168
169
170int
171fun_gmp_sscanf (const char *input, const char *fmt, void *a1, void *a2)
172{
173  if (a2 == NULL)
174    return gmp_sscanf (input, fmt, a1);
175  else
176    return gmp_sscanf (input, fmt, a1, a2);
177}
178
179int
180fun_gmp_fscanf (const char *input, const char *fmt, void *a1, void *a2)
181{
182  if (a2 == NULL)
183    return fromstring_gmp_fscanf (input, fmt, a1);
184  else
185    return fromstring_gmp_fscanf (input, fmt, a1, a2);
186}
187
188
189int
190fun_fscanf (const char *input, const char *fmt, void *a1, void *a2)
191{
192  FILE  *fp;
193  int   ret;
194
195  fp = fopen (TEMPFILE, "w+");
196  ASSERT_ALWAYS (fp != NULL);
197  ASSERT_ALWAYS (fputs (input, fp) != EOF);
198  ASSERT_ALWAYS (fflush (fp) == 0);
199  rewind (fp);
200
201  if (a2 == NULL)
202    ret = fscanf (fp, fmt, a1);
203  else
204    ret = fscanf (fp, fmt, a1, a2);
205
206  got_ftell = ftell (fp);
207  ASSERT_ALWAYS (got_ftell != -1L);
208
209  fromstring_next_c = getc (fp);
210
211  ASSERT_ALWAYS (fclose (fp) == 0);
212  return ret;
213}
214
215
216/* On various old systems, for instance HP-UX 9, the C library sscanf needs
217   to be able to write into the input string.  Ensure that this is possible,
218   when gcc is putting the test data into a read-only section.
219
220   Actually we ought to only need this under SSCANF_WRITABLE_INPUT from
221   configure, but it's just as easy to do it unconditionally, and in any
222   case this code is only executed under the -s option.  */
223
224int
225fun_sscanf (const char *input, const char *fmt, void *a1, void *a2)
226{
227  char    *input_writable;
228  size_t  size;
229  int     ret;
230
231  size = strlen (input) + 1;
232  input_writable = (*__gmp_allocate_func) (size);
233  memcpy (input_writable, input, size);
234
235  if (a2 == NULL)
236    ret = sscanf (input_writable, fmt, a1);
237  else
238    ret = sscanf (input_writable, fmt, a1, a2);
239
240  (*__gmp_free_func) (input_writable, size);
241  return ret;
242}
243
244
245/* whether the format string consists entirely of ignored fields */
246int
247fmt_allignore (const char *fmt)
248{
249  int  saw_star = 1;
250  for ( ; *fmt != '\0'; fmt++)
251    {
252      switch (*fmt) {
253      case '%':
254        if (! saw_star)
255          return 0;
256        saw_star = 0;
257        break;
258      case '*':
259        saw_star = 1;
260        break;
261      }
262    }
263  return 1;
264}
265
266void
267check_z (void)
268{
269  static const struct {
270    const char  *fmt;
271    const char  *input;
272    const char  *want;
273    int         want_ret;
274    long        want_ftell;
275    int         want_upto;
276    int         not_glibc;
277
278  } data[] = {
279
280    { "%Zd",    "0",    "0", 1, -1, -1 },
281    { "%Zd",    "1",    "1", 1, -1, -1 },
282    { "%Zd",  "123",  "123", 1, -1, -1 },
283    { "%Zd",   "+0",    "0", 1, -1, -1 },
284    { "%Zd",   "+1",    "1", 1, -1, -1 },
285    { "%Zd", "+123",  "123", 1, -1, -1 },
286    { "%Zd",   "-0",    "0", 1, -1, -1 },
287    { "%Zd",   "-1",   "-1", 1, -1, -1 },
288    { "%Zd", "-123", "-123", 1, -1, -1 },
289
290    { "%Zo",    "0",    "0", 1, -1, -1 },
291    { "%Zo",  "173",  "123", 1, -1, -1 },
292    { "%Zo",   "+0",    "0", 1, -1, -1 },
293    { "%Zo", "+173",  "123", 1, -1, -1 },
294    { "%Zo",   "-0",    "0", 1, -1, -1 },
295    { "%Zo", "-173", "-123", 1, -1, -1 },
296
297    { "%Zx",    "0",    "0", 1, -1, -1 },
298    { "%Zx",   "7b",  "123", 1, -1, -1 },
299    { "%Zx",   "7b",  "123", 1, -1, -1 },
300    { "%Zx",   "+0",    "0", 1, -1, -1 },
301    { "%Zx",  "+7b",  "123", 1, -1, -1 },
302    { "%Zx",  "+7b",  "123", 1, -1, -1 },
303    { "%Zx",   "-0",   "-0", 1, -1, -1 },
304    { "%Zx",  "-7b", "-123", 1, -1, -1 },
305    { "%Zx",  "-7b", "-123", 1, -1, -1 },
306    { "%ZX",    "0",    "0", 1, -1, -1 },
307    { "%ZX",   "7b",  "123", 1, -1, -1 },
308    { "%ZX",   "7b",  "123", 1, -1, -1 },
309    { "%ZX",   "+0",    "0", 1, -1, -1 },
310    { "%ZX",  "+7b",  "123", 1, -1, -1 },
311    { "%ZX",  "+7b",  "123", 1, -1, -1 },
312    { "%ZX",   "-0",   "-0", 1, -1, -1 },
313    { "%ZX",  "-7b", "-123", 1, -1, -1 },
314    { "%ZX",  "-7b", "-123", 1, -1, -1 },
315    { "%Zx",    "0",    "0", 1, -1, -1 },
316    { "%Zx",   "7B",  "123", 1, -1, -1 },
317    { "%Zx",   "7B",  "123", 1, -1, -1 },
318    { "%Zx",   "+0",    "0", 1, -1, -1 },
319    { "%Zx",  "+7B",  "123", 1, -1, -1 },
320    { "%Zx",  "+7B",  "123", 1, -1, -1 },
321    { "%Zx",   "-0",   "-0", 1, -1, -1 },
322    { "%Zx",  "-7B", "-123", 1, -1, -1 },
323    { "%Zx",  "-7B", "-123", 1, -1, -1 },
324    { "%ZX",    "0",    "0", 1, -1, -1 },
325    { "%ZX",   "7B",  "123", 1, -1, -1 },
326    { "%ZX",   "7B",  "123", 1, -1, -1 },
327    { "%ZX",   "+0",    "0", 1, -1, -1 },
328    { "%ZX",  "+7B",  "123", 1, -1, -1 },
329    { "%ZX",  "+7B",  "123", 1, -1, -1 },
330    { "%ZX",   "-0",   "-0", 1, -1, -1 },
331    { "%ZX",  "-7B", "-123", 1, -1, -1 },
332    { "%ZX",  "-7B", "-123", 1, -1, -1 },
333
334    { "%Zi",    "0",    "0", 1, -1, -1 },
335    { "%Zi",    "1",    "1", 1, -1, -1 },
336    { "%Zi",  "123",  "123", 1, -1, -1 },
337    { "%Zi",   "+0",    "0", 1, -1, -1 },
338    { "%Zi",   "+1",    "1", 1, -1, -1 },
339    { "%Zi", "+123",  "123", 1, -1, -1 },
340    { "%Zi",   "-0",    "0", 1, -1, -1 },
341    { "%Zi",   "-1",   "-1", 1, -1, -1 },
342    { "%Zi", "-123", "-123", 1, -1, -1 },
343
344    { "%Zi",    "00",    "0", 1, -1, -1 },
345    { "%Zi",  "0173",  "123", 1, -1, -1 },
346    { "%Zi",   "+00",    "0", 1, -1, -1 },
347    { "%Zi", "+0173",  "123", 1, -1, -1 },
348    { "%Zi",   "-00",    "0", 1, -1, -1 },
349    { "%Zi", "-0173", "-123", 1, -1, -1 },
350
351    { "%Zi",    "0x0",    "0", 1, -1, -1 },
352    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
353    { "%Zi",   "0x7b",  "123", 1, -1, -1 },
354    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
355    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
356    { "%Zi",  "+0x7b",  "123", 1, -1, -1 },
357    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
358    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
359    { "%Zi",  "-0x7b", "-123", 1, -1, -1 },
360    { "%Zi",    "0X0",    "0", 1, -1, -1 },
361    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
362    { "%Zi",   "0X7b",  "123", 1, -1, -1 },
363    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
364    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
365    { "%Zi",  "+0X7b",  "123", 1, -1, -1 },
366    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
367    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
368    { "%Zi",  "-0X7b", "-123", 1, -1, -1 },
369    { "%Zi",    "0x0",    "0", 1, -1, -1 },
370    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
371    { "%Zi",   "0x7B",  "123", 1, -1, -1 },
372    { "%Zi",   "+0x0",    "0", 1, -1, -1 },
373    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
374    { "%Zi",  "+0x7B",  "123", 1, -1, -1 },
375    { "%Zi",   "-0x0",   "-0", 1, -1, -1 },
376    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
377    { "%Zi",  "-0x7B", "-123", 1, -1, -1 },
378    { "%Zi",    "0X0",    "0", 1, -1, -1 },
379    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
380    { "%Zi",   "0X7B",  "123", 1, -1, -1 },
381    { "%Zi",   "+0X0",    "0", 1, -1, -1 },
382    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
383    { "%Zi",  "+0X7B",  "123", 1, -1, -1 },
384    { "%Zi",   "-0X0",   "-0", 1, -1, -1 },
385    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
386    { "%Zi",  "-0X7B", "-123", 1, -1, -1 },
387
388    { "%Zd",    " 0",    "0", 1, -1, -1 },
389    { "%Zd",   "  0",    "0", 1, -1, -1 },
390    { "%Zd",  "   0",    "0", 1, -1, -1 },
391    { "%Zd",   "\t0",    "0", 1, -1, -1 },
392    { "%Zd", "\t\t0",    "0", 1, -1, -1 },
393
394    { "hello%Zd",      "hello0",       "0", 1, -1, -1 },
395    { "hello%Zd",      "hello 0",      "0", 1, -1, -1 },
396    { "hello%Zd",      "hello \t0",    "0", 1, -1, -1 },
397    { "hello%Zdworld", "hello 0world", "0", 1, -1, -1 },
398
399    { "hello%*Zd",      "hello0",       "-999", 0, -1, -1 },
400    { "hello%*Zd",      "hello 0",      "-999", 0, -1, -1 },
401    { "hello%*Zd",      "hello \t0",    "-999", 0, -1, -1 },
402    { "hello%*Zdworld", "hello 0world", "-999", 0, -1, -1 },
403
404    { "%Zd",    "",     "-999", -1, -1, -555 },
405    { "%Zd",    " ",    "-999", -1, -1, -555 },
406    { " %Zd",   "",     "-999", -1, -1, -555 },
407    { "xyz%Zd", "",     "-999", -1, -1, -555 },
408
409    { "%*Zd",    "",     "-999", -1, -1, -555 },
410    { " %*Zd",   "",     "-999", -1, -1, -555 },
411    { "xyz%*Zd", "",     "-999", -1, -1, -555 },
412
413    { "%Zd",    "xyz",  "0",     0, 0, -555 },
414
415    /* match something, but invalid */
416    { "%Zd",    "-",    "-999",  0, 1, -555 },
417    { "%Zd",    "+",    "-999",  0, 1, -555 },
418    { "xyz%Zd", "xyz-", "-999",  0, 4, -555 },
419    { "xyz%Zd", "xyz+", "-999",  0, 4, -555 },
420    { "%Zi",    "0x",   "-999",  0, 2, -555 },
421    { "%Zi",    "0X",   "-999",  0, 2, -555 },
422    { "%Zi",    "0x-",  "-999",  0, 2, -555 },
423    { "%Zi",    "0X+",  "-999",  0, 2, -555 },
424    { "%Zi",    "-0x",  "-999",  0, 3, -555 },
425    { "%Zi",    "-0X",  "-999",  0, 3, -555 },
426    { "%Zi",    "+0x",  "-999",  0, 3, -555 },
427    { "%Zi",    "+0X",  "-999",  0, 3, -555 },
428
429    { "%1Zi",  "1234", "1",    1, 1, 1 },
430    { "%2Zi",  "1234", "12",   1, 2, 2 },
431    { "%3Zi",  "1234", "123",  1, 3, 3 },
432    { "%4Zi",  "1234", "1234", 1, 4, 4 },
433    { "%5Zi",  "1234", "1234", 1, 4, 4 },
434    { "%6Zi",  "1234", "1234", 1, 4, 4 },
435
436    { "%1Zi",  "01234", "0",     1, 1, 1 },
437    { "%2Zi",  "01234", "01",    1, 2, 2 },
438    { "%3Zi",  "01234", "012",   1, 3, 3 },
439    { "%4Zi",  "01234", "0123",  1, 4, 4 },
440    { "%5Zi",  "01234", "01234", 1, 5, 5 },
441    { "%6Zi",  "01234", "01234", 1, 5, 5 },
442    { "%7Zi",  "01234", "01234", 1, 5, 5 },
443
444    { "%1Zi",  "0x1234", "0",      1, 1, 1 },
445    { "%2Zi",  "0x1234", "-999",   0, 2, -555 },
446    { "%3Zi",  "0x1234", "0x1",    1, 3, 3 },
447    { "%4Zi",  "0x1234", "0x12",   1, 4, 4 },
448    { "%5Zi",  "0x1234", "0x123",  1, 5, 5 },
449    { "%6Zi",  "0x1234", "0x1234", 1, 6, 6 },
450    { "%7Zi",  "0x1234", "0x1234", 1, 6, 6 },
451    { "%8Zi",  "0x1234", "0x1234", 1, 6, 6 },
452
453    { "%%xyz%Zd",  "%xyz123",  "123", 1, -1, -1 },
454    { "12%%34%Zd", "12%34567", "567", 1, -1, -1 },
455    { "%%%%%Zd",   "%%123",    "123", 1, -1, -1 },
456
457    /* various subtle EOF cases */
458    { "x",       "",    "-999", EOF, 0, -555 },
459    { " x",      "",    "-999", EOF, 0, -555 },
460    { "xyz",     "",    "-999", EOF, 0, -555 },
461    { " ",       "",    "-999",   0, 0,    0 },
462    { " ",       " ",   "-999",   0, 1,    1 },
463    { "%*Zd%Zd", "",    "-999", EOF, 0, -555 },
464    { "%*Zd%Zd", "123", "-999", EOF, 3, -555 },
465    { "x",       "x",   "-999",   0, 1,    1 },
466    { "xyz",     "x",   "-999", EOF, 1, -555 },
467    { "xyz",     "xy",  "-999", EOF, 2, -555 },
468    { "xyz",     "xyz", "-999",   0, 3,    3 },
469    { "%Zn",     "",    "0",      0, 0,    0 },
470    { " %Zn",    "",    "0",      0, 0,    0 },
471    { " x%Zn",   "",    "-999", EOF, 0, -555 },
472    { "xyz%Zn",  "",    "-999", EOF, 0, -555 },
473    { " x%Zn",   "",    "-999", EOF, 0, -555 },
474    { " %Zn x",  " ",   "-999", EOF, 1, -555 },
475
476    /* these seem to tickle a bug in glibc 2.2.4 */
477    { " x",      " ",   "-999", EOF, 1, -555, 1 },
478    { " xyz",    " ",   "-999", EOF, 1, -555, 1 },
479    { " x%Zn",   " ",   "-999", EOF, 1, -555, 1 },
480  };
481
482  int         i, j, ignore;
483  int         got_ret, want_ret, got_upto, want_upto;
484  mpz_t       got, want;
485  long        got_l, want_ftell;
486  int         error = 0;
487  fun_t       fun;
488  const char  *name;
489  char        fmt[128];
490
491  mpz_init (got);
492  mpz_init (want);
493
494  for (i = 0; i < numberof (data); i++)
495    {
496      mpz_set_str_or_abort (want, data[i].want, 0);
497
498      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
499      strcpy (fmt, data[i].fmt);
500      strcat (fmt, "%n");
501
502      ignore = fmt_allignore (fmt);
503
504      for (j = 0; j <= 3; j++)
505        {
506          want_ret = data[i].want_ret;
507
508          want_ftell = data[i].want_ftell;
509          if (want_ftell == -1)
510            want_ftell = strlen (data[i].input);
511
512          want_upto = data[i].want_upto;
513          if (want_upto == -1)
514            want_upto = strlen (data[i].input);
515
516          switch (j) {
517          case 0:
518            name = "gmp_sscanf";
519            fun = fun_gmp_sscanf;
520            break;
521          case 1:
522            name = "gmp_fscanf";
523            fun = fun_gmp_fscanf;
524            break;
525          case 2:
526#ifdef __GLIBC__
527            if (data[i].not_glibc)
528              continue;
529#endif
530            if (! libc_scanf_convert (fmt))
531              continue;
532            name = "standard sscanf";
533            fun = fun_sscanf;
534            break;
535          case 3:
536#ifdef __GLIBC__
537            if (data[i].not_glibc)
538              continue;
539#endif
540            if (! libc_scanf_convert (fmt))
541              continue;
542            name = "standard fscanf";
543            fun = fun_fscanf;
544            break;
545          default:
546            ASSERT_ALWAYS (0);
547            break;
548          }
549
550          got_upto = -555;
551          got_ftell = -1L;
552
553          switch (j) {
554          case 0:
555          case 1:
556            mpz_set_si (got, -999L);
557            if (ignore)
558              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
559            else
560              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
561            break;
562          case 2:
563          case 3:
564            got_l = -999L;
565            if (ignore)
566              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
567            else
568              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
569            mpz_set_si (got, got_l);
570            break;
571          default:
572            ASSERT_ALWAYS (0);
573            break;
574          }
575
576          MPZ_CHECK_FORMAT (got);
577
578          if (got_ret != want_ret)
579            {
580              printf ("%s wrong return value\n", name);
581              error = 1;
582            }
583          if (want_ret == 1 && mpz_cmp (want, got) != 0)
584            {
585              printf ("%s wrong result\n", name);
586              error = 1;
587            }
588          if (got_upto != want_upto)
589            {
590              printf ("%s wrong upto\n", name);
591              error = 1;
592            }
593          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
594            {
595              printf ("%s wrong ftell\n", name);
596              error = 1;
597            }
598          if (error)
599            {
600              printf    ("  fmt   \"%s\"\n", data[i].fmt);
601              printf    ("  input \"%s\"\n", data[i].input);
602              printf    ("  ignore %d\n", ignore);
603              printf    ("  ret   want=%d\n", want_ret);
604              printf    ("        got =%d\n", got_ret);
605              mpz_trace ("  value want", want);
606              mpz_trace ("        got ", got);
607              printf    ("  upto  want =%d\n", want_upto);
608              printf    ("        got  =%d\n", got_upto);
609              if (got_ftell != -1)
610                {
611                  printf    ("  ftell want =%ld\n", want_ftell);
612                  printf    ("        got  =%ld\n", got_ftell);
613                }
614              abort ();
615            }
616        }
617    }
618
619  mpz_clear (got);
620  mpz_clear (want);
621}
622
623void
624check_q (void)
625{
626  static const struct {
627    const char  *fmt;
628    const char  *input;
629    const char  *want;
630    int         ret;
631    long        ftell;
632
633  } data[] = {
634
635    { "%Qd",    "0",    "0", 1, -1 },
636    { "%Qd",    "1",    "1", 1, -1 },
637    { "%Qd",  "123",  "123", 1, -1 },
638    { "%Qd",   "+0",    "0", 1, -1 },
639    { "%Qd",   "+1",    "1", 1, -1 },
640    { "%Qd", "+123",  "123", 1, -1 },
641    { "%Qd",   "-0",    "0", 1, -1 },
642    { "%Qd",   "-1",   "-1", 1, -1 },
643    { "%Qd", "-123", "-123", 1, -1 },
644
645    { "%Qo",    "0",    "0", 1, -1 },
646    { "%Qo",  "173",  "123", 1, -1 },
647    { "%Qo",   "+0",    "0", 1, -1 },
648    { "%Qo", "+173",  "123", 1, -1 },
649    { "%Qo",   "-0",    "0", 1, -1 },
650    { "%Qo", "-173", "-123", 1, -1 },
651
652    { "%Qx",    "0",    "0", 1, -1 },
653    { "%Qx",   "7b",  "123", 1, -1 },
654    { "%Qx",   "7b",  "123", 1, -1 },
655    { "%Qx",   "+0",    "0", 1, -1 },
656    { "%Qx",  "+7b",  "123", 1, -1 },
657    { "%Qx",  "+7b",  "123", 1, -1 },
658    { "%Qx",   "-0",   "-0", 1, -1 },
659    { "%Qx",  "-7b", "-123", 1, -1 },
660    { "%Qx",  "-7b", "-123", 1, -1 },
661    { "%QX",    "0",    "0", 1, -1 },
662    { "%QX",   "7b",  "123", 1, -1 },
663    { "%QX",   "7b",  "123", 1, -1 },
664    { "%QX",   "+0",    "0", 1, -1 },
665    { "%QX",  "+7b",  "123", 1, -1 },
666    { "%QX",  "+7b",  "123", 1, -1 },
667    { "%QX",   "-0",   "-0", 1, -1 },
668    { "%QX",  "-7b", "-123", 1, -1 },
669    { "%QX",  "-7b", "-123", 1, -1 },
670    { "%Qx",    "0",    "0", 1, -1 },
671    { "%Qx",   "7B",  "123", 1, -1 },
672    { "%Qx",   "7B",  "123", 1, -1 },
673    { "%Qx",   "+0",    "0", 1, -1 },
674    { "%Qx",  "+7B",  "123", 1, -1 },
675    { "%Qx",  "+7B",  "123", 1, -1 },
676    { "%Qx",   "-0",   "-0", 1, -1 },
677    { "%Qx",  "-7B", "-123", 1, -1 },
678    { "%Qx",  "-7B", "-123", 1, -1 },
679    { "%QX",    "0",    "0", 1, -1 },
680    { "%QX",   "7B",  "123", 1, -1 },
681    { "%QX",   "7B",  "123", 1, -1 },
682    { "%QX",   "+0",    "0", 1, -1 },
683    { "%QX",  "+7B",  "123", 1, -1 },
684    { "%QX",  "+7B",  "123", 1, -1 },
685    { "%QX",   "-0",   "-0", 1, -1 },
686    { "%QX",  "-7B", "-123", 1, -1 },
687    { "%QX",  "-7B", "-123", 1, -1 },
688
689    { "%Qi",    "0",    "0", 1, -1 },
690    { "%Qi",    "1",    "1", 1, -1 },
691    { "%Qi",  "123",  "123", 1, -1 },
692    { "%Qi",   "+0",    "0", 1, -1 },
693    { "%Qi",   "+1",    "1", 1, -1 },
694    { "%Qi", "+123",  "123", 1, -1 },
695    { "%Qi",   "-0",    "0", 1, -1 },
696    { "%Qi",   "-1",   "-1", 1, -1 },
697    { "%Qi", "-123", "-123", 1, -1 },
698
699    { "%Qi",    "00",    "0", 1, -1 },
700    { "%Qi",  "0173",  "123", 1, -1 },
701    { "%Qi",   "+00",    "0", 1, -1 },
702    { "%Qi", "+0173",  "123", 1, -1 },
703    { "%Qi",   "-00",    "0", 1, -1 },
704    { "%Qi", "-0173", "-123", 1, -1 },
705
706    { "%Qi",    "0x0",    "0", 1, -1 },
707    { "%Qi",   "0x7b",  "123", 1, -1 },
708    { "%Qi",   "0x7b",  "123", 1, -1 },
709    { "%Qi",   "+0x0",    "0", 1, -1 },
710    { "%Qi",  "+0x7b",  "123", 1, -1 },
711    { "%Qi",  "+0x7b",  "123", 1, -1 },
712    { "%Qi",   "-0x0",   "-0", 1, -1 },
713    { "%Qi",  "-0x7b", "-123", 1, -1 },
714    { "%Qi",  "-0x7b", "-123", 1, -1 },
715    { "%Qi",    "0X0",    "0", 1, -1 },
716    { "%Qi",   "0X7b",  "123", 1, -1 },
717    { "%Qi",   "0X7b",  "123", 1, -1 },
718    { "%Qi",   "+0X0",    "0", 1, -1 },
719    { "%Qi",  "+0X7b",  "123", 1, -1 },
720    { "%Qi",  "+0X7b",  "123", 1, -1 },
721    { "%Qi",   "-0X0",   "-0", 1, -1 },
722    { "%Qi",  "-0X7b", "-123", 1, -1 },
723    { "%Qi",  "-0X7b", "-123", 1, -1 },
724    { "%Qi",    "0x0",    "0", 1, -1 },
725    { "%Qi",   "0x7B",  "123", 1, -1 },
726    { "%Qi",   "0x7B",  "123", 1, -1 },
727    { "%Qi",   "+0x0",    "0", 1, -1 },
728    { "%Qi",  "+0x7B",  "123", 1, -1 },
729    { "%Qi",  "+0x7B",  "123", 1, -1 },
730    { "%Qi",   "-0x0",   "-0", 1, -1 },
731    { "%Qi",  "-0x7B", "-123", 1, -1 },
732    { "%Qi",  "-0x7B", "-123", 1, -1 },
733    { "%Qi",    "0X0",    "0", 1, -1 },
734    { "%Qi",   "0X7B",  "123", 1, -1 },
735    { "%Qi",   "0X7B",  "123", 1, -1 },
736    { "%Qi",   "+0X0",    "0", 1, -1 },
737    { "%Qi",  "+0X7B",  "123", 1, -1 },
738    { "%Qi",  "+0X7B",  "123", 1, -1 },
739    { "%Qi",   "-0X0",   "-0", 1, -1 },
740    { "%Qi",  "-0X7B", "-123", 1, -1 },
741    { "%Qi",  "-0X7B", "-123", 1, -1 },
742
743    { "%Qd",    " 0",    "0", 1, -1 },
744    { "%Qd",   "  0",    "0", 1, -1 },
745    { "%Qd",  "   0",    "0", 1, -1 },
746    { "%Qd",   "\t0",    "0", 1, -1 },
747    { "%Qd", "\t\t0",    "0", 1, -1 },
748
749    { "%Qd",  "3/2",   "3/2", 1, -1 },
750    { "%Qd", "+3/2",   "3/2", 1, -1 },
751    { "%Qd", "-3/2",  "-3/2", 1, -1 },
752
753    { "%Qx",  "f/10", "15/16", 1, -1 },
754    { "%Qx",  "F/10", "15/16", 1, -1 },
755    { "%QX",  "f/10", "15/16", 1, -1 },
756    { "%QX",  "F/10", "15/16", 1, -1 },
757
758    { "%Qo",  "20/21",  "16/17", 1, -1 },
759    { "%Qo", "-20/21", "-16/17", 1, -1 },
760
761    { "%Qi",    "10/11",  "10/11", 1, -1 },
762    { "%Qi",   "+10/11",  "10/11", 1, -1 },
763    { "%Qi",   "-10/11", "-10/11", 1, -1 },
764    { "%Qi",   "010/11",   "8/11", 1, -1 },
765    { "%Qi",  "+010/11",   "8/11", 1, -1 },
766    { "%Qi",  "-010/11",  "-8/11", 1, -1 },
767    { "%Qi",  "0x10/11",  "16/11", 1, -1 },
768    { "%Qi", "+0x10/11",  "16/11", 1, -1 },
769    { "%Qi", "-0x10/11", "-16/11", 1, -1 },
770
771    { "%Qi",    "10/011",  "10/9", 1, -1 },
772    { "%Qi",   "+10/011",  "10/9", 1, -1 },
773    { "%Qi",   "-10/011", "-10/9", 1, -1 },
774    { "%Qi",   "010/011",   "8/9", 1, -1 },
775    { "%Qi",  "+010/011",   "8/9", 1, -1 },
776    { "%Qi",  "-010/011",  "-8/9", 1, -1 },
777    { "%Qi",  "0x10/011",  "16/9", 1, -1 },
778    { "%Qi", "+0x10/011",  "16/9", 1, -1 },
779    { "%Qi", "-0x10/011", "-16/9", 1, -1 },
780
781    { "%Qi",    "10/0x11",  "10/17", 1, -1 },
782    { "%Qi",   "+10/0x11",  "10/17", 1, -1 },
783    { "%Qi",   "-10/0x11", "-10/17", 1, -1 },
784    { "%Qi",   "010/0x11",   "8/17", 1, -1 },
785    { "%Qi",  "+010/0x11",   "8/17", 1, -1 },
786    { "%Qi",  "-010/0x11",  "-8/17", 1, -1 },
787    { "%Qi",  "0x10/0x11",  "16/17", 1, -1 },
788    { "%Qi", "+0x10/0x11",  "16/17", 1, -1 },
789    { "%Qi", "-0x10/0x11", "-16/17", 1, -1 },
790
791    { "hello%Qd",      "hello0",         "0", 1, -1 },
792    { "hello%Qd",      "hello 0",        "0", 1, -1 },
793    { "hello%Qd",      "hello \t0",      "0", 1, -1 },
794    { "hello%Qdworld", "hello 0world",   "0", 1, -1 },
795    { "hello%Qd",      "hello3/2",     "3/2", 1, -1 },
796
797    { "hello%*Qd",      "hello0",        "-999/121", 0, -1 },
798    { "hello%*Qd",      "hello 0",       "-999/121", 0, -1 },
799    { "hello%*Qd",      "hello \t0",     "-999/121", 0, -1 },
800    { "hello%*Qdworld", "hello 0world",  "-999/121", 0, -1 },
801    { "hello%*Qdworld", "hello3/2world", "-999/121", 0, -1 },
802
803    { "%Qd",    "",     "-999/121", -1, -1 },
804    { "%Qd",   " ",     "-999/121", -1, -1 },
805    { " %Qd",   "",     "-999/121", -1, -1 },
806    { "xyz%Qd", "",     "-999/121", -1, -1 },
807
808    { "%*Qd",    "",     "-999/121", -1, -1 },
809    { " %*Qd",   "",     "-999/121", -1, -1 },
810    { "xyz%*Qd", "",     "-999/121", -1, -1 },
811
812    /* match something, but invalid */
813    { "%Qd",    "-",     "-999/121",  0, 1 },
814    { "%Qd",    "+",     "-999/121",  0, 1 },
815    { "%Qd",    "/-",    "-999/121",  0, 1 },
816    { "%Qd",    "/+",    "-999/121",  0, 1 },
817    { "%Qd",    "-/",    "-999/121",  0, 1 },
818    { "%Qd",    "+/",    "-999/121",  0, 1 },
819    { "%Qd",    "-/-",   "-999/121",  0, 1 },
820    { "%Qd",    "-/+",   "-999/121",  0, 1 },
821    { "%Qd",    "+/+",   "-999/121",  0, 1 },
822    { "%Qd",    "/123",  "-999/121",  0, 1 },
823    { "%Qd",    "-/123", "-999/121",  0, 1 },
824    { "%Qd",    "+/123", "-999/121",  0, 1 },
825    { "%Qd",    "123/",  "-999/121",  0, 1 },
826    { "%Qd",    "123/-", "-999/121",  0, 1 },
827    { "%Qd",    "123/+", "-999/121",  0, 1 },
828    { "xyz%Qd", "xyz-",  "-999/121",  0, 4 },
829    { "xyz%Qd", "xyz+",  "-999/121",  0, 4 },
830
831    { "%1Qi",  "12/57", "1",        1, 1 },
832    { "%2Qi",  "12/57", "12",       1, 2 },
833    { "%3Qi",  "12/57", "-999/121", 0, -1 },
834    { "%4Qi",  "12/57", "12/5",     1, 4 },
835    { "%5Qi",  "12/57", "12/57",    1, 5 },
836    { "%6Qi",  "12/57", "12/57",    1, 5 },
837    { "%7Qi",  "12/57", "12/57",    1, 5 },
838
839    { "%1Qi",  "012/057", "0",        1, 1 },
840    { "%2Qi",  "012/057", "01",       1, 2 },
841    { "%3Qi",  "012/057", "012",      1, 3 },
842    { "%4Qi",  "012/057", "-999/121", 0, -1 },
843    { "%5Qi",  "012/057", "012/0",    1, 5 },
844    { "%6Qi",  "012/057", "012/5",    1, 6 },
845    { "%7Qi",  "012/057", "012/057",  1, 7 },
846    { "%8Qi",  "012/057", "012/057",  1, 7 },
847    { "%9Qi",  "012/057", "012/057",  1, 7 },
848
849    { "%1Qi",  "0x12/0x57", "0",         1, 1 },
850    { "%2Qi",  "0x12/0x57", "-999",      0, 2 },
851    { "%3Qi",  "0x12/0x57", "0x1",       1, 3 },
852    { "%4Qi",  "0x12/0x57", "0x12",      1, 4 },
853    { "%5Qi",  "0x12/0x57", "-999/121",  0, 5 },
854    { "%6Qi",  "0x12/0x57", "0x12/0",    1, 6 },
855    { "%7Qi",  "0x12/0x57", "-999/121",  0, 7 },
856    { "%8Qi",  "0x12/0x57", "0x12/0x5",  1, 8 },
857    { "%9Qi",  "0x12/0x57", "0x12/0x57", 1, 9 },
858    { "%10Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
859    { "%11Qi", "0x12/0x57", "0x12/0x57", 1, 9 },
860
861    { "%Qd",  "xyz", "0", 0, 0 },
862  };
863
864  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
865  mpq_t       got, want;
866  long        got_l, want_ftell;
867  int         error = 0;
868  fun_t       fun;
869  const char  *name;
870  char        fmt[128];
871
872  mpq_init (got);
873  mpq_init (want);
874
875  for (i = 0; i < numberof (data); i++)
876    {
877      mpq_set_str_or_abort (want, data[i].want, 0);
878
879      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
880      strcpy (fmt, data[i].fmt);
881      strcat (fmt, "%n");
882
883      ignore = (strchr (fmt, '*') != NULL);
884
885      for (j = 0; j <= 3; j++)
886        {
887          want_ret = data[i].ret;
888
889          want_ftell = data[i].ftell;
890          if (want_ftell == -1)
891            want_ftell = strlen (data[i].input);
892          want_upto = want_ftell;
893
894          if (want_ret == -1 || (want_ret == 0 && ! ignore))
895            {
896              want_ftell = -1;
897              want_upto = -555;
898            }
899
900          switch (j) {
901          case 0:
902            name = "gmp_sscanf";
903            fun = fun_gmp_sscanf;
904            break;
905          case 1:
906            name = "gmp_fscanf";
907            fun = fun_gmp_fscanf;
908            break;
909          case 2:
910            if (strchr (data[i].input, '/') != NULL)
911              continue;
912            if (! libc_scanf_convert (fmt))
913              continue;
914            name = "standard sscanf";
915            fun = fun_sscanf;
916            break;
917          case 3:
918            if (strchr (data[i].input, '/') != NULL)
919              continue;
920            if (! libc_scanf_convert (fmt))
921              continue;
922            name = "standard fscanf";
923            fun = fun_fscanf;
924            break;
925          default:
926            ASSERT_ALWAYS (0);
927            break;
928          }
929
930          got_upto = -555;
931          got_ftell = -1;
932
933          switch (j) {
934          case 0:
935          case 1:
936            mpq_set_si (got, -999L, 121L);
937            if (ignore)
938              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
939            else
940              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
941            break;
942          case 2:
943          case 3:
944            got_l = -999L;
945            if (ignore)
946              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
947            else
948              got_ret = (*fun) (data[i].input, fmt, &got_l, &got_upto);
949            mpq_set_si (got, got_l, (got_l == -999L ? 121L : 1L));
950            break;
951          default:
952            ASSERT_ALWAYS (0);
953            break;
954          }
955
956          MPZ_CHECK_FORMAT (mpq_numref (got));
957          MPZ_CHECK_FORMAT (mpq_denref (got));
958
959          if (got_ret != want_ret)
960            {
961              printf ("%s wrong return value\n", name);
962              error = 1;
963            }
964          /* use direct mpz compares, since some of the test data is
965             non-canonical and can trip ASSERTs in mpq_equal */
966          if (want_ret == 1
967              && ! (mpz_cmp (mpq_numref(want), mpq_numref(got)) == 0
968                    && mpz_cmp (mpq_denref(want), mpq_denref(got)) == 0))
969            {
970              printf ("%s wrong result\n", name);
971              error = 1;
972            }
973          if (got_upto != want_upto)
974            {
975              printf ("%s wrong upto\n", name);
976              error = 1;
977            }
978          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
979            {
980              printf ("%s wrong ftell\n", name);
981              error = 1;
982            }
983          if (error)
984            {
985              printf    ("  fmt   \"%s\"\n", data[i].fmt);
986              printf    ("  input \"%s\"\n", data[i].input);
987              printf    ("  ret   want=%d\n", want_ret);
988              printf    ("        got =%d\n", got_ret);
989              mpq_trace ("  value want", want);
990              mpq_trace ("        got ", got);
991              printf    ("  upto  want=%d\n", want_upto);
992              printf    ("        got =%d\n", got_upto);
993              if (got_ftell != -1)
994                {
995                  printf    ("  ftell want =%ld\n", want_ftell);
996                  printf    ("        got  =%ld\n", got_ftell);
997                }
998              abort ();
999            }
1000        }
1001    }
1002
1003  mpq_clear (got);
1004  mpq_clear (want);
1005}
1006
1007void
1008check_f (void)
1009{
1010  static const struct {
1011    const char  *fmt;
1012    const char  *input;
1013    const char  *want;
1014    int         ret;
1015    long        ftell;    /* or -1 for length of input string */
1016
1017  } data[] = {
1018
1019    { "%Ff",    "0",    "0", 1, -1 },
1020    { "%Fe",    "0",    "0", 1, -1 },
1021    { "%FE",    "0",    "0", 1, -1 },
1022    { "%Fg",    "0",    "0", 1, -1 },
1023    { "%FG",    "0",    "0", 1, -1 },
1024
1025    { "%Ff",  "123",    "123", 1, -1 },
1026    { "%Ff", "+123",    "123", 1, -1 },
1027    { "%Ff", "-123",   "-123", 1, -1 },
1028    { "%Ff",  "123.",   "123", 1, -1 },
1029    { "%Ff", "+123.",   "123", 1, -1 },
1030    { "%Ff", "-123.",  "-123", 1, -1 },
1031    { "%Ff",  "123.0",  "123", 1, -1 },
1032    { "%Ff", "+123.0",  "123", 1, -1 },
1033    { "%Ff", "-123.0", "-123", 1, -1 },
1034    { "%Ff",  "0123",   "123", 1, -1 },
1035    { "%Ff", "-0123",  "-123", 1, -1 },
1036
1037    { "%Ff",  "123.456e3",   "123456", 1, -1 },
1038    { "%Ff", "-123.456e3",  "-123456", 1, -1 },
1039    { "%Ff",  "123.456e+3",  "123456", 1, -1 },
1040    { "%Ff", "-123.456e+3", "-123456", 1, -1 },
1041    { "%Ff",  "123000e-3",      "123", 1, -1 },
1042    { "%Ff", "-123000e-3",     "-123", 1, -1 },
1043    { "%Ff",  "123000.e-3",     "123", 1, -1 },
1044    { "%Ff", "-123000.e-3",    "-123", 1, -1 },
1045
1046    { "%Ff",  "123.456E3",   "123456", 1, -1 },
1047    { "%Ff", "-123.456E3",  "-123456", 1, -1 },
1048    { "%Ff",  "123.456E+3",  "123456", 1, -1 },
1049    { "%Ff", "-123.456E+3", "-123456", 1, -1 },
1050    { "%Ff",  "123000E-3",      "123", 1, -1 },
1051    { "%Ff", "-123000E-3",     "-123", 1, -1 },
1052    { "%Ff",  "123000.E-3",     "123", 1, -1 },
1053    { "%Ff", "-123000.E-3",    "-123", 1, -1 },
1054
1055    { "%Ff",  ".456e3",   "456", 1, -1 },
1056    { "%Ff", "-.456e3",  "-456", 1, -1 },
1057    { "%Ff",  ".456e+3",  "456", 1, -1 },
1058    { "%Ff", "-.456e+3", "-456", 1, -1 },
1059
1060    { "%Ff",    " 0",    "0", 1, -1 },
1061    { "%Ff",   "  0",    "0", 1, -1 },
1062    { "%Ff",  "   0",    "0", 1, -1 },
1063    { "%Ff",   "\t0",    "0", 1, -1 },
1064    { "%Ff", "\t\t0",    "0", 1, -1 },
1065
1066    { "hello%Fg",      "hello0",       "0",   1, -1 },
1067    { "hello%Fg",      "hello 0",      "0",   1, -1 },
1068    { "hello%Fg",      "hello \t0",    "0",   1, -1 },
1069    { "hello%Fgworld", "hello 0world", "0",   1, -1 },
1070    { "hello%Fg",      "hello3.0",     "3.0", 1, -1 },
1071
1072    { "hello%*Fg",      "hello0",        "-999", 0, -1 },
1073    { "hello%*Fg",      "hello 0",       "-999", 0, -1 },
1074    { "hello%*Fg",      "hello \t0",     "-999", 0, -1 },
1075    { "hello%*Fgworld", "hello 0world",  "-999", 0, -1 },
1076    { "hello%*Fgworld", "hello3.0world", "-999", 0, -1 },
1077
1078    { "%Ff",     "",   "-999", -1, -1 },
1079    { "%Ff",    " ",   "-999", -1, -1 },
1080    { "%Ff",   "\t",   "-999", -1, -1 },
1081    { "%Ff",  " \t",   "-999", -1, -1 },
1082    { " %Ff",    "",   "-999", -1, -1 },
1083    { "xyz%Ff",  "",   "-999", -1, -1 },
1084
1085    { "%*Ff",    "",   "-999", -1, -1 },
1086    { " %*Ff",   "",   "-999", -1, -1 },
1087    { "xyz%*Ff", "",   "-999", -1, -1 },
1088
1089    { "%Ff",    "xyz", "0", 0 },
1090
1091    /* various non-empty but invalid */
1092    { "%Ff",    "-",      "-999",  0, 1 },
1093    { "%Ff",    "+",      "-999",  0, 1 },
1094    { "xyz%Ff", "xyz-",   "-999",  0, 4 },
1095    { "xyz%Ff", "xyz+",   "-999",  0, 4 },
1096    { "%Ff",    "-.",     "-999",  0, 2 },
1097    { "%Ff",    "+.",     "-999",  0, 2 },
1098    { "%Ff",    ".e",     "-999",  0, 1 },
1099    { "%Ff",   "-.e",     "-999",  0, 2 },
1100    { "%Ff",   "+.e",     "-999",  0, 2 },
1101    { "%Ff",    ".E",     "-999",  0, 1 },
1102    { "%Ff",   "-.E",     "-999",  0, 2 },
1103    { "%Ff",   "+.E",     "-999",  0, 2 },
1104    { "%Ff",    ".e123",  "-999",  0, 1 },
1105    { "%Ff",   "-.e123",  "-999",  0, 2 },
1106    { "%Ff",   "+.e123",  "-999",  0, 2 },
1107    { "%Ff",    "123e",   "-999",  0, 4 },
1108    { "%Ff",   "-123e",   "-999",  0, 5 },
1109    { "%Ff",    "123e-",  "-999",  0, 5 },
1110    { "%Ff",   "-123e-",  "-999",  0, 6 },
1111    { "%Ff",    "123e+",  "-999",  0, 5 },
1112    { "%Ff",   "-123e+",  "-999",  0, 6 },
1113    { "%Ff",   "123e-Z",  "-999",  0, 5 },
1114
1115    /* hex floats */
1116    { "%Ff", "0x123p0",       "291",  1, -1 },
1117    { "%Ff", "0x123P0",       "291",  1, -1 },
1118    { "%Ff", "0X123p0",       "291",  1, -1 },
1119    { "%Ff", "0X123P0",       "291",  1, -1 },
1120    { "%Ff", "-0x123p0",     "-291",  1, -1 },
1121    { "%Ff", "+0x123p0",      "291",  1, -1 },
1122    { "%Ff", "0x123.p0",      "291",  1, -1 },
1123    { "%Ff", "0x12.3p4",      "291",  1, -1 },
1124    { "%Ff", "-0x12.3p4",    "-291",  1, -1 },
1125    { "%Ff", "+0x12.3p4",     "291",  1, -1 },
1126    { "%Ff", "0x1230p-4",     "291",  1, -1 },
1127    { "%Ff", "-0x1230p-4",   "-291",  1, -1 },
1128    { "%Ff", "+0x1230p-4",    "291",  1, -1 },
1129    { "%Ff", "+0x.1230p12",   "291",  1, -1 },
1130    { "%Ff", "+0x123000p-12", "291",  1, -1 },
1131    { "%Ff", "0x123 p12",     "291",  1, 5 },
1132    { "%Ff", "0x9 9",           "9",  1, 3 },
1133    { "%Ff", "0x01",            "1",  1, 4 },
1134    { "%Ff", "0x23",           "35",  1, 4 },
1135    { "%Ff", "0x45",           "69",  1, 4 },
1136    { "%Ff", "0x67",          "103",  1, 4 },
1137    { "%Ff", "0x89",          "137",  1, 4 },
1138    { "%Ff", "0xAB",          "171",  1, 4 },
1139    { "%Ff", "0xCD",          "205",  1, 4 },
1140    { "%Ff", "0xEF",          "239",  1, 4 },
1141    { "%Ff", "0xab",          "171",  1, 4 },
1142    { "%Ff", "0xcd",          "205",  1, 4 },
1143    { "%Ff", "0xef",          "239",  1, 4 },
1144    { "%Ff", "0x100p0A",      "256",  1, 7 },
1145    { "%Ff", "0x1p9",         "512",  1, -1 },
1146
1147    /* invalid hex floats */
1148    { "%Ff", "0x",     "-999",  0, 2 },
1149    { "%Ff", "-0x",    "-999",  0, 3 },
1150    { "%Ff", "+0x",    "-999",  0, 3 },
1151    { "%Ff", "0x-",    "-999",  0, 2 },
1152    { "%Ff", "0x+",    "-999",  0, 2 },
1153    { "%Ff", "0x.",    "-999",  0, 3 },
1154    { "%Ff", "-0x.",   "-999",  0, 4 },
1155    { "%Ff", "+0x.",   "-999",  0, 4 },
1156    { "%Ff", "0x.p",   "-999",  0, 3 },
1157    { "%Ff", "-0x.p",  "-999",  0, 4 },
1158    { "%Ff", "+0x.p",  "-999",  0, 4 },
1159    { "%Ff", "0x.P",   "-999",  0, 3 },
1160    { "%Ff", "-0x.P",  "-999",  0, 4 },
1161    { "%Ff", "+0x.P",  "-999",  0, 4 },
1162    { "%Ff", ".p123",  "-999",  0, 1 },
1163    { "%Ff", "-.p123", "-999",  0, 2 },
1164    { "%Ff", "+.p123", "-999",  0, 2 },
1165    { "%Ff", "0x1p",   "-999",  0, 4 },
1166    { "%Ff", "0x1p-",  "-999",  0, 5 },
1167    { "%Ff", "0x1p+",  "-999",  0, 5 },
1168    { "%Ff", "0x123p 12", "291",  0, 6 },
1169    { "%Ff", "0x 123p12", "291",  0, 2 },
1170
1171  };
1172
1173  int         i, j, ignore, got_ret, want_ret, got_upto, want_upto;
1174  mpf_t       got, want;
1175  double      got_d;
1176  long        want_ftell;
1177  int         error = 0;
1178  fun_t       fun;
1179  const char  *name;
1180  char        fmt[128];
1181
1182  mpf_init (got);
1183  mpf_init (want);
1184
1185  for (i = 0; i < numberof (data); i++)
1186    {
1187      mpf_set_str_or_abort (want, data[i].want, 10);
1188
1189      ASSERT_ALWAYS (strlen (data[i].fmt) + 2 < sizeof (fmt));
1190      strcpy (fmt, data[i].fmt);
1191      strcat (fmt, "%n");
1192
1193      ignore = (strchr (fmt, '*') != NULL);
1194
1195      for (j = 0; j <= 3; j++)
1196        {
1197          want_ret = data[i].ret;
1198
1199          want_ftell = data[i].ftell;
1200          if (want_ftell == -1)
1201            want_ftell = strlen (data[i].input);
1202          want_upto = want_ftell;
1203
1204          if (want_ret == -1 || (want_ret == 0 && ! ignore))
1205            want_upto = -555;
1206
1207          switch (j) {
1208          case 0:
1209            name = "gmp_sscanf";
1210            fun = fun_gmp_sscanf;
1211            break;
1212          case 1:
1213            name = "gmp_fscanf";
1214            fun = fun_gmp_fscanf;
1215            break;
1216          case 2:
1217            if (! libc_scanf_convert (fmt))
1218              continue;
1219            name = "standard sscanf";
1220            fun = fun_sscanf;
1221            break;
1222          case 3:
1223            if (! libc_scanf_convert (fmt))
1224              continue;
1225            name = "standard fscanf";
1226            fun = fun_fscanf;
1227            break;
1228          default:
1229            ASSERT_ALWAYS (0);
1230            break;
1231          }
1232
1233          got_upto = -555;
1234          got_ftell = -1;
1235
1236          switch (j) {
1237          case 0:
1238          case 1:
1239            mpf_set_si (got, -999L);
1240            if (ignore)
1241              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
1242            else
1243              got_ret = (*fun) (data[i].input, fmt, got, &got_upto);
1244            break;
1245          case 2:
1246          case 3:
1247            got_d = -999L;
1248            if (ignore)
1249              got_ret = (*fun) (data[i].input, fmt, &got_upto, NULL);
1250            else
1251              got_ret = (*fun) (data[i].input, fmt, &got_d, &got_upto);
1252            mpf_set_d (got, got_d);
1253            break;
1254          default:
1255            ASSERT_ALWAYS (0);
1256            break;
1257          }
1258
1259          MPF_CHECK_FORMAT (got);
1260
1261          if (got_ret != want_ret)
1262            {
1263              printf ("%s wrong return value\n", name);
1264              error = 1;
1265            }
1266          if (want_ret == 1 && mpf_cmp (want, got) != 0)
1267            {
1268              printf ("%s wrong result\n", name);
1269              error = 1;
1270            }
1271          if (got_upto != want_upto)
1272            {
1273              printf ("%s wrong upto\n", name);
1274              error = 1;
1275            }
1276          if (got_ftell != -1 && want_ftell != -1 && got_ftell != want_ftell)
1277            {
1278              printf ("%s wrong ftell\n", name);
1279              error = 1;
1280            }
1281          if (error)
1282            {
1283              printf    ("  fmt   \"%s\"\n", data[i].fmt);
1284              printf    ("  input \"%s\"\n", data[i].input);
1285              printf    ("  ret   want=%d\n", want_ret);
1286              printf    ("        got =%d\n", got_ret);
1287              mpf_trace ("  value want", want);
1288              mpf_trace ("        got ", got);
1289              printf    ("  upto  want=%d\n", want_upto);
1290              printf    ("        got =%d\n", got_upto);
1291              if (got_ftell != -1)
1292                {
1293                  printf    ("  ftell want =%ld\n", want_ftell);
1294                  printf    ("        got  =%ld\n", got_ftell);
1295                }
1296              abort ();
1297            }
1298        }
1299    }
1300
1301  mpf_clear (got);
1302  mpf_clear (want);
1303}
1304
1305
1306void
1307check_n (void)
1308{
1309  int    ret;
1310
1311  /* %n suppressed */
1312  {
1313    int n = 123;
1314    gmp_sscanf ("   ", " %*n", &n);
1315    ASSERT_ALWAYS (n == 123);
1316  }
1317  {
1318    int n = 123;
1319    fromstring_gmp_fscanf ("   ", " %*n", &n);
1320    ASSERT_ALWAYS (n == 123);
1321  }
1322
1323
1324#define CHECK_N(type, string)                           \
1325  do {                                                  \
1326    type  x[2];                                         \
1327    char  fmt[128];                                     \
1328    int   ret;                                          \
1329                                                        \
1330    x[0] = ~ (type) 0;                                  \
1331    x[1] = ~ (type) 0;                                  \
1332    sprintf (fmt, "abc%%%sn", string);                  \
1333    ret = gmp_sscanf ("abc", fmt, &x[0]);               \
1334                                                        \
1335    ASSERT_ALWAYS (ret == 0);                           \
1336                                                        \
1337    /* should write whole of x[0] and none of x[1] */   \
1338    ASSERT_ALWAYS (x[0] == 3);                          \
1339    ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
1340                                                        \
1341  } while (0)
1342
1343  CHECK_N (char,      "hh");
1344  CHECK_N (long,      "l");
1345#if HAVE_LONG_LONG
1346  CHECK_N (long long, "L");
1347#endif
1348#if HAVE_INTMAX_T
1349  CHECK_N (intmax_t,  "j");
1350#endif
1351#if HAVE_PTRDIFF_T
1352  CHECK_N (ptrdiff_t, "t");
1353#endif
1354  CHECK_N (short,     "h");
1355  CHECK_N (size_t,    "z");
1356
1357  /* %Zn */
1358  {
1359    mpz_t  x[2];
1360    mpz_init_set_si (x[0], -987L);
1361    mpz_init_set_si (x[1],  654L);
1362    ret = gmp_sscanf ("xyz   ", "xyz%Zn", x[0]);
1363    MPZ_CHECK_FORMAT (x[0]);
1364    MPZ_CHECK_FORMAT (x[1]);
1365    ASSERT_ALWAYS (ret == 0);
1366    ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
1367    ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
1368    mpz_clear (x[0]);
1369    mpz_clear (x[1]);
1370  }
1371  {
1372    mpz_t  x;
1373    mpz_init (x);
1374    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Zn", x);
1375    ASSERT_ALWAYS (ret == 0);
1376    ASSERT_ALWAYS (mpz_cmp_ui (x, 3L) == 0);
1377    mpz_clear (x);
1378  }
1379
1380  /* %Qn */
1381  {
1382    mpq_t  x[2];
1383    mpq_init (x[0]);
1384    mpq_init (x[1]);
1385    mpq_set_ui (x[0], 987L, 654L);
1386    mpq_set_ui (x[1], 4115L, 226L);
1387    ret = gmp_sscanf ("xyz   ", "xyz%Qn", x[0]);
1388    MPQ_CHECK_FORMAT (x[0]);
1389    MPQ_CHECK_FORMAT (x[1]);
1390    ASSERT_ALWAYS (ret == 0);
1391    ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
1392    ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
1393    mpq_clear (x[0]);
1394    mpq_clear (x[1]);
1395  }
1396  {
1397    mpq_t  x;
1398    mpq_init (x);
1399    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Qn", x);
1400    ASSERT_ALWAYS (ret == 0);
1401    ASSERT_ALWAYS (mpq_cmp_ui (x, 3L, 1L) == 0);
1402    mpq_clear (x);
1403  }
1404
1405  /* %Fn */
1406  {
1407    mpf_t  x[2];
1408    mpf_init (x[0]);
1409    mpf_init (x[1]);
1410    mpf_set_ui (x[0], 987L);
1411    mpf_set_ui (x[1], 654L);
1412    ret = gmp_sscanf ("xyz   ", "xyz%Fn", x[0]);
1413    MPF_CHECK_FORMAT (x[0]);
1414    MPF_CHECK_FORMAT (x[1]);
1415    ASSERT_ALWAYS (ret == 0);
1416    ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
1417    ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
1418    mpf_clear (x[0]);
1419    mpf_clear (x[1]);
1420  }
1421  {
1422    mpf_t  x;
1423    mpf_init (x);
1424    ret = fromstring_gmp_fscanf ("xyz   ", "xyz%Fn", x);
1425    ASSERT_ALWAYS (ret == 0);
1426    ASSERT_ALWAYS (mpf_cmp_ui (x, 3L) == 0);
1427    mpf_clear (x);
1428  }
1429}
1430
1431
1432void
1433check_misc (void)
1434{
1435  int  ret, cmp;
1436  {
1437    int  a=9, b=8, c=7, n=66;
1438    mpz_t  z;
1439    mpz_init (z);
1440    ret = gmp_sscanf ("1 2 3 4", "%d %d %d %Zd%n",
1441                      &a, &b, &c, z, &n);
1442    ASSERT_ALWAYS (ret == 4);
1443    ASSERT_ALWAYS (a == 1);
1444    ASSERT_ALWAYS (b == 2);
1445    ASSERT_ALWAYS (c == 3);
1446    ASSERT_ALWAYS (n == 7);
1447    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
1448    mpz_clear (z);
1449  }
1450  {
1451    int  a=9, b=8, c=7, n=66;
1452    mpz_t  z;
1453    mpz_init (z);
1454    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %d %d %Zd%n",
1455                                 &a, &b, &c, z, &n);
1456    ASSERT_ALWAYS (ret == 4);
1457    ASSERT_ALWAYS (a == 1);
1458    ASSERT_ALWAYS (b == 2);
1459    ASSERT_ALWAYS (c == 3);
1460    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
1461    ASSERT_ALWAYS (n == 7);
1462    ASSERT_ALWAYS (got_ftell == 7);
1463    mpz_clear (z);
1464  }
1465
1466  {
1467    int  a=9, n=8;
1468    mpz_t  z;
1469    mpz_init (z);
1470    ret = gmp_sscanf ("1 2 3 4", "%d %*d %*d %Zd%n", &a, z, &n);
1471    ASSERT_ALWAYS (ret == 2);
1472    ASSERT_ALWAYS (a == 1);
1473    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
1474    ASSERT_ALWAYS (n == 7);
1475    mpz_clear (z);
1476  }
1477  {
1478    int  a=9, n=8;
1479    mpz_t  z;
1480    mpz_init (z);
1481    ret = fromstring_gmp_fscanf ("1 2 3 4", "%d %*d %*d %Zd%n",
1482                                 &a, z, &n);
1483    ASSERT_ALWAYS (ret == 2);
1484    ASSERT_ALWAYS (a == 1);
1485    ASSERT_ALWAYS (mpz_cmp_ui (z, 4L) == 0);
1486    ASSERT_ALWAYS (n == 7);
1487    ASSERT_ALWAYS (got_ftell == 7);
1488    mpz_clear (z);
1489  }
1490
1491  /* EOF for no matching */
1492  {
1493    char buf[128];
1494    ret = gmp_sscanf ("   ", "%s", buf);
1495    ASSERT_ALWAYS (ret == EOF);
1496    ret = fromstring_gmp_fscanf ("   ", "%s", buf);
1497    ASSERT_ALWAYS (ret == EOF);
1498    if (option_libc_scanf)
1499      {
1500        ret = sscanf ("   ", "%s", buf);
1501        ASSERT_ALWAYS (ret == EOF);
1502        ret = fun_fscanf ("   ", "%s", buf, NULL);
1503        ASSERT_ALWAYS (ret == EOF);
1504      }
1505  }
1506
1507  /* suppressed field, then eof */
1508  {
1509    int  x;
1510    if (test_sscanf_eof_ok ())
1511      {
1512        ret = gmp_sscanf ("123", "%*d%d", &x);
1513        ASSERT_ALWAYS (ret == EOF);
1514      }
1515    ret = fromstring_gmp_fscanf ("123", "%*d%d", &x);
1516    ASSERT_ALWAYS (ret == EOF);
1517    if (option_libc_scanf)
1518      {
1519        ret = sscanf ("123", "%*d%d", &x);
1520        ASSERT_ALWAYS (ret == EOF);
1521        ret = fun_fscanf ("123", "%*d%d", &x, NULL);
1522        ASSERT_ALWAYS (ret == EOF);
1523      }
1524  }
1525  {
1526    mpz_t  x;
1527    mpz_init (x);
1528    ret = gmp_sscanf ("123", "%*Zd%Zd", x);
1529    ASSERT_ALWAYS (ret == EOF);
1530    ret = fromstring_gmp_fscanf ("123", "%*Zd%Zd", x);
1531    ASSERT_ALWAYS (ret == EOF);
1532    mpz_clear (x);
1533  }
1534
1535  /* %[...], glibc only */
1536#ifdef __GLIBC__
1537  {
1538    char  buf[128];
1539    int   n = -1;
1540    buf[0] = '\0';
1541    ret = gmp_sscanf ("abcdefgh", "%[a-d]ef%n", buf, &n);
1542    ASSERT_ALWAYS (ret == 1);
1543    cmp = strcmp (buf, "abcd");
1544    ASSERT_ALWAYS (cmp == 0);
1545    ASSERT_ALWAYS (n == 6);
1546  }
1547  {
1548    char  buf[128];
1549    int   n = -1;
1550    buf[0] = '\0';
1551    ret = gmp_sscanf ("xyza", "%[^a]a%n", buf, &n);
1552    ASSERT_ALWAYS (ret == 1);
1553    cmp = strcmp (buf, "xyz");
1554    ASSERT_ALWAYS (cmp == 0);
1555    ASSERT_ALWAYS (n == 4);
1556  }
1557  {
1558    char  buf[128];
1559    int   n = -1;
1560    buf[0] = '\0';
1561    ret = gmp_sscanf ("ab]ab]", "%[]ab]%n", buf, &n);
1562    ASSERT_ALWAYS (ret == 1);
1563    cmp = strcmp (buf, "ab]ab]");
1564    ASSERT_ALWAYS (cmp == 0);
1565    ASSERT_ALWAYS (n == 6);
1566  }
1567  {
1568    char  buf[128];
1569    int   n = -1;
1570    buf[0] = '\0';
1571    ret = gmp_sscanf ("xyzb", "%[^]ab]b%n", buf, &n);
1572    ASSERT_ALWAYS (ret == 1);
1573    cmp = strcmp (buf, "xyz");
1574    ASSERT_ALWAYS (cmp == 0);
1575    ASSERT_ALWAYS (n == 4);
1576  }
1577#endif
1578
1579  /* %zd etc won't be accepted by sscanf on old systems, and running
1580     something to see if they work might be bad, so only try it on glibc,
1581     and only on a new enough version (glibc 2.0 doesn't have %zd) */
1582#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
1583  {
1584    mpz_t   z;
1585    size_t  s = -1;
1586    mpz_init (z);
1587    ret = gmp_sscanf ("456 789", "%zd %Zd", &s, z);
1588    ASSERT_ALWAYS (ret == 2);
1589    ASSERT_ALWAYS (s == 456);
1590    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
1591    mpz_clear (z);
1592  }
1593  {
1594    mpz_t      z;
1595    ptrdiff_t  d = -1;
1596    mpz_init (z);
1597    ret = gmp_sscanf ("456 789", "%td %Zd", &d, z);
1598    ASSERT_ALWAYS (ret == 2);
1599    ASSERT_ALWAYS (d == 456);
1600    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
1601    mpz_clear (z);
1602  }
1603  {
1604    mpz_t      z;
1605    long long  ll = -1;
1606    mpz_init (z);
1607    ret = gmp_sscanf ("456 789", "%Ld %Zd", &ll, z);
1608    ASSERT_ALWAYS (ret == 2);
1609    ASSERT_ALWAYS (ll == 456);
1610    ASSERT_ALWAYS (mpz_cmp_ui (z, 789L) == 0);
1611    mpz_clear (z);
1612  }
1613#endif
1614}
1615
1616int
1617main (int argc, char *argv[])
1618{
1619  if (argc > 1 && strcmp (argv[1], "-s") == 0)
1620    option_libc_scanf = 1;
1621
1622  tests_start ();
1623
1624  mp_trace_base = 16;
1625
1626  check_z ();
1627  check_q ();
1628  check_f ();
1629  check_n ();
1630  check_misc ();
1631
1632  unlink (TEMPFILE);
1633  tests_end ();
1634  exit (0);
1635}
1636