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