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