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