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