1/* tprintf.c -- test file for mpfr_printf and mpfr_vprintf 2 3Copyright 2008-2023 Free Software Foundation, Inc. 4Contributed by the AriC and Caramba projects, INRIA. 5 6This file is part of the GNU MPFR Library. 7 8The GNU MPFR Library is free software; you can redistribute it and/or modify 9it under the terms of the GNU Lesser General Public License as published by 10the Free Software Foundation; either version 3 of the License, or (at your 11option) any later version. 12 13The GNU MPFR Library is distributed in the hope that it will be useful, but 14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16License for more details. 17 18You should have received a copy of the GNU Lesser General Public License 19along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ 22 23/* FIXME: The output is not tested (thus coverage data are meaningless); 24 only the return value is tested (output string length). 25 Knowing the implementation, we may need only some minimal checks: 26 all the formatted output functions are based on mpfr_vasnprintf_aux 27 and full checks are done via tsprintf. */ 28 29/* Needed due to the tests on HAVE_STDARG and MPFR_USE_MINI_GMP */ 30#ifdef HAVE_CONFIG_H 31# include "config.h" 32#endif 33 34#if defined(HAVE_STDARG) && !defined(MPFR_USE_MINI_GMP) 35#include <stdarg.h> 36 37#include <stddef.h> 38#include <errno.h> 39 40#ifdef HAVE_LOCALE_H 41#include <locale.h> 42#endif 43 44#define MPFR_NEED_INTMAX_H 45#include "mpfr-test.h" 46#define STDOUT_FILENO 1 47 48#define QUOTE(X) NAME(X) 49#define NAME(X) #X 50 51/* unlike other tests, we print out errors to stderr because stdout might be 52 redirected */ 53#define check_length(num_test, var, value, var_spec) \ 54 if ((var) != (value)) \ 55 { \ 56 fprintf (stderr, "Error in test #%d: mpfr_printf printed %" \ 57 QUOTE(var_spec)" characters instead of %d\n", \ 58 (num_test), (var), (value)); \ 59 exit (1); \ 60 } 61 62#define check_length_with_cmp(num_test, var, value, cmp, var_spec) \ 63 if (cmp != 0) \ 64 { \ 65 mpfr_fprintf (stderr, "Error in test #%d, mpfr_printf printed %" \ 66 QUOTE(var_spec)" characters instead of %d\n", \ 67 (num_test), (var), (value)); \ 68 exit (1); \ 69 } 70 71/* limit for random precision in random() */ 72const int prec_max_printf = 5000; 73/* boolean: is stdout redirected to a file ? */ 74int stdout_redirect; 75 76static void 77check (const char *fmt, mpfr_ptr x) 78{ 79 if (mpfr_printf (fmt, x) == -1) 80 { 81 fprintf (stderr, "Error 1 in mpfr_printf(\"%s\", ...)\n", fmt); 82 83 exit (1); 84 } 85 putchar ('\n'); 86} 87 88static void 89check_vprintf (const char *fmt, ...) 90{ 91 va_list ap; 92 93 va_start (ap, fmt); 94 if (mpfr_vprintf (fmt, ap) == -1) 95 { 96 fprintf (stderr, "Error 2 in mpfr_vprintf(\"%s\", ...)\n", fmt); 97 98 va_end (ap); 99 exit (1); 100 } 101 putchar ('\n'); 102 va_end (ap); 103} 104 105static unsigned int 106check_vprintf_failure (const char *fmt, ...) 107{ 108 va_list ap; 109 int r, e; 110 111 va_start (ap, fmt); 112 errno = 0; 113 r = mpfr_vprintf (fmt, ap); 114 e = errno; 115 va_end (ap); 116 117 if (r != -1 118#ifdef EOVERFLOW 119 || e != EOVERFLOW 120#endif 121 ) 122 { 123 putchar ('\n'); 124 fprintf (stderr, "Error 3 in mpfr_vprintf(\"%s\", ...)\n" 125 "Got r = %d, errno = %d\n", fmt, r, e); 126 return 1; 127 } 128 129 putchar ('\n'); 130 return 0; 131} 132 133/* The goal of this test is to check cases where more INT_MAX characters 134 are output, in which case, it should be a failure, because like C's 135 *printf functions, the return type is int and the returned value must 136 be either the number of characters printed or a negative value. */ 137static void 138check_long_string (void) 139{ 140 /* this test is VERY expensive both in time (~1 min on core2 @ 2.40GHz) and 141 in memory (~2.5 GB) */ 142 mpfr_t x; 143 long large_prec = 2147483647; 144 size_t min_memory_limit, old_memory_limit; 145 146 old_memory_limit = tests_memory_limit; 147 148 /* With a 32-bit (4GB) address space, a realloc failure has been noticed 149 with a 2G precision (though allocating up to 4GB is possible): 150 MPFR: Can't reallocate memory (old_size=4096 new_size=2147487744) 151 The implementation might be improved to use less memory and avoid 152 this problem. In the mean time, let's choose a smaller precision, 153 but this will generally have the effect to disable the test. */ 154 if (sizeof (void *) == 4) 155 large_prec /= 2; 156 157 /* We assume that the precision won't be increased internally. */ 158 if (large_prec > MPFR_PREC_MAX) 159 large_prec = MPFR_PREC_MAX; 160 161 /* Increase tests_memory_limit if need be in order to avoid an 162 obvious failure due to insufficient memory. Note that such an 163 increase is necessary, but is not guaranteed to be sufficient 164 in all cases (e.g. with logging activated). */ 165 min_memory_limit = large_prec / MPFR_BYTES_PER_MP_LIMB; 166 if (min_memory_limit > (size_t) -1 / 32) 167 min_memory_limit = (size_t) -1; 168 else 169 min_memory_limit *= 32; 170 if (tests_memory_limit > 0 && tests_memory_limit < min_memory_limit) 171 tests_memory_limit = min_memory_limit; 172 173 mpfr_init2 (x, large_prec); 174 175 mpfr_set_ui (x, 1, MPFR_RNDN); 176 mpfr_nextabove (x); 177 178 if (large_prec >= INT_MAX - 512) 179 { 180 unsigned int err = 0; 181 182#define LS1 "%Rb %512d" 183#define LS2 "%RA %RA %Ra %Ra %512d" 184 185 err |= check_vprintf_failure (LS1, x, 1); 186 err |= check_vprintf_failure (LS2, x, x, x, x, 1); 187 188 if (sizeof (long) * CHAR_BIT > 40) 189 { 190 long n1, n2; 191 192 n1 = large_prec + 517; 193 n2 = -17; 194 err |= check_vprintf_failure (LS1 "%ln", x, 1, &n2); 195 if (n1 != n2) 196 { 197 fprintf (stderr, "Error in check_long_string(\"%s\", ...)\n" 198 "Expected n = %ld\n" 199 "Got n = %ld\n", 200 LS1 "%ln", n1, n2); 201 err = 1; 202 } 203 n1 = ((large_prec - 2) / 4) * 4 + 548; 204 n2 = -17; 205 err |= check_vprintf_failure (LS2 "%ln", x, x, x, x, 1, &n2); 206 if (n1 != n2) 207 { 208 fprintf (stderr, "Error in check_long_string(\"%s\", ...)\n" 209 "Expected n = %ld\n" 210 "Got n = %ld\n", 211 LS2 "%ln", n1, n2); 212 err = 1; 213 } 214 } 215 216 if (err) 217 exit (1); 218 } 219 220 mpfr_clear (x); 221 tests_memory_limit = old_memory_limit; 222} 223 224static void 225check_special (void) 226{ 227 mpfr_t x; 228 229 mpfr_init (x); 230 231 mpfr_set_inf (x, 1); 232 check ("%Ra", x); 233 check ("%Rb", x); 234 check ("%Re", x); 235 check ("%Rf", x); 236 check ("%Rg", x); 237 check_vprintf ("%Ra", x); 238 check_vprintf ("%Rb", x); 239 check_vprintf ("%Re", x); 240 check_vprintf ("%Rf", x); 241 check_vprintf ("%Rg", x); 242 243 mpfr_set_inf (x, -1); 244 check ("%Ra", x); 245 check ("%Rb", x); 246 check ("%Re", x); 247 check ("%Rf", x); 248 check ("%Rg", x); 249 check_vprintf ("%Ra", x); 250 check_vprintf ("%Rb", x); 251 check_vprintf ("%Re", x); 252 check_vprintf ("%Rf", x); 253 check_vprintf ("%Rg", x); 254 255 mpfr_set_nan (x); 256 check ("%Ra", x); 257 check ("%Rb", x); 258 check ("%Re", x); 259 check ("%Rf", x); 260 check ("%Rg", x); 261 check_vprintf ("%Ra", x); 262 check_vprintf ("%Rb", x); 263 check_vprintf ("%Re", x); 264 check_vprintf ("%Rf", x); 265 check_vprintf ("%Rg", x); 266 267 mpfr_clear (x); 268} 269 270static void 271check_mixed (void) 272{ 273 int ch = 'a'; 274#ifndef NPRINTF_HH 275 signed char sch = -1; 276 unsigned char uch = 1; 277#endif 278 short sh = -1; 279 unsigned short ush = 1; 280 int i = -1; 281 int j = 1; 282 unsigned int ui = 1; 283 long lo = -1; 284 unsigned long ulo = 1; 285 float f = -1.25; 286 double d = -1.25; 287#if defined(PRINTF_T) || defined(PRINTF_L) 288 long double ld = -1.25; 289#endif 290 291#ifdef PRINTF_T 292 ptrdiff_t p = 1, saved_p; 293#endif 294 size_t sz = 1; 295 296 mpz_t mpz; 297 mpq_t mpq; 298 mpf_t mpf; 299 mpfr_rnd_t rnd = MPFR_RNDN; 300 301 mpfr_t mpfr; 302 mpfr_prec_t prec; 303 304 mpz_init (mpz); 305 mpz_set_ui (mpz, ulo); 306 mpq_init (mpq); 307 mpq_set_si (mpq, lo, ulo); 308 mpf_init (mpf); 309 mpf_set_q (mpf, mpq); 310 mpfr_init (mpfr); 311 mpfr_set_f (mpfr, mpf, MPFR_RNDN); 312 prec = mpfr_get_prec (mpfr); 313 314 check_vprintf ("a. %Ra, b. %u, c. %lx%n", mpfr, ui, ulo, &j); 315 check_length (1, j, 22, d); 316 check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo); 317 check_length (2, ulo, 36, lu); 318 check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush); 319 check_length (3, ush, 46, hu); 320 check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i); 321 check_length (4, i, 29, d); 322 check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz); 323 check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C90 */ 324 check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz); 325 check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi); 326 check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p", 327 mpfr, mpq, &mpfr, (void *) &i); 328 check_length_with_cmp (7, mpfr, 15, mpfr_cmp_ui (mpfr, 15), Rg); 329 330#ifdef PRINTF_T 331 saved_p = p; 332 check_vprintf ("%% a. %RNg, b. %Qx, c. %td%tn", mpfr, mpq, p, &p); 333 if (p != 20) 334 { 335 mpfr_fprintf (stderr, "Error in test 8, got '%% a. %RNg, b. %Qx, c. %td'\n", mpfr, mpq, saved_p); 336#if defined(__MINGW32__) || defined(__MINGW64__) 337 fprintf (stderr, 338 "Your MinGW may be too old, in which case compiling GMP\n" 339 "with -D__USE_MINGW_ANSI_STDIO might be required.\n"); 340#endif 341 } 342 check_length (8, (long) p, 20, ld); /* no format specifier '%td' in C90 */ 343#endif 344 345#ifdef PRINTF_L 346 check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz); 347 check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C90 */ 348#endif 349 350#ifndef NPRINTF_HH 351 check_vprintf ("a. %hhi, b. %Ra, c. %hhu%hhn", sch, mpfr, uch, &uch); 352 check_length (10, (unsigned int) uch, 22, u); /* no format specifier '%hhu' in C90 */ 353#endif 354 355#if defined(HAVE_LONG_LONG) && !defined(NPRINTF_LL) 356 { 357 long long llo = -1; 358 unsigned long long ullo = 1; 359 360 check_vprintf ("a. %Re, b. %llx%Qn", mpfr, ullo, &mpq); 361 check_length_with_cmp (11, mpq, 31, mpq_cmp_ui (mpq, 31, 1), Qu); 362 check_vprintf ("a. %lli, b. %Rf%lln", llo, mpfr, &ullo); 363 check_length (12, ullo, 19, llu); 364 } 365#endif 366 367#if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J) 368 { 369 intmax_t im = -1; 370 uintmax_t uim = 1; 371 372 check_vprintf ("a. %*RA, b. %ji%Fn", 10, mpfr, im, &mpf); 373 check_length_with_cmp (31, mpf, 20, mpf_cmp_ui (mpf, 20), Fg); 374 check_vprintf ("a. %.*Re, b. %jx%jn", 10, mpfr, uim, &im); 375 check_length (32, (long) im, 25, li); /* no format specifier "%ji" in C90 */ 376 } 377#endif 378 379 mpfr_clear (mpfr); 380 mpf_clear (mpf); 381 mpq_clear (mpq); 382 mpz_clear (mpz); 383} 384 385static void 386check_random (int nb_tests) 387{ 388 int i; 389 mpfr_t x; 390 mpfr_rnd_t rnd; 391 char flag[] = 392 { 393 '-', 394 '+', 395 ' ', 396 '#', 397 '0', /* no ambiguity: first zeros are flag zero*/ 398 '\'' 399 }; 400 char specifier[] = 401 { 402 'a', 403 'b', 404 'e', 405 'f', 406 'g' 407 }; 408 mpfr_exp_t old_emin, old_emax; 409 410 old_emin = mpfr_get_emin (); 411 old_emax = mpfr_get_emax (); 412 413 mpfr_init (x); 414 415 for (i = 0; i < nb_tests; ++i) 416 { 417 int ret; 418 int j, jmax; 419 int spec, prec; 420#define FMT_SIZE 13 421 char fmt[FMT_SIZE]; /* at most something like "%-+ #0'.*R*f" */ 422 char *ptr = fmt; 423 424 tests_default_random (x, 256, MPFR_EMIN_MIN, MPFR_EMAX_MAX, 0); 425 rnd = (mpfr_rnd_t) RND_RAND (); 426 427 spec = (int) (randlimb () % 5); 428 jmax = (spec == 3 || spec == 4) ? 6 : 5; /* ' flag only with %f or %g */ 429 /* advantage small precision */ 430 prec = RAND_BOOL () ? 10 : prec_max_printf; 431 prec = (int) (randlimb () % prec); 432 if (spec == 3 433 && (mpfr_get_exp (x) > prec_max_printf 434 || mpfr_get_exp (x) < -prec_max_printf)) 435 /* change style 'f' to style 'e' when number x is very large or very 436 small*/ 437 --spec; 438 439 *ptr++ = '%'; 440 for (j = 0; j < jmax; j++) 441 { 442 if (randlimb () % 3 == 0) 443 *ptr++ = flag[j]; 444 } 445 *ptr++ = '.'; 446 *ptr++ = '*'; 447 *ptr++ = 'R'; 448 *ptr++ = '*'; 449 *ptr++ = specifier[spec]; 450 *ptr = '\0'; 451 MPFR_ASSERTD (ptr - fmt < FMT_SIZE); 452 453 mpfr_printf ("mpfr_printf(\"%s\", %d, %s, %Re)\n", fmt, prec, 454 mpfr_print_rnd_mode (rnd), x); 455 ret = mpfr_printf (fmt, prec, rnd, x); 456 if (ret == -1) 457 { 458 if (spec == 3 459 && (MPFR_GET_EXP (x) > INT_MAX || MPFR_GET_EXP (x) < -INT_MAX)) 460 /* normal failure: x is too large to be output with full precision */ 461 { 462 mpfr_printf ("too large !"); 463 } 464 else 465 { 466 printf ("Error in mpfr_printf(\"%s\", %d, %s, ...)", 467 fmt, prec, mpfr_print_rnd_mode (rnd)); 468 469 if (stdout_redirect) 470 { 471 if ((fflush (stdout) == EOF) || (fclose (stdout) == EOF)) 472 { 473 perror ("check_random"); 474 exit (1); 475 } 476 } 477 exit (1); 478 } 479 } 480 putchar ('\n'); 481 } 482 483 set_emin (old_emin); 484 set_emax (old_emax); 485 486 mpfr_clear (x); 487} 488 489#if defined(HAVE_LOCALE_H) && defined(HAVE_SETLOCALE) 490 491static void 492test_locale (void) 493{ 494 const char * const tab_locale[] = { 495 "en_US", 496 "en_US.iso88591", 497 "en_US.iso885915", 498 "en_US.utf8" 499 }; 500 int i; 501 mpfr_t x; 502 int count; 503 char v[] = "99999999999999999999999.5"; 504 505 for (i = 0; i < numberof(tab_locale); i++) 506 { 507 char *s; 508 509 s = setlocale (LC_ALL, tab_locale[i]); 510 511 if (s != NULL && MPFR_THOUSANDS_SEPARATOR == ',') 512 break; 513 } 514 515 if (i == numberof(tab_locale)) 516 { 517 if (getenv ("MPFR_CHECK_LOCALES") == NULL) 518 return; 519 520 fprintf (stderr, "Cannot find a locale with ',' thousands separator.\n" 521 "Please install one of the en_US based locales.\n"); 522 exit (1); 523 } 524 525 mpfr_init2 (x, 113); 526 mpfr_set_ui (x, 10000, MPFR_RNDN); 527 528 count = mpfr_printf ("(1) 10000=%'Rg \n", x); 529 check_length (10000, count, 18, d); 530 count = mpfr_printf ("(2) 10000=%'Rf \n", x); 531 check_length (10001, count, 25, d); 532 533 mpfr_set_ui (x, 1000, MPFR_RNDN); 534 count = mpfr_printf ("(3) 1000=%'Rf \n", x); 535 check_length (10002, count, 23, d); 536 537 for (i = 1; i <= sizeof (v) - 3; i++) 538 { 539 mpfr_set_str (x, v + sizeof (v) - 3 - i, 10, MPFR_RNDN); 540 count = mpfr_printf ("(4) 10^i=%'.0Rf \n", x); 541 check_length (10002 + i, count, 12 + i + i/3, d); 542 } 543 544#define N0 20 545 546 for (i = 1; i <= N0; i++) 547 { 548 char s[N0+4]; 549 int j, rnd; 550 551 s[0] = '1'; 552 for (j = 1; j <= i; j++) 553 s[j] = '0'; 554 s[i+1] = '\0'; 555 556 mpfr_set_str (x, s, 10, MPFR_RNDN); 557 558 RND_LOOP (rnd) 559 { 560 count = mpfr_printf ("(5) 10^i=%'.0R*f \n", (mpfr_rnd_t) rnd, x); 561 check_length (11000 + 10 * i + rnd, count, 12 + i + i/3, d); 562 } 563 564 strcat (s + (i + 1), ".5"); 565 count = mpfr_printf ("(5) 10^i=%'.0Rf \n", x); 566 check_length (11000 + 10 * i + 9, count, 12 + i + i/3, d); 567 } 568 569 mpfr_set_str (x, "1000", 10, MPFR_RNDN); 570 count = mpfr_printf ("%'012.3Rg\n", x); 571 check_length (12000, count, 13, d); 572 count = mpfr_printf ("%'012.4Rg\n", x); 573 check_length (12001, count, 13, d); 574 count = mpfr_printf ("%'013.4Rg\n", x); 575 check_length (12002, count, 14, d); 576 577 mpfr_clear (x); 578} 579 580#else 581 582static void 583test_locale (void) 584{ 585 if (getenv ("MPFR_CHECK_LOCALES") != NULL) 586 { 587 fprintf (stderr, "Cannot test locales.\n"); 588 exit (1); 589 } 590} 591 592#endif 593 594int 595main (int argc, char *argv[]) 596{ 597 int N; 598 599 tests_start_mpfr (); 600 601 /* with no argument: prints to /dev/null, 602 tprintf N: prints N tests to stdout */ 603 if (argc == 1) 604 { 605 N = 1000; 606 stdout_redirect = 1; 607 if (freopen ("/dev/null", "w", stdout) == NULL) 608 { 609 /* We failed to open this device, try with a dummy file */ 610 if (freopen ("tprintf_out.txt", "w", stdout) == NULL) 611 { 612 /* Output the error message to stderr since it is not 613 a message about a wrong result in MPFR. Anyway the 614 standard output may have changed. */ 615 fprintf (stderr, "Can't open /dev/null or a temporary file\n"); 616 exit (1); 617 } 618 } 619 } 620 else 621 { 622 stdout_redirect = 0; 623 N = atoi (argv[1]); 624 } 625 626 check_special (); 627 check_mixed (); 628 629 /* expensive tests */ 630 if (getenv ("MPFR_CHECK_LARGEMEM") != NULL) 631 check_long_string(); 632 633 check_random (N); 634 635 test_locale (); 636 637 if (stdout_redirect) 638 { 639 if ((fflush (stdout) == EOF) || (fclose (stdout) == EOF)) 640 perror ("main"); 641 } 642 tests_end_mpfr (); 643 return 0; 644} 645 646#else /* HAVE_STDARG */ 647 648int 649main (void) 650{ 651 /* We have nothing to test. */ 652 return 77; 653} 654 655#endif /* HAVE_STDARG */ 656