1/* tprintf.c -- test file for mpfr_printf and mpfr_vprintf
2
3Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4Contributed by the Arenaire and Cacao projects, INRIA.
5
6The GNU MPFR Library is free software; you can redistribute it and/or modify
7it under the terms of the GNU Lesser General Public License as published by
8the Free Software Foundation; either version 3 of the License, or (at your
9option) any later version.
10
11The GNU MPFR Library is distributed in the hope that it will be useful, but
12WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14License for more details.
15
16You should have received a copy of the GNU Lesser General Public License
17along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
18http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
1951 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
20
21#if defined HAVE_STDARG
22#include <stdarg.h>
23
24#include <stdio.h>
25#include <stdlib.h>
26#include <stddef.h>
27
28#if HAVE_INTTYPES_H
29# include <inttypes.h> /* for intmax_t */
30#else
31# if HAVE_STDINT_H
32#  include <stdint.h>
33# endif
34#endif
35
36#include "mpfr-test.h"
37#define STDOUT_FILENO 1
38
39#if MPFR_VERSION >= MPFR_VERSION_NUM(2,4,0)
40
41#define QUOTE(X) NAME(X)
42#define NAME(X) #X
43
44/* unlike other tests, we print out errors to stderr because stdout might be
45   redirected */
46#define check_length(num_test, var, value, var_spec)                    \
47  if ((var) != (value))                                                 \
48    {                                                                   \
49      fprintf (stderr, "Error in test #%d: mpfr_printf printed %"       \
50               QUOTE(var_spec)" characters instead of %d\n",            \
51               (num_test), (var), (value));                             \
52      exit (1);                                                         \
53    }
54
55#define check_length_with_cmp(num_test, var, value, cmp, var_spec)      \
56  if (cmp != 0)                                                         \
57    {                                                                   \
58      mpfr_fprintf (stderr, "Error in test #%d, mpfr_printf printed %"  \
59                    QUOTE(var_spec)" characters instead of %d\n",       \
60                    (num_test), (var), (value));                        \
61      exit (1);                                                         \
62    }
63
64/* limit for random precision in random() */
65const int prec_max_printf = 5000;
66/* boolean: is stdout redirected to a file ? */
67int stdout_redirect;
68
69static void
70check (char *fmt, mpfr_t x)
71{
72  if (mpfr_printf (fmt, x) == -1)
73    {
74      fprintf (stderr, "Error in mpfr_printf(\"%s\", ...)\n", fmt);
75
76      exit (1);
77    }
78  putchar ('\n');
79}
80
81static void
82check_vprintf (char *fmt, ...)
83{
84  va_list ap;
85
86  va_start (ap, fmt);
87  if (mpfr_vprintf (fmt, ap) == -1)
88    {
89      fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt);
90
91      va_end (ap);
92      exit (1);
93    }
94  putchar ('\n');
95  va_end (ap);
96}
97
98static void
99check_vprintf_failure (char *fmt, ...)
100{
101  va_list ap;
102
103  va_start (ap, fmt);
104  if (mpfr_vprintf (fmt, ap) != -1)
105   {
106      putchar ('\n');
107      fprintf (stderr, "Error in mpfr_vprintf(\"%s\", ...)\n", fmt);
108
109      va_end (ap);
110      exit (1);
111    }
112  putchar ('\n');
113  va_end (ap);
114}
115
116static void
117check_invalid_format (void)
118{
119  int i = 0;
120
121  /* format in disorder */
122  check_vprintf_failure ("blah %l2.1d blah", i);
123  check_vprintf_failure ("blah %2.1#d blah", i);
124
125  /* incomplete format */
126  check_vprintf_failure ("%", i);
127  check_vprintf_failure ("% (missing conversion specifier)", i);
128  check_vprintf_failure ("missing conversion specifier %h", i);
129  check_vprintf_failure ("this should fail %.l because of missing conversion specifier "
130                         "(or doubling %%)", i);
131  check_vprintf_failure ("%L", i);
132  check_vprintf_failure ("%hh. ", i);
133  check_vprintf_failure ("blah %j.");
134  check_vprintf_failure ("%ll blah");
135  check_vprintf_failure ("blah%t blah");
136  check_vprintf_failure ("%z ");
137  check_vprintf_failure ("%F (missing conversion specifier)");
138  check_vprintf_failure ("%Q (missing conversion specifier)");
139  check_vprintf_failure ("%M (missing conversion specifier)");
140  check_vprintf_failure ("%N (missing conversion specifier)");
141  check_vprintf_failure ("%Z (missing conversion specifier)");
142  check_vprintf_failure ("%R (missing conversion specifier)");
143  check_vprintf_failure ("%R");
144  check_vprintf_failure ("%P (missing conversion specifier)");
145
146  /* conversion specifier with wrong length specifier */
147  check_vprintf_failure ("%ha", i);
148  check_vprintf_failure ("%hhe", i);
149  check_vprintf_failure ("%jf", i);
150  check_vprintf_failure ("%lg", i);
151  check_vprintf_failure ("%tA", i);
152  check_vprintf_failure ("%zE", i);
153  check_vprintf_failure ("%Ld", i);
154  check_vprintf_failure ("%Qf", i);
155  check_vprintf_failure ("%MG", i);
156  check_vprintf_failure ("%Na", i);
157  check_vprintf_failure ("%ZE", i);
158  check_vprintf_failure ("%PG", i);
159  check_vprintf_failure ("%Fu", i);
160  check_vprintf_failure ("%Rx", i);
161}
162
163static void
164check_long_string (void)
165{
166  /* this test is VERY expensive both in time (~1 min on core2 @ 2.40GHz) and
167     in memory (~2.5 GB) */
168  mpfr_t x;
169
170  mpfr_init2 (x, INT_MAX);
171
172  mpfr_set_ui (x, 1, MPFR_RNDN);
173  mpfr_nextabove (x);
174
175  check_vprintf_failure ("%Rb", x);
176  check_vprintf_failure ("%RA %RA %Ra %Ra", x, x, x, x);
177
178  mpfr_clear (x);
179}
180
181static void
182check_special (void)
183{
184  mpfr_t x;
185
186  mpfr_init (x);
187
188  mpfr_set_inf (x, 1);
189  check ("%Ra", x);
190  check ("%Rb", x);
191  check ("%Re", x);
192  check ("%Rf", x);
193  check ("%Rg", x);
194  check_vprintf ("%Ra", x);
195  check_vprintf ("%Rb", x);
196  check_vprintf ("%Re", x);
197  check_vprintf ("%Rf", x);
198  check_vprintf ("%Rg", x);
199
200  mpfr_set_inf (x, -1);
201  check ("%Ra", x);
202  check ("%Rb", x);
203  check ("%Re", x);
204  check ("%Rf", x);
205  check ("%Rg", x);
206  check_vprintf ("%Ra", x);
207  check_vprintf ("%Rb", x);
208  check_vprintf ("%Re", x);
209  check_vprintf ("%Rf", x);
210  check_vprintf ("%Rg", x);
211
212  mpfr_set_nan (x);
213  check ("%Ra", x);
214  check ("%Rb", x);
215  check ("%Re", x);
216  check ("%Rf", x);
217  check ("%Rg", x);
218  check_vprintf ("%Ra", x);
219  check_vprintf ("%Rb", x);
220  check_vprintf ("%Re", x);
221  check_vprintf ("%Rf", x);
222  check_vprintf ("%Rg", x);
223
224  mpfr_clear (x);
225}
226
227static void
228check_mixed (void)
229{
230  int ch = 'a';
231  signed char sch = -1;
232  unsigned char uch = 1;
233  short sh = -1;
234  unsigned short ush = 1;
235  int i = -1;
236  int j = 1;
237  unsigned int ui = 1;
238  long lo = -1;
239  unsigned long ulo = 1;
240  float f = -1.25;
241  double d = -1.25;
242  long double ld = -1.25;
243
244  ptrdiff_t p = 1, saved_p;
245  size_t sz = 1;
246
247  mpz_t mpz;
248  mpq_t mpq;
249  mpf_t mpf;
250  mpfr_rnd_t rnd = MPFR_RNDN;
251
252  mpfr_t mpfr;
253  mpfr_prec_t prec;
254
255  mpz_init (mpz);
256  mpz_set_ui (mpz, ulo);
257  mpq_init (mpq);
258  mpq_set_si (mpq, lo, ulo);
259  mpf_init (mpf);
260  mpf_set_q (mpf, mpq);
261  mpfr_init (mpfr);
262  mpfr_set_f (mpfr, mpf, MPFR_RNDN);
263  prec = mpfr_get_prec (mpfr);
264
265  check_vprintf ("a. %Ra, b. %u, c. %lx%n", mpfr, ui, ulo, &j);
266  check_length (1, j, 22, d);
267  check_vprintf ("a. %c, b. %Rb, c. %u, d. %li%ln", i, mpfr, i, lo, &ulo);
268  check_length (2, ulo, 36, lu);
269  check_vprintf ("a. %hi, b. %*f, c. %Re%hn", ush, 3, f, mpfr, &ush);
270  check_length (3, ush, 29, hu);
271  check_vprintf ("a. %hi, b. %f, c. %#.2Rf%n", sh, d, mpfr, &i);
272  check_length (4, i, 29, d);
273  check_vprintf ("a. %R*A, b. %Fe, c. %i%zn", rnd, mpfr, mpf, sz, &sz);
274  check_length (5, (unsigned long) sz, 34, lu); /* no format specifier '%zu' in C89 */
275  check_vprintf ("a. %Pu, b. %c, c. %RUG, d. %Zi%Zn", prec, ch, mpfr, mpz, &mpz);
276  check_length_with_cmp (6, mpz, 24, mpz_cmp_ui (mpz, 24), Zi);
277  check_vprintf ("%% a. %#.0RNg, b. %Qx%Rn c. %p",
278                 mpfr, mpq, &mpfr, (void *) &i);
279  check_length_with_cmp (7, mpfr, 15, mpfr_cmp_ui (mpfr, 15), Rg);
280
281#ifndef NPRINTF_T
282  saved_p = p;
283  check_vprintf ("%% a. %RNg, b. %Qx, c. %td%tn", mpfr, mpq, p, &p);
284  if (p != 20)
285    mpfr_fprintf (stderr, "Error in test 8, got '%% a. %RNg, b. %Qx, c. %td'\n", mpfr, mpq, saved_p);
286  check_length (8, (long) p, 20, ld); /* no format specifier '%td' in C89 */
287#endif
288
289#ifndef NPRINTF_L
290  check_vprintf ("a. %RA, b. %Lf, c. %QX%zn", mpfr, ld, mpq, &sz);
291  check_length (9, (unsigned long) sz, 30, lu); /* no format specifier '%zu' in C89 */
292#endif
293
294#ifndef NPRINTF_HH
295  check_vprintf ("a. %hhi, b. %Ra, c. %hhu%hhn", sch, mpfr, uch, &uch);
296  check_length (10, (unsigned int) uch, 22, u); /* no format specifier '%hhu' in C89 */
297#endif
298
299#if defined(HAVE_LONG_LONG) && !defined(NPRINTF_LL)
300  {
301    long long llo = -1;
302    unsigned long long ullo = 1;
303
304    check_vprintf ("a. %Re, b. %llx%Qn", mpfr, ullo, &mpq);
305    check_length_with_cmp (11, mpq, 16, mpq_cmp_ui (mpq, 16, 1), Qu);
306    check_vprintf ("a. %lli, b. %Rf%lln", llo, mpfr, &ullo);
307    check_length (12, ullo, 19, llu);
308  }
309#endif
310
311#if defined(_MPFR_H_HAVE_INTMAX_T) && !defined(NPRINTF_J)
312  {
313    intmax_t im = -1;
314    uintmax_t uim = 1;
315
316    check_vprintf ("a. %*RA, b. %ji%Fn", 10, mpfr, im, &mpf);
317    check_length_with_cmp (31, mpf, 20, mpf_cmp_ui (mpf, 20), Fg);
318    check_vprintf ("a. %.*Re, b. %jx%jn", 10, mpfr, uim, &im);
319    check_length (32, (long) im, 25, li); /* no format specifier "%ji" in C89 */
320  }
321#endif
322
323  mpfr_clear (mpfr);
324  mpf_clear (mpf);
325  mpq_clear (mpq);
326  mpz_clear (mpz);
327}
328
329static void
330check_random (int nb_tests)
331{
332  int i;
333  mpfr_t x;
334  mpfr_rnd_t rnd;
335  char flag[] =
336    {
337      '-',
338      '+',
339      ' ',
340      '#',
341      '0', /* no ambiguity: first zeros are flag zero*/
342      '\''
343    };
344  char specifier[] =
345    {
346      'a',
347      'b',
348      'e',
349      'f',
350      'g'
351    };
352  mpfr_exp_t old_emin, old_emax;
353
354  old_emin = mpfr_get_emin ();
355  old_emax = mpfr_get_emax ();
356
357  mpfr_init (x);
358
359  for (i = 0; i < nb_tests; ++i)
360    {
361      int ret;
362      int j, jmax;
363      int spec, prec;
364#define FMT_SIZE 13
365      char fmt[FMT_SIZE]; /* at most something like "%-+ #0'.*R*f" */
366      char *ptr = fmt;
367
368      tests_default_random (x, 256, MPFR_EMIN_MIN, MPFR_EMAX_MAX);
369      rnd = (mpfr_rnd_t) RND_RAND ();
370
371      spec = (int) (randlimb () % 5);
372      jmax = (spec == 3 || spec == 4) ? 6 : 5; /* ' flag only with %f or %g */
373      /* advantage small precision */
374      prec = (randlimb () % 2) ? 10 : prec_max_printf;
375      prec = (int) (randlimb () % prec);
376      if (spec == 3
377          && (mpfr_get_exp (x) > prec_max_printf
378              || mpfr_get_exp (x) < -prec_max_printf))
379        /*  change style 'f' to style 'e' when number x is very large or very
380            small*/
381        --spec;
382
383      *ptr++ = '%';
384      for (j = 0; j < jmax; j++)
385        {
386          if (randlimb () % 3 == 0)
387            *ptr++ = flag[j];
388        }
389      *ptr++ = '.';
390      *ptr++ = '*';
391      *ptr++ = 'R';
392      *ptr++ = '*';
393      *ptr++ = specifier[spec];
394      *ptr = '\0';
395      MPFR_ASSERTD (ptr - fmt < FMT_SIZE);
396
397      mpfr_printf ("mpfr_printf(\"%s\", %d, %s, %Re)\n", fmt, prec,
398                   mpfr_print_rnd_mode (rnd), x);
399      ret = mpfr_printf (fmt, prec, rnd, x);
400      if (ret == -1)
401        {
402          if (spec == 3
403              && (MPFR_GET_EXP (x) > INT_MAX || MPFR_GET_EXP (x) < -INT_MAX))
404            /* normal failure: x is too large to be output with full precision */
405            {
406              mpfr_printf ("too large !");
407            }
408          else
409            {
410              printf ("Error in mpfr_printf(\"%s\", %d, %s, ...)",
411                      fmt, prec, mpfr_print_rnd_mode (rnd));
412
413              if (stdout_redirect)
414                {
415                  if ((fflush (stdout) == EOF) || (fclose (stdout) == -1))
416                    {
417                      perror ("check_random");
418                      exit (1);
419                    }
420                }
421              exit (1);
422            }
423        }
424      putchar ('\n');
425    }
426
427  mpfr_set_emin (old_emin);
428  mpfr_set_emax (old_emax);
429
430  mpfr_clear (x);
431}
432
433int
434main (int argc, char *argv[])
435{
436  int N;
437
438  tests_start_mpfr ();
439
440  /* with no argument: prints to /dev/null,
441     tprintf N: prints N tests to stdout */
442  if (argc == 1)
443    {
444      N = 1000;
445      stdout_redirect = 1;
446      if (freopen ("/dev/null", "w", stdout) == NULL)
447        {
448          /* We failed to open this device, try with a dummy file */
449          if (freopen ("mpfrtest.txt", "w", stdout) == NULL)
450            {
451              /* Output the error message to stderr since it is not
452                 a message about a wrong result in MPFR. Anyway the
453                 stdandard output may have changed. */
454              fprintf (stderr, "Can't open /dev/null or a temporary file\n");
455              exit (1);
456            }
457        }
458    }
459  else
460    {
461      stdout_redirect = 0;
462      N = atoi (argv[1]);
463    }
464
465  check_invalid_format ();
466  check_special ();
467  check_mixed ();
468
469  /* expensive tests */
470  if (getenv ("MPFR_CHECK_LARGEMEM") != NULL)
471    check_long_string();
472
473  check_random (N);
474
475  if (stdout_redirect)
476    {
477      if ((fflush (stdout) == EOF) || (fclose (stdout) == -1))
478        perror ("main");
479    }
480  tests_end_mpfr ();
481  return 0;
482}
483
484#else  /* MPFR_VERSION */
485
486int
487main (void)
488{
489  printf ("Warning! Test disabled for this MPFR version.\n");
490  return 0;
491}
492
493#endif  /* MPFR_VERSION */
494
495#else  /* HAVE_STDARG */
496
497int
498main (void)
499{
500  /* We have nothing to test. */
501  return 0;
502}
503
504#endif  /* HAVE_STDARG */
505