Upload Tizen:Base source
[external/gmp.git] / tests / misc / t-scanf.c
1 /* Test gmp_scanf and related functions.
2
3 Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
4
5 This file is part of the GNU MP Library.
6
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along 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
64 int   option_libc_scanf = 0;
65
66 typedef 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.  */
73 int
74 test_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.  */
100 int
101 libc_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
127 long  got_ftell;
128 int   fromstring_next_c;
129
130 /* Call gmp_fscanf, reading the "input" string data provided. */
131 int
132 #if HAVE_STDARG
133 fromstring_gmp_fscanf (const char *input, const char *fmt, ...)
134 #else
135 fromstring_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
170 int
171 fun_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
179 int
180 fun_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
189 int
190 fun_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
224 int
225 fun_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 */
246 int
247 fmt_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
266 void
267 check_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
623 void
624 check_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
1007 void
1008 check_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
1306 void
1307 check_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
1432 void
1433 check_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
1616 int
1617 main (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 }