blob: fdae5de1e8e196ce019e8078085cf5841bb6475f [file] [log] [blame]
Austin Schuhdace2a62020-08-18 10:56:48 -07001/* Test gmp_scanf and related functions.
2
3Copyright 2001-2004 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library test suite.
6
7The GNU MP Library test suite is free software; you can redistribute it
8and/or modify it under the terms of the GNU General Public License as
9published by the Free Software Foundation; either version 3 of the License,
10or (at your option) any later version.
11
12The GNU MP Library test suite is distributed in the hope that it will be
13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
15Public License for more details.
16
17You should have received a copy of the GNU General Public License along with
18the 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
58int option_libc_scanf = 0;
59
60typedef 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. */
67int
68test_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. */
94int
95libc_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
121long got_ftell;
122int fromstring_next_c;
123
124/* Call gmp_fscanf, reading the "input" string data provided. */
125int
126fromstring_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
151int
152fun_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
160int
161fun_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
170int
171fun_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
205int
206fun_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 */
227int
228fmt_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
247void
248check_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
604void
605check_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
988void
989check_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
1287void
1288check_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
1413void
1414check_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
1597int
1598main (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}