1/* Test gmp_printf and related functions. 2 3Copyright 2001-2003, 2015 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-printf [-s] 22 23 -s Check the data against the system printf, where possible. This is 24 only an option since we don't want to fail if the system printf is 25 faulty or strange. */ 26 27 28#include "config.h" /* needed for the HAVE_, could also move gmp incls */ 29 30#include <stdarg.h> 31#include <stddef.h> /* for ptrdiff_t */ 32#include <stdio.h> 33#include <stdlib.h> 34#include <string.h> 35 36#if HAVE_OBSTACK_VPRINTF 37#define obstack_chunk_alloc tests_allocate 38#define obstack_chunk_free tests_free_nosize 39#include <obstack.h> 40#endif 41 42#if HAVE_INTTYPES_H 43# include <inttypes.h> /* for intmax_t */ 44#else 45# if HAVE_STDINT_H 46# include <stdint.h> 47# endif 48#endif 49 50#if HAVE_UNISTD_H 51#include <unistd.h> /* for unlink */ 52#endif 53 54#include "gmp-impl.h" 55#include "tests.h" 56 57 58int option_check_printf = 0; 59 60 61#define CHECK_VFPRINTF_FILENAME "t-printf.tmp" 62FILE *check_vfprintf_fp; 63 64 65/* From any of the tests run here. */ 66#define MAX_OUTPUT 1024 67 68 69void 70check_plain (const char *want, const char *fmt_orig, ...) 71{ 72 char got[MAX_OUTPUT]; 73 int got_len, want_len; 74 size_t fmtsize; 75 char *fmt, *q; 76 const char *p; 77 va_list ap; 78 va_start (ap, fmt_orig); 79 80 if (! option_check_printf) 81 return; 82 83 fmtsize = strlen (fmt_orig) + 1; 84 fmt = (char *) (*__gmp_allocate_func) (fmtsize); 85 86 for (p = fmt_orig, q = fmt; *p != '\0'; p++) 87 { 88 switch (*p) { 89 case 'a': 90 case 'A': 91 /* The exact value of the exponent isn't guaranteed in glibc, and it 92 and gmp_printf do slightly different things, so don't compare 93 directly. */ 94 goto done; 95 case 'F': 96 if (p > fmt_orig && *(p-1) == '.') 97 goto done; /* don't test the "all digits" cases */ 98 /* discard 'F' type */ 99 break; 100 case 'Z': 101 /* transmute */ 102 *q++ = 'l'; 103 break; 104 default: 105 *q++ = *p; 106 break; 107 } 108 } 109 *q = '\0'; 110 111 want_len = strlen (want); 112 ASSERT_ALWAYS (want_len < sizeof(got)); 113 114 got_len = vsprintf (got, fmt, ap); 115 116 if (got_len != want_len || strcmp (got, want) != 0) 117 { 118 printf ("wanted data doesn't match plain vsprintf\n"); 119 printf (" fmt |%s|\n", fmt); 120 printf (" got |%s|\n", got); 121 printf (" want |%s|\n", want); 122 printf (" got_len %d\n", got_len); 123 printf (" want_len %d\n", want_len); 124 abort (); 125 } 126 127 done: 128 (*__gmp_free_func) (fmt, fmtsize); 129} 130 131void 132check_vsprintf (const char *want, const char *fmt, va_list ap) 133{ 134 char got[MAX_OUTPUT]; 135 int got_len, want_len; 136 137 want_len = strlen (want); 138 got_len = gmp_vsprintf (got, fmt, ap); 139 140 if (got_len != want_len || strcmp (got, want) != 0) 141 { 142 printf ("gmp_vsprintf wrong\n"); 143 printf (" fmt |%s|\n", fmt); 144 printf (" got |%s|\n", got); 145 printf (" want |%s|\n", want); 146 printf (" got_len %d\n", got_len); 147 printf (" want_len %d\n", want_len); 148 abort (); 149 } 150} 151 152void 153check_vfprintf (const char *want, const char *fmt, va_list ap) 154{ 155 char got[MAX_OUTPUT]; 156 int got_len, want_len, fread_len; 157 long ftell_len; 158 159 want_len = strlen (want); 160 161 rewind (check_vfprintf_fp); 162 got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap); 163 ASSERT_ALWAYS (got_len != -1); 164 ASSERT_ALWAYS (fflush (check_vfprintf_fp) == 0); 165 166 ftell_len = ftell (check_vfprintf_fp); 167 ASSERT_ALWAYS (ftell_len != -1); 168 169 rewind (check_vfprintf_fp); 170 ASSERT_ALWAYS (ftell_len <= sizeof(got)); 171 fread_len = fread (got, 1, ftell_len, check_vfprintf_fp); 172 173 if (got_len != want_len 174 || ftell_len != want_len 175 || fread_len != want_len 176 || memcmp (got, want, want_len) != 0) 177 { 178 printf ("gmp_vfprintf wrong\n"); 179 printf (" fmt |%s|\n", fmt); 180 printf (" got |%.*s|\n", fread_len, got); 181 printf (" want |%s|\n", want); 182 printf (" got_len %d\n", got_len); 183 printf (" ftell_len %ld\n", ftell_len); 184 printf (" fread_len %d\n", fread_len); 185 printf (" want_len %d\n", want_len); 186 abort (); 187 } 188} 189 190void 191check_vsnprintf (const char *want, const char *fmt, va_list ap) 192{ 193 char got[MAX_OUTPUT+1]; 194 int ret, got_len, want_len; 195 size_t bufsize; 196 197 want_len = strlen (want); 198 199 bufsize = -1; 200 for (;;) 201 { 202 /* do 0 to 5, then want-5 to want+5 */ 203 bufsize++; 204 if (bufsize > 5 && bufsize < want_len-5) 205 bufsize = want_len-5; 206 if (bufsize > want_len + 5) 207 break; 208 ASSERT_ALWAYS (bufsize+1 <= sizeof (got)); 209 210 got[bufsize] = '!'; 211 ret = gmp_vsnprintf (got, bufsize, fmt, ap); 212 213 got_len = MIN (MAX(1,bufsize)-1, want_len); 214 215 if (got[bufsize] != '!') 216 { 217 printf ("gmp_vsnprintf overwrote bufsize sentinel\n"); 218 goto error; 219 } 220 221 if (ret != want_len) 222 { 223 printf ("gmp_vsnprintf return value wrong\n"); 224 goto error; 225 } 226 227 if (bufsize > 0) 228 { 229 if (memcmp (got, want, got_len) != 0 || got[got_len] != '\0') 230 { 231 printf ("gmp_vsnprintf wrong result string\n"); 232 error: 233 printf (" fmt |%s|\n", fmt); 234 printf (" bufsize %lu\n", (unsigned long) bufsize); 235 printf (" got |%s|\n", got); 236 printf (" want |%.*s|\n", got_len, want); 237 printf (" want full |%s|\n", want); 238 printf (" ret %d\n", ret); 239 printf (" want_len %d\n", want_len); 240 abort (); 241 } 242 } 243 } 244} 245 246void 247check_vasprintf (const char *want, const char *fmt, va_list ap) 248{ 249 char *got; 250 int got_len, want_len; 251 252 want_len = strlen (want); 253 got_len = gmp_vasprintf (&got, fmt, ap); 254 255 if (got_len != want_len || strcmp (got, want) != 0) 256 { 257 printf ("gmp_vasprintf wrong\n"); 258 printf (" fmt |%s|\n", fmt); 259 printf (" got |%s|\n", got); 260 printf (" want |%s|\n", want); 261 printf (" got_len %d\n", got_len); 262 printf (" want_len %d\n", want_len); 263 abort (); 264 } 265 (*__gmp_free_func) (got, strlen(got)+1); 266} 267 268void 269check_obstack_vprintf (const char *want, const char *fmt, va_list ap) 270{ 271#if HAVE_OBSTACK_VPRINTF 272 struct obstack ob; 273 int got_len, want_len, ob_len; 274 char *got; 275 276 want_len = strlen (want); 277 278 obstack_init (&ob); 279 got_len = gmp_obstack_vprintf (&ob, fmt, ap); 280 got = (char *) obstack_base (&ob); 281 ob_len = obstack_object_size (&ob); 282 283 if (got_len != want_len 284 || ob_len != want_len 285 || memcmp (got, want, want_len) != 0) 286 { 287 printf ("gmp_obstack_vprintf wrong\n"); 288 printf (" fmt |%s|\n", fmt); 289 printf (" got |%s|\n", got); 290 printf (" want |%s|\n", want); 291 printf (" got_len %d\n", got_len); 292 printf (" ob_len %d\n", ob_len); 293 printf (" want_len %d\n", want_len); 294 abort (); 295 } 296 obstack_free (&ob, NULL); 297#endif 298} 299 300 301void 302check_one (const char *want, const char *fmt, ...) 303{ 304 va_list ap; 305 va_start (ap, fmt); 306 307 /* simplest first */ 308 check_vsprintf (want, fmt, ap); 309 check_vfprintf (want, fmt, ap); 310 check_vsnprintf (want, fmt, ap); 311 check_vasprintf (want, fmt, ap); 312 check_obstack_vprintf (want, fmt, ap); 313} 314 315 316#define hex_or_octal_p(fmt) \ 317 (strchr (fmt, 'x') != NULL \ 318 || strchr (fmt, 'X') != NULL \ 319 || strchr (fmt, 'o') != NULL) 320 321void 322check_z (void) 323{ 324 static const struct { 325 const char *fmt; 326 const char *z; 327 const char *want; 328 } data[] = { 329 { "%Zd", "0", "0" }, 330 { "%Zd", "1", "1" }, 331 { "%Zd", "123", "123" }, 332 { "%Zd", "-1", "-1" }, 333 { "%Zd", "-123", "-123" }, 334 335 { "%+Zd", "0", "+0" }, 336 { "%+Zd", "123", "+123" }, 337 { "%+Zd", "-123", "-123" }, 338 339 { "%Zx", "123", "7b" }, 340 { "%ZX", "123", "7B" }, 341 { "%Zx", "-123", "-7b" }, 342 { "%ZX", "-123", "-7B" }, 343 { "%Zo", "123", "173" }, 344 { "%Zo", "-123", "-173" }, 345 346 { "%#Zx", "0", "0" }, 347 { "%#ZX", "0", "0" }, 348 { "%#Zx", "123", "0x7b" }, 349 { "%#ZX", "123", "0X7B" }, 350 { "%#Zx", "-123", "-0x7b" }, 351 { "%#ZX", "-123", "-0X7B" }, 352 353 { "%#Zo", "0", "0" }, 354 { "%#Zo", "123", "0173" }, 355 { "%#Zo", "-123", "-0173" }, 356 357 { "%10Zd", "0", " 0" }, 358 { "%10Zd", "123", " 123" }, 359 { "%10Zd", "-123", " -123" }, 360 361 { "%-10Zd", "0", "0 " }, 362 { "%-10Zd", "123", "123 " }, 363 { "%-10Zd", "-123", "-123 " }, 364 365 { "%+10Zd", "123", " +123" }, 366 { "%+-10Zd", "123", "+123 " }, 367 { "%+10Zd", "-123", " -123" }, 368 { "%+-10Zd", "-123", "-123 " }, 369 370 { "%08Zd", "0", "00000000" }, 371 { "%08Zd", "123", "00000123" }, 372 { "%08Zd", "-123", "-0000123" }, 373 374 { "%+08Zd", "0", "+0000000" }, 375 { "%+08Zd", "123", "+0000123" }, 376 { "%+08Zd", "-123", "-0000123" }, 377 378 { "%#08Zx", "0", "00000000" }, 379 { "%#08Zx", "123", "0x00007b" }, 380 { "%#08Zx", "-123", "-0x0007b" }, 381 382 { "%+#08Zx", "0", "+0000000" }, 383 { "%+#08Zx", "123", "+0x0007b" }, 384 { "%+#08Zx", "-123", "-0x0007b" }, 385 386 { "%.0Zd", "0", "" }, 387 { "%.1Zd", "0", "0" }, 388 { "%.2Zd", "0", "00" }, 389 { "%.3Zd", "0", "000" }, 390 }; 391 392 int i, j; 393 mpz_t z; 394 char *nfmt; 395 mp_size_t nsize, zeros; 396 397 mpz_init (z); 398 399 for (i = 0; i < numberof (data); i++) 400 { 401 mpz_set_str_or_abort (z, data[i].z, 0); 402 403 /* don't try negatives or forced sign in hex or octal */ 404 if (mpz_fits_slong_p (z) 405 && ! (hex_or_octal_p (data[i].fmt) 406 && (strchr (data[i].fmt, '+') != NULL || mpz_sgn(z) < 0))) 407 { 408 check_plain (data[i].want, data[i].fmt, mpz_get_si (z)); 409 } 410 411 check_one (data[i].want, data[i].fmt, z); 412 413 /* Same again, with %N and possibly some high zero limbs */ 414 nfmt = __gmp_allocate_strdup (data[i].fmt); 415 for (j = 0; nfmt[j] != '\0'; j++) 416 if (nfmt[j] == 'Z') 417 nfmt[j] = 'N'; 418 for (zeros = 0; zeros <= 3; zeros++) 419 { 420 nsize = ABSIZ(z)+zeros; 421 MPZ_REALLOC (z, nsize); 422 nsize = (SIZ(z) >= 0 ? nsize : -nsize); 423 refmpn_zero (PTR(z)+ABSIZ(z), zeros); 424 check_one (data[i].want, nfmt, PTR(z), nsize); 425 } 426 __gmp_free_func (nfmt, strlen(nfmt)+1); 427 } 428 429 mpz_clear (z); 430} 431 432void 433check_q (void) 434{ 435 static const struct { 436 const char *fmt; 437 const char *q; 438 const char *want; 439 } data[] = { 440 { "%Qd", "0", "0" }, 441 { "%Qd", "1", "1" }, 442 { "%Qd", "123", "123" }, 443 { "%Qd", "-1", "-1" }, 444 { "%Qd", "-123", "-123" }, 445 { "%Qd", "3/2", "3/2" }, 446 { "%Qd", "-3/2", "-3/2" }, 447 448 { "%+Qd", "0", "+0" }, 449 { "%+Qd", "123", "+123" }, 450 { "%+Qd", "-123", "-123" }, 451 { "%+Qd", "5/8", "+5/8" }, 452 { "%+Qd", "-5/8", "-5/8" }, 453 454 { "%Qx", "123", "7b" }, 455 { "%QX", "123", "7B" }, 456 { "%Qx", "15/16", "f/10" }, 457 { "%QX", "15/16", "F/10" }, 458 { "%Qx", "-123", "-7b" }, 459 { "%QX", "-123", "-7B" }, 460 { "%Qx", "-15/16", "-f/10" }, 461 { "%QX", "-15/16", "-F/10" }, 462 { "%Qo", "123", "173" }, 463 { "%Qo", "-123", "-173" }, 464 { "%Qo", "16/17", "20/21" }, 465 { "%Qo", "-16/17", "-20/21" }, 466 467 { "%#Qx", "0", "0" }, 468 { "%#QX", "0", "0" }, 469 { "%#Qx", "123", "0x7b" }, 470 { "%#QX", "123", "0X7B" }, 471 { "%#Qx", "5/8", "0x5/0x8" }, 472 { "%#QX", "5/8", "0X5/0X8" }, 473 { "%#Qx", "-123", "-0x7b" }, 474 { "%#QX", "-123", "-0X7B" }, 475 { "%#Qx", "-5/8", "-0x5/0x8" }, 476 { "%#QX", "-5/8", "-0X5/0X8" }, 477 { "%#Qo", "0", "0" }, 478 { "%#Qo", "123", "0173" }, 479 { "%#Qo", "-123", "-0173" }, 480 { "%#Qo", "5/7", "05/07" }, 481 { "%#Qo", "-5/7", "-05/07" }, 482 483 /* zero denominator and showbase */ 484 { "%#10Qo", "0/0", " 0/0" }, 485 { "%#10Qd", "0/0", " 0/0" }, 486 { "%#10Qx", "0/0", " 0/0" }, 487 { "%#10Qo", "123/0", " 0173/0" }, 488 { "%#10Qd", "123/0", " 123/0" }, 489 { "%#10Qx", "123/0", " 0x7b/0" }, 490 { "%#10QX", "123/0", " 0X7B/0" }, 491 { "%#10Qo", "-123/0", " -0173/0" }, 492 { "%#10Qd", "-123/0", " -123/0" }, 493 { "%#10Qx", "-123/0", " -0x7b/0" }, 494 { "%#10QX", "-123/0", " -0X7B/0" }, 495 496 { "%10Qd", "0", " 0" }, 497 { "%-10Qd", "0", "0 " }, 498 { "%10Qd", "123", " 123" }, 499 { "%-10Qd", "123", "123 " }, 500 { "%10Qd", "-123", " -123" }, 501 { "%-10Qd", "-123", "-123 " }, 502 503 { "%+10Qd", "123", " +123" }, 504 { "%+-10Qd", "123", "+123 " }, 505 { "%+10Qd", "-123", " -123" }, 506 { "%+-10Qd", "-123", "-123 " }, 507 508 { "%08Qd", "0", "00000000" }, 509 { "%08Qd", "123", "00000123" }, 510 { "%08Qd", "-123", "-0000123" }, 511 512 { "%+08Qd", "0", "+0000000" }, 513 { "%+08Qd", "123", "+0000123" }, 514 { "%+08Qd", "-123", "-0000123" }, 515 516 { "%#08Qx", "0", "00000000" }, 517 { "%#08Qx", "123", "0x00007b" }, 518 { "%#08Qx", "-123", "-0x0007b" }, 519 520 { "%+#08Qx", "0", "+0000000" }, 521 { "%+#08Qx", "123", "+0x0007b" }, 522 { "%+#08Qx", "-123", "-0x0007b" }, 523 }; 524 525 int i; 526 mpq_t q; 527 528 mpq_init (q); 529 530 for (i = 0; i < numberof (data); i++) 531 { 532 mpq_set_str_or_abort (q, data[i].q, 0); 533 check_one (data[i].want, data[i].fmt, q); 534 } 535 536 mpq_clear (q); 537} 538 539void 540check_f (void) 541{ 542 static const struct { 543 const char *fmt; 544 const char *f; 545 const char *want; 546 547 } data[] = { 548 549 { "%Ff", "0", "0.000000" }, 550 { "%Ff", "123", "123.000000" }, 551 { "%Ff", "-123", "-123.000000" }, 552 553 { "%+Ff", "0", "+0.000000" }, 554 { "%+Ff", "123", "+123.000000" }, 555 { "%+Ff", "-123", "-123.000000" }, 556 557 { "%.0Ff", "0", "0" }, 558 { "%.0Ff", "123", "123" }, 559 { "%.0Ff", "-123", "-123" }, 560 561 { "%8.0Ff", "0", " 0" }, 562 { "%8.0Ff", "123", " 123" }, 563 { "%8.0Ff", "-123", " -123" }, 564 565 { "%08.0Ff", "0", "00000000" }, 566 { "%08.0Ff", "123", "00000123" }, 567 { "%08.0Ff", "-123", "-0000123" }, 568 569 { "%10.2Ff", "0", " 0.00" }, 570 { "%10.2Ff", "0.25", " 0.25" }, 571 { "%10.2Ff", "123.25", " 123.25" }, 572 { "%10.2Ff", "-123.25", " -123.25" }, 573 574 { "%-10.2Ff", "0", "0.00 " }, 575 { "%-10.2Ff", "0.25", "0.25 " }, 576 { "%-10.2Ff", "123.25", "123.25 " }, 577 { "%-10.2Ff", "-123.25", "-123.25 " }, 578 579 { "%.2Ff", "0.00000000000001", "0.00" }, 580 { "%.2Ff", "0.002", "0.00" }, 581 { "%.2Ff", "0.008", "0.01" }, 582 583 { "%.0Ff", "123.00000000000001", "123" }, 584 { "%.0Ff", "123.2", "123" }, 585 { "%.0Ff", "123.8", "124" }, 586 587 { "%.0Ff", "999999.9", "1000000" }, 588 { "%.0Ff", "3999999.9", "4000000" }, 589 590 { "%Fe", "0", "0.000000e+00" }, 591 { "%Fe", "1", "1.000000e+00" }, 592 { "%Fe", "123", "1.230000e+02" }, 593 594 { "%FE", "0", "0.000000E+00" }, 595 { "%FE", "1", "1.000000E+00" }, 596 { "%FE", "123", "1.230000E+02" }, 597 598 { "%Fe", "0", "0.000000e+00" }, 599 { "%Fe", "1", "1.000000e+00" }, 600 601 { "%.0Fe", "10000000000", "1e+10" }, 602 { "%.0Fe", "-10000000000", "-1e+10" }, 603 604 { "%.2Fe", "10000000000", "1.00e+10" }, 605 { "%.2Fe", "-10000000000", "-1.00e+10" }, 606 607 { "%8.0Fe", "10000000000", " 1e+10" }, 608 { "%8.0Fe", "-10000000000", " -1e+10" }, 609 610 { "%-8.0Fe", "10000000000", "1e+10 " }, 611 { "%-8.0Fe", "-10000000000", "-1e+10 " }, 612 613 { "%12.2Fe", "10000000000", " 1.00e+10" }, 614 { "%12.2Fe", "-10000000000", " -1.00e+10" }, 615 616 { "%012.2Fe", "10000000000", "00001.00e+10" }, 617 { "%012.2Fe", "-10000000000", "-0001.00e+10" }, 618 619 { "%Fg", "0", "0" }, 620 { "%Fg", "1", "1" }, 621 { "%Fg", "-1", "-1" }, 622 623 { "%.0Fg", "0", "0" }, 624 { "%.0Fg", "1", "1" }, 625 { "%.0Fg", "-1", "-1" }, 626 627 { "%.1Fg", "100", "1e+02" }, 628 { "%.2Fg", "100", "1e+02" }, 629 { "%.3Fg", "100", "100" }, 630 { "%.4Fg", "100", "100" }, 631 632 { "%Fg", "0.001", "0.001" }, 633 { "%Fg", "0.0001", "0.0001" }, 634 { "%Fg", "0.00001", "1e-05" }, 635 { "%Fg", "0.000001", "1e-06" }, 636 637 { "%.4Fg", "1.00000000000001", "1" }, 638 { "%.4Fg", "100000000000001", "1e+14" }, 639 640 { "%.4Fg", "12345678", "1.235e+07" }, 641 642 { "%Fa", "0","0x0p+0" }, 643 { "%FA", "0","0X0P+0" }, 644 645 { "%Fa", "1","0x1p+0" }, 646 { "%Fa", "65535","0xf.fffp+12" }, 647 { "%Fa", "65536","0x1p+16" }, 648 { "%F.10a", "65536","0x1.0000000000p+16" }, 649 { "%F.1a", "65535","0x1.0p+16" }, 650 { "%F.0a", "65535","0x1p+16" }, 651 652 { "%.2Ff", "0.99609375", "1.00" }, 653 { "%.Ff", "0.99609375", "0.99609375" }, 654 { "%.Fe", "0.99609375", "9.9609375e-01" }, 655 { "%.Fg", "0.99609375", "0.99609375" }, 656 { "%.20Fg", "1000000", "1000000" }, 657 { "%.Fg", "1000000", "1000000" }, 658 659 { "%#.0Ff", "1", "1." }, 660 { "%#.0Fe", "1", "1.e+00" }, 661 { "%#.0Fg", "1", "1." }, 662 663 { "%#.1Ff", "1", "1.0" }, 664 { "%#.1Fe", "1", "1.0e+00" }, 665 { "%#.1Fg", "1", "1." }, 666 667 { "%#.4Ff", "1234", "1234.0000" }, 668 { "%#.4Fe", "1234", "1.2340e+03" }, 669 { "%#.4Fg", "1234", "1234." }, 670 671 { "%#.8Ff", "1234", "1234.00000000" }, 672 { "%#.8Fe", "1234", "1.23400000e+03" }, 673 { "%#.8Fg", "1234", "1234.0000" }, 674 675 }; 676 677 int i; 678 mpf_t f; 679 double d; 680 681 mpf_init2 (f, 256L); 682 683 for (i = 0; i < numberof (data); i++) 684 { 685 if (data[i].f[0] == '0' && data[i].f[1] == 'x') 686 mpf_set_str_or_abort (f, data[i].f, 16); 687 else 688 mpf_set_str_or_abort (f, data[i].f, 10); 689 690 /* if mpf->double doesn't truncate, then expect same result */ 691 d = mpf_get_d (f); 692 if (mpf_cmp_d (f, d) == 0) 693 check_plain (data[i].want, data[i].fmt, d); 694 695 check_one (data[i].want, data[i].fmt, f); 696 } 697 698 mpf_clear (f); 699} 700 701 702void 703check_limb (void) 704{ 705 int i; 706 mp_limb_t limb; 707 mpz_t z; 708 char *s; 709 710 check_one ("0", "%Md", CNST_LIMB(0)); 711 check_one ("1", "%Md", CNST_LIMB(1)); 712 713 /* "i" many 1 bits, tested against mpz_get_str in decimal and hex */ 714 limb = 1; 715 mpz_init_set_ui (z, 1L); 716 for (i = 1; i <= GMP_LIMB_BITS; i++) 717 { 718 s = mpz_get_str (NULL, 10, z); 719 check_one (s, "%Mu", limb); 720 (*__gmp_free_func) (s, strlen (s) + 1); 721 722 s = mpz_get_str (NULL, 16, z); 723 check_one (s, "%Mx", limb); 724 (*__gmp_free_func) (s, strlen (s) + 1); 725 726 s = mpz_get_str (NULL, -16, z); 727 check_one (s, "%MX", limb); 728 (*__gmp_free_func) (s, strlen (s) + 1); 729 730 limb = 2*limb + 1; 731 mpz_mul_2exp (z, z, 1L); 732 mpz_add_ui (z, z, 1L); 733 } 734 735 mpz_clear (z); 736} 737 738 739void 740check_n (void) 741{ 742 { 743 int n = -1; 744 check_one ("blah", "%nblah", &n); 745 ASSERT_ALWAYS (n == 0); 746 } 747 748 { 749 int n = -1; 750 check_one ("hello ", "hello %n", &n); 751 ASSERT_ALWAYS (n == 6); 752 } 753 754 { 755 int n = -1; 756 check_one ("hello world", "hello %n world", &n); 757 ASSERT_ALWAYS (n == 6); 758 } 759 760#define CHECK_N(type, string) \ 761 do { \ 762 type x[2]; \ 763 char fmt[128]; \ 764 \ 765 x[0] = ~ (type) 0; \ 766 x[1] = ~ (type) 0; \ 767 sprintf (fmt, "%%d%%%sn%%d", string); \ 768 check_one ("123456", fmt, 123, &x[0], 456); \ 769 \ 770 /* should write whole of x[0] and none of x[1] */ \ 771 ASSERT_ALWAYS (x[0] == 3); \ 772 ASSERT_ALWAYS (x[1] == (type) ~ (type) 0); \ 773 \ 774 } while (0) 775 776 CHECK_N (mp_limb_t, "M"); 777 CHECK_N (char, "hh"); 778 CHECK_N (long, "l"); 779#if HAVE_LONG_LONG 780 CHECK_N (long long, "L"); 781#endif 782#if HAVE_INTMAX_T 783 CHECK_N (intmax_t, "j"); 784#endif 785#if HAVE_PTRDIFF_T 786 CHECK_N (ptrdiff_t, "t"); 787#endif 788 CHECK_N (short, "h"); 789 CHECK_N (size_t, "z"); 790 791 { 792 mpz_t x[2]; 793 mpz_init_set_si (x[0], -987L); 794 mpz_init_set_si (x[1], 654L); 795 check_one ("123456", "%d%Zn%d", 123, x[0], 456); 796 MPZ_CHECK_FORMAT (x[0]); 797 MPZ_CHECK_FORMAT (x[1]); 798 ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0); 799 ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0); 800 mpz_clear (x[0]); 801 mpz_clear (x[1]); 802 } 803 804 { 805 mpq_t x[2]; 806 mpq_init (x[0]); 807 mpq_init (x[1]); 808 mpq_set_ui (x[0], 987L, 654L); 809 mpq_set_ui (x[1], 4115L, 226L); 810 check_one ("123456", "%d%Qn%d", 123, x[0], 456); 811 MPQ_CHECK_FORMAT (x[0]); 812 MPQ_CHECK_FORMAT (x[1]); 813 ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0); 814 ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0); 815 mpq_clear (x[0]); 816 mpq_clear (x[1]); 817 } 818 819 { 820 mpf_t x[2]; 821 mpf_init (x[0]); 822 mpf_init (x[1]); 823 mpf_set_ui (x[0], 987L); 824 mpf_set_ui (x[1], 654L); 825 check_one ("123456", "%d%Fn%d", 123, x[0], 456); 826 MPF_CHECK_FORMAT (x[0]); 827 MPF_CHECK_FORMAT (x[1]); 828 ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0); 829 ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0); 830 mpf_clear (x[0]); 831 mpf_clear (x[1]); 832 } 833 834 { 835 mp_limb_t a[5]; 836 mp_limb_t a_want[numberof(a)]; 837 mp_size_t i; 838 839 a[0] = 123; 840 check_one ("blah", "bl%Nnah", a, (mp_size_t) 0); 841 ASSERT_ALWAYS (a[0] == 123); 842 843 MPN_ZERO (a_want, numberof (a_want)); 844 for (i = 1; i < numberof (a); i++) 845 { 846 check_one ("blah", "bl%Nnah", a, i); 847 a_want[0] = 2; 848 ASSERT_ALWAYS (mpn_cmp (a, a_want, i) == 0); 849 } 850 } 851} 852 853 854void 855check_misc (void) 856{ 857 mpz_t z; 858 mpf_t f; 859 860 mpz_init (z); 861 mpf_init2 (f, 128L); 862 863 check_one ("!", "%c", '!'); 864 865 check_one ("hello world", "hello %s", "world"); 866 check_one ("hello:", "%s:", "hello"); 867 mpz_set_ui (z, 0L); 868 check_one ("hello0", "%s%Zd", "hello", z, z); 869 870 { 871 static char xs[801]; 872 memset (xs, 'x', sizeof(xs)-1); 873 check_one (xs, "%s", xs); 874 } 875 { 876 char *xs; 877 xs = (char *) (*__gmp_allocate_func) (MAX_OUTPUT * 2 - 12); 878 memset (xs, '%', MAX_OUTPUT * 2 - 14); 879 xs [MAX_OUTPUT * 2 - 13] = '\0'; 880 xs [MAX_OUTPUT * 2 - 14] = 'x'; 881 check_one (xs + MAX_OUTPUT - 7, xs, NULL); 882 (*__gmp_free_func) (xs, MAX_OUTPUT * 2 - 12); 883 } 884 885 mpz_set_ui (z, 12345L); 886 check_one (" 12345", "%*Zd", 10, z); 887 check_one ("0000012345", "%0*Zd", 10, z); 888 check_one ("12345 ", "%*Zd", -10, z); 889 check_one ("12345 and 678", "%Zd and %d", z, 678); 890 check_one ("12345,1,12345,2,12345", "%Zd,%d,%Zd,%d,%Zd", z, 1, z, 2, z); 891 892 /* from the glibc info docs */ 893 mpz_set_si (z, 0L); 894 check_one ("| 0|0 | +0|+0 | 0|00000| | 00|0|", 895 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|", 896 /**/ z, z, z, z, z, z, z, z, z); 897 mpz_set_si (z, 1L); 898 check_one ("| 1|1 | +1|+1 | 1|00001| 1| 01|1|", 899 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|", 900 /**/ z, z, z, z, z, z, z, z, z); 901 mpz_set_si (z, -1L); 902 check_one ("| -1|-1 | -1|-1 | -1|-0001| -1| -01|-1|", 903 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|", 904 /**/ z, z, z, z, z, z, z, z, z); 905 mpz_set_si (z, 100000L); 906 check_one ("|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|", 907 "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|", 908 /**/ z, z, z, z, z, z, z, z, z); 909 mpz_set_si (z, 0L); 910 check_one ("| 0| 0| 0| 0| 0| 0| 00000000|", 911 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|", 912 /**/ z, z, z, z, z, z, z); 913 mpz_set_si (z, 1L); 914 check_one ("| 1| 1| 1| 01| 0x1| 0X1|0x00000001|", 915 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|", 916 /**/ z, z, z, z, z, z, z); 917 mpz_set_si (z, 100000L); 918 check_one ("|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|", 919 "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|", 920 /**/ z, z, z, z, z, z, z); 921 922 /* %zd for size_t won't be available on old systems, and running something 923 to see if it works might be bad, so only try it on glibc, and only on a 924 new enough version (glibc 2.0 doesn't have %zd) */ 925#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0) 926 mpz_set_ui (z, 789L); 927 check_one ("456 789 blah", "%zd %Zd blah", (size_t) 456, z); 928#endif 929 930 mpz_clear (z); 931 mpf_clear (f); 932} 933 934 935int 936main (int argc, char *argv[]) 937{ 938 if (argc > 1 && strcmp (argv[1], "-s") == 0) 939 option_check_printf = 1; 940 941 tests_start (); 942 check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME, "w+"); 943 ASSERT_ALWAYS (check_vfprintf_fp != NULL); 944 945 check_z (); 946 check_q (); 947 check_f (); 948 check_limb (); 949 check_n (); 950 check_misc (); 951 952 ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0); 953 unlink (CHECK_VFPRINTF_FILENAME); 954 tests_end (); 955 exit (0); 956} 957