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