1 /* Test gmp_printf and related functions. 2 3 Copyright 2001-2003, 2015 Free Software Foundation, Inc. 4 5 This file is part of the GNU MP Library test suite. 6 7 The GNU MP Library test suite is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 3 of the License, 10 or (at your option) any later version. 11 12 The GNU MP Library test suite is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 15 Public License for more details. 16 17 You should have received a copy of the GNU General Public License along with 18 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ 19 20 21 /* Usage: t-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 58 int option_check_printf = 0; 59 60 61 #define CHECK_VFPRINTF_FILENAME "t-printf.tmp" 62 FILE *check_vfprintf_fp; 63 64 65 /* From any of the tests run here. */ 66 #define MAX_OUTPUT 1024 67 68 69 void 70 check_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 131 void 132 check_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 152 void 153 check_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 190 void 191 check_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 246 void 247 check_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 268 void 269 check_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 301 void 302 check_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 321 void 322 check_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 432 void 433 check_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 539 void 540 check_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 702 void 703 check_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 739 void 740 check_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 854 void 855 check_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 935 int 936 main (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