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