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