1 /* Test gmp_printf and related functions. 2 3 Copyright 2001, 2002, 2003 Free Software Foundation, Inc. 4 5 This file is part of the GNU MP Library test suite. 6 7 The GNU MP Library test suite is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 3 of the License, 10 or (at your option) any later version. 11 12 The GNU MP Library test suite is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 15 Public License for more details. 16 17 You should have received a copy of the GNU General Public License along with 18 the GNU MP Library test suite. If not, see 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 64 int option_check_printf = 0; 65 66 67 #define CHECK_VFPRINTF_FILENAME "t-printf.tmp" 68 FILE *check_vfprintf_fp; 69 70 71 /* From any of the tests run here. */ 72 #define MAX_OUTPUT 1024 73 74 75 void 76 #if HAVE_STDARG 77 check_plain (const char *want, const char *fmt_orig, ...) 78 #else 79 check_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 = (char *) (*__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 150 void 151 check_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 171 void 172 check_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 209 void 210 check_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 265 void 266 check_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 287 void 288 check_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 = (char *) 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 320 void 321 #if HAVE_STDARG 322 check_one (const char *want, const char *fmt, ...) 323 #else 324 check_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 353 void 354 check_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 464 void 465 check_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 571 void 572 check_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 734 void 735 check_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 771 void 772 check_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 886 void 887 check_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 958 int 959 main (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