xref: /netbsd-src/external/lgpl3/gmp/dist/tests/misc/t-printf.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Test gmp_printf and related functions.
2 
3 Copyright 2001-2003 Free Software Foundation, Inc.
4 
5 This file is part of the GNU MP Library test suite.
6 
7 The GNU MP Library test suite is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 3 of the License,
10 or (at your option) any later version.
11 
12 The GNU MP Library test suite is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 Public License for more details.
16 
17 You should have received a copy of the GNU General Public License along with
18 the 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.h"
55 #include "gmp-impl.h"
56 #include "tests.h"
57 
58 
59 int   option_check_printf = 0;
60 
61 
62 #define CHECK_VFPRINTF_FILENAME  "t-printf.tmp"
63 FILE  *check_vfprintf_fp;
64 
65 
66 /* From any of the tests run here. */
67 #define MAX_OUTPUT  1024
68 
69 
70 void
71 check_plain (const char *want, const char *fmt_orig, ...)
72 {
73   char        got[MAX_OUTPUT];
74   int         got_len, want_len;
75   size_t      fmtsize;
76   char        *fmt, *q;
77   const char  *p;
78   va_list     ap;
79   va_start (ap, fmt_orig);
80 
81   if (! option_check_printf)
82     return;
83 
84   fmtsize = strlen (fmt_orig) + 1;
85   fmt = (char *) (*__gmp_allocate_func) (fmtsize);
86 
87   for (p = fmt_orig, q = fmt; *p != '\0'; p++)
88     {
89       switch (*p) {
90       case 'a':
91       case 'A':
92 	/* The exact value of the exponent isn't guaranteed in glibc, and it
93 	   and gmp_printf do slightly different things, so don't compare
94 	   directly. */
95 	goto done;
96       case 'F':
97 	if (p > fmt_orig && *(p-1) == '.')
98 	  goto done;  /* don't test the "all digits" cases */
99 	/* discard 'F' type */
100 	break;
101       case 'Z':
102 	/* transmute */
103 	*q++ = 'l';
104 	break;
105       default:
106 	*q++ = *p;
107 	break;
108       }
109     }
110   *q = '\0';
111 
112   want_len = strlen (want);
113   ASSERT_ALWAYS (want_len < sizeof(got));
114 
115   got_len = vsprintf (got, fmt, ap);
116 
117   if (got_len != want_len || strcmp (got, want) != 0)
118     {
119       printf ("wanted data doesn't match plain vsprintf\n");
120       printf ("  fmt      |%s|\n", fmt);
121       printf ("  got      |%s|\n", got);
122       printf ("  want     |%s|\n", want);
123       printf ("  got_len  %d\n", got_len);
124       printf ("  want_len %d\n", want_len);
125       abort ();
126     }
127 
128  done:
129   (*__gmp_free_func) (fmt, fmtsize);
130 }
131 
132 void
133 check_vsprintf (const char *want, const char *fmt, va_list ap)
134 {
135   char  got[MAX_OUTPUT];
136   int   got_len, want_len;
137 
138   want_len = strlen (want);
139   got_len = gmp_vsprintf (got, fmt, ap);
140 
141   if (got_len != want_len || strcmp (got, want) != 0)
142     {
143       printf ("gmp_vsprintf wrong\n");
144       printf ("  fmt      |%s|\n", fmt);
145       printf ("  got      |%s|\n", got);
146       printf ("  want     |%s|\n", want);
147       printf ("  got_len  %d\n", got_len);
148       printf ("  want_len %d\n", want_len);
149       abort ();
150     }
151 }
152 
153 void
154 check_vfprintf (const char *want, const char *fmt, va_list ap)
155 {
156   char  got[MAX_OUTPUT];
157   int   got_len, want_len, fread_len;
158   long  ftell_len;
159 
160   want_len = strlen (want);
161 
162   rewind (check_vfprintf_fp);
163   got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap);
164   ASSERT_ALWAYS (got_len != -1);
165   ASSERT_ALWAYS (fflush (check_vfprintf_fp) == 0);
166 
167   ftell_len = ftell (check_vfprintf_fp);
168   ASSERT_ALWAYS (ftell_len != -1);
169 
170   rewind (check_vfprintf_fp);
171   ASSERT_ALWAYS (ftell_len <= sizeof(got));
172   fread_len = fread (got, 1, ftell_len, check_vfprintf_fp);
173 
174   if (got_len != want_len
175       || ftell_len != want_len
176       || fread_len != want_len
177       || memcmp (got, want, want_len) != 0)
178     {
179       printf ("gmp_vfprintf wrong\n");
180       printf ("  fmt       |%s|\n", fmt);
181       printf ("  got       |%.*s|\n", fread_len, got);
182       printf ("  want      |%s|\n", want);
183       printf ("  got_len   %d\n", got_len);
184       printf ("  ftell_len %ld\n", ftell_len);
185       printf ("  fread_len %d\n", fread_len);
186       printf ("  want_len  %d\n", want_len);
187       abort ();
188     }
189 }
190 
191 void
192 check_vsnprintf (const char *want, const char *fmt, va_list ap)
193 {
194   char    got[MAX_OUTPUT+1];
195   int     ret, got_len, want_len;
196   size_t  bufsize;
197 
198   want_len = strlen (want);
199 
200   bufsize = -1;
201   for (;;)
202     {
203       /* do 0 to 5, then want-5 to want+5 */
204       bufsize++;
205       if (bufsize > 5 && bufsize < want_len-5)
206 	bufsize = want_len-5;
207       if (bufsize > want_len + 5)
208 	break;
209       ASSERT_ALWAYS (bufsize+1 <= sizeof (got));
210 
211       got[bufsize] = '!';
212       ret = gmp_vsnprintf (got, bufsize, fmt, ap);
213 
214       got_len = MIN (MAX(1,bufsize)-1, want_len);
215 
216       if (got[bufsize] != '!')
217 	{
218 	  printf ("gmp_vsnprintf overwrote bufsize sentinel\n");
219 	  goto error;
220 	}
221 
222       if (ret != want_len)
223 	{
224 	  printf ("gmp_vsnprintf return value wrong\n");
225 	  goto error;
226 	}
227 
228       if (bufsize > 0)
229 	{
230 	  if (memcmp (got, want, got_len) != 0 || got[got_len] != '\0')
231 	    {
232 	      printf ("gmp_vsnprintf wrong result string\n");
233 	    error:
234 	      printf ("  fmt       |%s|\n", fmt);
235 	      printf ("  bufsize   %lu\n", (unsigned long) bufsize);
236 	      printf ("  got       |%s|\n", got);
237 	      printf ("  want      |%.*s|\n", got_len, want);
238 	      printf ("  want full |%s|\n", want);
239 	      printf ("  ret       %d\n", ret);
240 	      printf ("  want_len  %d\n", want_len);
241 	      abort ();
242 	    }
243 	}
244     }
245 }
246 
247 void
248 check_vasprintf (const char *want, const char *fmt, va_list ap)
249 {
250   char  *got;
251   int   got_len, want_len;
252 
253   want_len = strlen (want);
254   got_len = gmp_vasprintf (&got, fmt, ap);
255 
256   if (got_len != want_len || strcmp (got, want) != 0)
257     {
258       printf ("gmp_vasprintf wrong\n");
259       printf ("  fmt      |%s|\n", fmt);
260       printf ("  got      |%s|\n", got);
261       printf ("  want     |%s|\n", want);
262       printf ("  got_len  %d\n", got_len);
263       printf ("  want_len %d\n", want_len);
264       abort ();
265     }
266   (*__gmp_free_func) (got, strlen(got)+1);
267 }
268 
269 void
270 check_obstack_vprintf (const char *want, const char *fmt, va_list ap)
271 {
272 #if HAVE_OBSTACK_VPRINTF
273   struct obstack  ob;
274   int   got_len, want_len, ob_len;
275   char  *got;
276 
277   want_len = strlen (want);
278 
279   obstack_init (&ob);
280   got_len = gmp_obstack_vprintf (&ob, fmt, ap);
281   got = (char *) obstack_base (&ob);
282   ob_len = obstack_object_size (&ob);
283 
284   if (got_len != want_len
285       || ob_len != want_len
286       || memcmp (got, want, want_len) != 0)
287     {
288       printf ("gmp_obstack_vprintf wrong\n");
289       printf ("  fmt      |%s|\n", fmt);
290       printf ("  got      |%s|\n", got);
291       printf ("  want     |%s|\n", want);
292       printf ("  got_len  %d\n", got_len);
293       printf ("  ob_len   %d\n", ob_len);
294       printf ("  want_len %d\n", want_len);
295       abort ();
296     }
297   obstack_free (&ob, NULL);
298 #endif
299 }
300 
301 
302 void
303 check_one (const char *want, const char *fmt, ...)
304 {
305   va_list ap;
306   va_start (ap, fmt);
307 
308   /* simplest first */
309   check_vsprintf (want, fmt, ap);
310   check_vfprintf (want, fmt, ap);
311   check_vsnprintf (want, fmt, ap);
312   check_vasprintf (want, fmt, ap);
313   check_obstack_vprintf (want, fmt, ap);
314 }
315 
316 
317 #define hex_or_octal_p(fmt)             \
318   (strchr (fmt, 'x') != NULL            \
319    || strchr (fmt, 'X') != NULL         \
320    || strchr (fmt, 'o') != NULL)
321 
322 void
323 check_z (void)
324 {
325   static const struct {
326     const char  *fmt;
327     const char  *z;
328     const char  *want;
329   } data[] = {
330     { "%Zd", "0",    "0" },
331     { "%Zd", "1",    "1" },
332     { "%Zd", "123",  "123" },
333     { "%Zd", "-1",   "-1" },
334     { "%Zd", "-123", "-123" },
335 
336     { "%+Zd", "0",      "+0" },
337     { "%+Zd", "123",  "+123" },
338     { "%+Zd", "-123", "-123" },
339 
340     { "%Zx",  "123",   "7b" },
341     { "%ZX",  "123",   "7B" },
342     { "%Zx", "-123",  "-7b" },
343     { "%ZX", "-123",  "-7B" },
344     { "%Zo",  "123",  "173" },
345     { "%Zo", "-123", "-173" },
346 
347     { "%#Zx",    "0",     "0" },
348     { "%#ZX",    "0",     "0" },
349     { "%#Zx",  "123",  "0x7b" },
350     { "%#ZX",  "123",  "0X7B" },
351     { "%#Zx", "-123", "-0x7b" },
352     { "%#ZX", "-123", "-0X7B" },
353 
354     { "%#Zo",    "0",     "0" },
355     { "%#Zo",  "123",  "0173" },
356     { "%#Zo", "-123", "-0173" },
357 
358     { "%10Zd",      "0", "         0" },
359     { "%10Zd",    "123", "       123" },
360     { "%10Zd",   "-123", "      -123" },
361 
362     { "%-10Zd",     "0", "0         " },
363     { "%-10Zd",   "123", "123       " },
364     { "%-10Zd",  "-123", "-123      " },
365 
366     { "%+10Zd",   "123", "      +123" },
367     { "%+-10Zd",  "123", "+123      " },
368     { "%+10Zd",  "-123", "      -123" },
369     { "%+-10Zd", "-123", "-123      " },
370 
371     { "%08Zd",    "0", "00000000" },
372     { "%08Zd",  "123", "00000123" },
373     { "%08Zd", "-123", "-0000123" },
374 
375     { "%+08Zd",    "0", "+0000000" },
376     { "%+08Zd",  "123", "+0000123" },
377     { "%+08Zd", "-123", "-0000123" },
378 
379     { "%#08Zx",    "0", "00000000" },
380     { "%#08Zx",  "123", "0x00007b" },
381     { "%#08Zx", "-123", "-0x0007b" },
382 
383     { "%+#08Zx",    "0", "+0000000" },
384     { "%+#08Zx",  "123", "+0x0007b" },
385     { "%+#08Zx", "-123", "-0x0007b" },
386 
387     { "%.0Zd", "0", "" },
388     { "%.1Zd", "0", "0" },
389     { "%.2Zd", "0", "00" },
390     { "%.3Zd", "0", "000" },
391   };
392 
393   int        i, j;
394   mpz_t      z;
395   char       *nfmt;
396   mp_size_t  nsize, zeros;
397 
398   mpz_init (z);
399 
400   for (i = 0; i < numberof (data); i++)
401     {
402       mpz_set_str_or_abort (z, data[i].z, 0);
403 
404       /* don't try negatives or forced sign in hex or octal */
405       if (mpz_fits_slong_p (z)
406 	  && ! (hex_or_octal_p (data[i].fmt)
407 		&& (strchr (data[i].fmt, '+') != NULL || mpz_sgn(z) < 0)))
408 	{
409 	  check_plain (data[i].want, data[i].fmt, mpz_get_si (z));
410 	}
411 
412       check_one (data[i].want, data[i].fmt, z);
413 
414       /* Same again, with %N and possibly some high zero limbs */
415       nfmt = __gmp_allocate_strdup (data[i].fmt);
416       for (j = 0; nfmt[j] != '\0'; j++)
417 	if (nfmt[j] == 'Z')
418 	  nfmt[j] = 'N';
419       for (zeros = 0; zeros <= 3; zeros++)
420 	{
421 	  nsize = ABSIZ(z)+zeros;
422 	  MPZ_REALLOC (z, nsize);
423 	  nsize = (SIZ(z) >= 0 ? nsize : -nsize);
424 	  refmpn_zero (PTR(z)+ABSIZ(z), zeros);
425 	  check_one (data[i].want, nfmt, PTR(z), nsize);
426 	}
427       __gmp_free_func (nfmt, strlen(nfmt)+1);
428     }
429 
430   mpz_clear (z);
431 }
432 
433 void
434 check_q (void)
435 {
436   static const struct {
437     const char  *fmt;
438     const char  *q;
439     const char  *want;
440   } data[] = {
441     { "%Qd",    "0",    "0" },
442     { "%Qd",    "1",    "1" },
443     { "%Qd",  "123",  "123" },
444     { "%Qd",   "-1",   "-1" },
445     { "%Qd", "-123", "-123" },
446     { "%Qd",  "3/2",  "3/2" },
447     { "%Qd", "-3/2", "-3/2" },
448 
449     { "%+Qd", "0",      "+0" },
450     { "%+Qd", "123",  "+123" },
451     { "%+Qd", "-123", "-123" },
452     { "%+Qd", "5/8",  "+5/8" },
453     { "%+Qd", "-5/8", "-5/8" },
454 
455     { "%Qx",  "123",   "7b" },
456     { "%QX",  "123",   "7B" },
457     { "%Qx",  "15/16", "f/10" },
458     { "%QX",  "15/16", "F/10" },
459     { "%Qx", "-123",  "-7b" },
460     { "%QX", "-123",  "-7B" },
461     { "%Qx", "-15/16", "-f/10" },
462     { "%QX", "-15/16", "-F/10" },
463     { "%Qo",  "123",  "173" },
464     { "%Qo", "-123", "-173" },
465     { "%Qo",  "16/17",  "20/21" },
466     { "%Qo", "-16/17", "-20/21" },
467 
468     { "%#Qx",    "0",     "0" },
469     { "%#QX",    "0",     "0" },
470     { "%#Qx",  "123",  "0x7b" },
471     { "%#QX",  "123",  "0X7B" },
472     { "%#Qx",  "5/8",  "0x5/0x8" },
473     { "%#QX",  "5/8",  "0X5/0X8" },
474     { "%#Qx", "-123", "-0x7b" },
475     { "%#QX", "-123", "-0X7B" },
476     { "%#Qx", "-5/8", "-0x5/0x8" },
477     { "%#QX", "-5/8", "-0X5/0X8" },
478     { "%#Qo",    "0",     "0" },
479     { "%#Qo",  "123",  "0173" },
480     { "%#Qo", "-123", "-0173" },
481     { "%#Qo",  "5/7",  "05/07" },
482     { "%#Qo", "-5/7", "-05/07" },
483 
484     /* zero denominator and showbase */
485     { "%#10Qo", "0/0",     "       0/0" },
486     { "%#10Qd", "0/0",     "       0/0" },
487     { "%#10Qx", "0/0",     "       0/0" },
488     { "%#10Qo", "123/0",   "    0173/0" },
489     { "%#10Qd", "123/0",   "     123/0" },
490     { "%#10Qx", "123/0",   "    0x7b/0" },
491     { "%#10QX", "123/0",   "    0X7B/0" },
492     { "%#10Qo", "-123/0",  "   -0173/0" },
493     { "%#10Qd", "-123/0",  "    -123/0" },
494     { "%#10Qx", "-123/0",  "   -0x7b/0" },
495     { "%#10QX", "-123/0",  "   -0X7B/0" },
496 
497     { "%10Qd",      "0", "         0" },
498     { "%-10Qd",     "0", "0         " },
499     { "%10Qd",    "123", "       123" },
500     { "%-10Qd",   "123", "123       " },
501     { "%10Qd",   "-123", "      -123" },
502     { "%-10Qd",  "-123", "-123      " },
503 
504     { "%+10Qd",   "123", "      +123" },
505     { "%+-10Qd",  "123", "+123      " },
506     { "%+10Qd",  "-123", "      -123" },
507     { "%+-10Qd", "-123", "-123      " },
508 
509     { "%08Qd",    "0", "00000000" },
510     { "%08Qd",  "123", "00000123" },
511     { "%08Qd", "-123", "-0000123" },
512 
513     { "%+08Qd",    "0", "+0000000" },
514     { "%+08Qd",  "123", "+0000123" },
515     { "%+08Qd", "-123", "-0000123" },
516 
517     { "%#08Qx",    "0", "00000000" },
518     { "%#08Qx",  "123", "0x00007b" },
519     { "%#08Qx", "-123", "-0x0007b" },
520 
521     { "%+#08Qx",    "0", "+0000000" },
522     { "%+#08Qx",  "123", "+0x0007b" },
523     { "%+#08Qx", "-123", "-0x0007b" },
524   };
525 
526   int    i;
527   mpq_t  q;
528 
529   mpq_init (q);
530 
531   for (i = 0; i < numberof (data); i++)
532     {
533       mpq_set_str_or_abort (q, data[i].q, 0);
534       check_one (data[i].want, data[i].fmt, q);
535     }
536 
537   mpq_clear (q);
538 }
539 
540 void
541 check_f (void)
542 {
543   static const struct {
544     const char  *fmt;
545     const char  *f;
546     const char  *want;
547 
548   } data[] = {
549 
550     { "%Ff",    "0",    "0.000000" },
551     { "%Ff",  "123",  "123.000000" },
552     { "%Ff", "-123", "-123.000000" },
553 
554     { "%+Ff",    "0",   "+0.000000" },
555     { "%+Ff",  "123", "+123.000000" },
556     { "%+Ff", "-123", "-123.000000" },
557 
558     { "%.0Ff",    "0",    "0" },
559     { "%.0Ff",  "123",  "123" },
560     { "%.0Ff", "-123", "-123" },
561 
562     { "%8.0Ff",    "0", "       0" },
563     { "%8.0Ff",  "123", "     123" },
564     { "%8.0Ff", "-123", "    -123" },
565 
566     { "%08.0Ff",    "0", "00000000" },
567     { "%08.0Ff",  "123", "00000123" },
568     { "%08.0Ff", "-123", "-0000123" },
569 
570     { "%10.2Ff",       "0", "      0.00" },
571     { "%10.2Ff",    "0.25", "      0.25" },
572     { "%10.2Ff",  "123.25", "    123.25" },
573     { "%10.2Ff", "-123.25", "   -123.25" },
574 
575     { "%-10.2Ff",       "0", "0.00      " },
576     { "%-10.2Ff",    "0.25", "0.25      " },
577     { "%-10.2Ff",  "123.25", "123.25    " },
578     { "%-10.2Ff", "-123.25", "-123.25   " },
579 
580     { "%.2Ff", "0.00000000000001", "0.00" },
581     { "%.2Ff", "0.002",            "0.00" },
582     { "%.2Ff", "0.008",            "0.01" },
583 
584     { "%.0Ff", "123.00000000000001", "123" },
585     { "%.0Ff", "123.2",              "123" },
586     { "%.0Ff", "123.8",              "124" },
587 
588     { "%.0Ff",  "999999.9", "1000000" },
589     { "%.0Ff", "3999999.9", "4000000" },
590 
591     { "%Fe",    "0",  "0.000000e+00" },
592     { "%Fe",    "1",  "1.000000e+00" },
593     { "%Fe",  "123",  "1.230000e+02" },
594 
595     { "%FE",    "0",  "0.000000E+00" },
596     { "%FE",    "1",  "1.000000E+00" },
597     { "%FE",  "123",  "1.230000E+02" },
598 
599     { "%Fe",    "0",  "0.000000e+00" },
600     { "%Fe",    "1",  "1.000000e+00" },
601 
602     { "%.0Fe",     "10000000000",    "1e+10" },
603     { "%.0Fe",    "-10000000000",   "-1e+10" },
604 
605     { "%.2Fe",     "10000000000",  "1.00e+10" },
606     { "%.2Fe",    "-10000000000", "-1.00e+10" },
607 
608     { "%8.0Fe",    "10000000000", "   1e+10" },
609     { "%8.0Fe",   "-10000000000", "  -1e+10" },
610 
611     { "%-8.0Fe",   "10000000000", "1e+10   " },
612     { "%-8.0Fe",  "-10000000000", "-1e+10  " },
613 
614     { "%12.2Fe",   "10000000000", "    1.00e+10" },
615     { "%12.2Fe",  "-10000000000", "   -1.00e+10" },
616 
617     { "%012.2Fe",  "10000000000", "00001.00e+10" },
618     { "%012.2Fe", "-10000000000", "-0001.00e+10" },
619 
620     { "%Fg",   "0", "0" },
621     { "%Fg",   "1", "1" },
622     { "%Fg",   "-1", "-1" },
623 
624     { "%.0Fg", "0", "0" },
625     { "%.0Fg", "1", "1" },
626     { "%.0Fg", "-1", "-1" },
627 
628     { "%.1Fg", "100", "1e+02" },
629     { "%.2Fg", "100", "1e+02" },
630     { "%.3Fg", "100", "100" },
631     { "%.4Fg", "100", "100" },
632 
633     { "%Fg", "0.001",    "0.001" },
634     { "%Fg", "0.0001",   "0.0001" },
635     { "%Fg", "0.00001",  "1e-05" },
636     { "%Fg", "0.000001", "1e-06" },
637 
638     { "%.4Fg", "1.00000000000001", "1" },
639     { "%.4Fg", "100000000000001",  "1e+14" },
640 
641     { "%.4Fg", "12345678", "1.235e+07" },
642 
643     { "%Fa", "0","0x0p+0" },
644     { "%FA", "0","0X0P+0" },
645 
646     { "%Fa", "1","0x1p+0" },
647     { "%Fa", "65535","0xf.fffp+12" },
648     { "%Fa", "65536","0x1p+16" },
649     { "%F.10a", "65536","0x1.0000000000p+16" },
650     { "%F.1a", "65535","0x1.0p+16" },
651     { "%F.0a", "65535","0x1p+16" },
652 
653     { "%.2Ff", "0.99609375", "1.00" },
654     { "%.Ff",  "0.99609375", "0.99609375" },
655     { "%.Fe",  "0.99609375", "9.9609375e-01" },
656     { "%.Fg",  "0.99609375", "0.99609375" },
657     { "%.20Fg",  "1000000", "1000000" },
658     { "%.Fg",  "1000000", "1000000" },
659 
660     { "%#.0Ff", "1", "1." },
661     { "%#.0Fe", "1", "1.e+00" },
662     { "%#.0Fg", "1", "1." },
663 
664     { "%#.1Ff", "1", "1.0" },
665     { "%#.1Fe", "1", "1.0e+00" },
666     { "%#.1Fg", "1", "1." },
667 
668     { "%#.4Ff", "1234", "1234.0000" },
669     { "%#.4Fe", "1234", "1.2340e+03" },
670     { "%#.4Fg", "1234", "1234." },
671 
672     { "%#.8Ff", "1234", "1234.00000000" },
673     { "%#.8Fe", "1234", "1.23400000e+03" },
674     { "%#.8Fg", "1234", "1234.0000" },
675 
676   };
677 
678   int     i;
679   mpf_t   f;
680   double  d;
681 
682   mpf_init2 (f, 256L);
683 
684   for (i = 0; i < numberof (data); i++)
685     {
686       if (data[i].f[0] == '0' && data[i].f[1] == 'x')
687 	mpf_set_str_or_abort (f, data[i].f, 16);
688       else
689 	mpf_set_str_or_abort (f, data[i].f, 10);
690 
691       /* if mpf->double doesn't truncate, then expect same result */
692       d = mpf_get_d (f);
693       if (mpf_cmp_d (f, d) == 0)
694 	check_plain (data[i].want, data[i].fmt, d);
695 
696       check_one (data[i].want, data[i].fmt, f);
697     }
698 
699   mpf_clear (f);
700 }
701 
702 
703 void
704 check_limb (void)
705 {
706   int        i;
707   mp_limb_t  limb;
708   mpz_t      z;
709   char       *s;
710 
711   check_one ("0", "%Md", CNST_LIMB(0));
712   check_one ("1", "%Md", CNST_LIMB(1));
713 
714   /* "i" many 1 bits, tested against mpz_get_str in decimal and hex */
715   limb = 1;
716   mpz_init_set_ui (z, 1L);
717   for (i = 1; i <= GMP_LIMB_BITS; i++)
718     {
719       s = mpz_get_str (NULL, 10, z);
720       check_one (s, "%Mu", limb);
721       (*__gmp_free_func) (s, strlen (s) + 1);
722 
723       s = mpz_get_str (NULL, 16, z);
724       check_one (s, "%Mx", limb);
725       (*__gmp_free_func) (s, strlen (s) + 1);
726 
727       s = mpz_get_str (NULL, -16, z);
728       check_one (s, "%MX", limb);
729       (*__gmp_free_func) (s, strlen (s) + 1);
730 
731       limb = 2*limb + 1;
732       mpz_mul_2exp (z, z, 1L);
733       mpz_add_ui (z, z, 1L);
734     }
735 
736   mpz_clear (z);
737 }
738 
739 
740 void
741 check_n (void)
742 {
743   {
744     int  n = -1;
745     check_one ("blah", "%nblah", &n);
746     ASSERT_ALWAYS (n == 0);
747   }
748 
749   {
750     int  n = -1;
751     check_one ("hello ", "hello %n", &n);
752     ASSERT_ALWAYS (n == 6);
753   }
754 
755   {
756     int  n = -1;
757     check_one ("hello  world", "hello %n world", &n);
758     ASSERT_ALWAYS (n == 6);
759   }
760 
761 #define CHECK_N(type, string)                           \
762   do {                                                  \
763     type  x[2];                                         \
764     char  fmt[128];                                     \
765 							\
766     x[0] = ~ (type) 0;                                  \
767     x[1] = ~ (type) 0;                                  \
768     sprintf (fmt, "%%d%%%sn%%d", string);               \
769     check_one ("123456", fmt, 123, &x[0], 456);         \
770 							\
771     /* should write whole of x[0] and none of x[1] */   \
772     ASSERT_ALWAYS (x[0] == 3);                          \
773     ASSERT_ALWAYS (x[1] == (type) ~ (type) 0);		\
774 							\
775   } while (0)
776 
777   CHECK_N (mp_limb_t, "M");
778   CHECK_N (char,      "hh");
779   CHECK_N (long,      "l");
780 #if HAVE_LONG_LONG
781   CHECK_N (long long, "L");
782 #endif
783 #if HAVE_INTMAX_T
784   CHECK_N (intmax_t,  "j");
785 #endif
786 #if HAVE_PTRDIFF_T
787   CHECK_N (ptrdiff_t, "t");
788 #endif
789   CHECK_N (short,     "h");
790   CHECK_N (size_t,    "z");
791 
792   {
793     mpz_t  x[2];
794     mpz_init_set_si (x[0], -987L);
795     mpz_init_set_si (x[1],  654L);
796     check_one ("123456", "%d%Zn%d", 123, x[0], 456);
797     MPZ_CHECK_FORMAT (x[0]);
798     MPZ_CHECK_FORMAT (x[1]);
799     ASSERT_ALWAYS (mpz_cmp_ui (x[0], 3L) == 0);
800     ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 0);
801     mpz_clear (x[0]);
802     mpz_clear (x[1]);
803   }
804 
805   {
806     mpq_t  x[2];
807     mpq_init (x[0]);
808     mpq_init (x[1]);
809     mpq_set_ui (x[0], 987L, 654L);
810     mpq_set_ui (x[1], 4115L, 226L);
811     check_one ("123456", "%d%Qn%d", 123, x[0], 456);
812     MPQ_CHECK_FORMAT (x[0]);
813     MPQ_CHECK_FORMAT (x[1]);
814     ASSERT_ALWAYS (mpq_cmp_ui (x[0], 3L, 1L) == 0);
815     ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 0);
816     mpq_clear (x[0]);
817     mpq_clear (x[1]);
818   }
819 
820   {
821     mpf_t  x[2];
822     mpf_init (x[0]);
823     mpf_init (x[1]);
824     mpf_set_ui (x[0], 987L);
825     mpf_set_ui (x[1], 654L);
826     check_one ("123456", "%d%Fn%d", 123, x[0], 456);
827     MPF_CHECK_FORMAT (x[0]);
828     MPF_CHECK_FORMAT (x[1]);
829     ASSERT_ALWAYS (mpf_cmp_ui (x[0], 3L) == 0);
830     ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 0);
831     mpf_clear (x[0]);
832     mpf_clear (x[1]);
833   }
834 
835   {
836     mp_limb_t  a[5];
837     mp_limb_t  a_want[numberof(a)];
838     mp_size_t  i;
839 
840     a[0] = 123;
841     check_one ("blah", "bl%Nnah", a, (mp_size_t) 0);
842     ASSERT_ALWAYS (a[0] == 123);
843 
844     MPN_ZERO (a_want, numberof (a_want));
845     for (i = 1; i < numberof (a); i++)
846       {
847 	check_one ("blah", "bl%Nnah", a, i);
848 	a_want[0] = 2;
849 	ASSERT_ALWAYS (mpn_cmp (a, a_want, i) == 0);
850       }
851   }
852 }
853 
854 
855 void
856 check_misc (void)
857 {
858   mpz_t  z;
859   mpf_t  f;
860 
861   mpz_init (z);
862   mpf_init2 (f, 128L);
863 
864   check_one ("!", "%c", '!');
865 
866   check_one ("hello world", "hello %s", "world");
867   check_one ("hello:", "%s:", "hello");
868   mpz_set_ui (z, 0L);
869   check_one ("hello0", "%s%Zd", "hello", z, z);
870 
871   {
872     static char  xs[801];
873     memset (xs, 'x', sizeof(xs)-1);
874     check_one (xs, "%s", xs);
875   }
876 
877   mpz_set_ui (z, 12345L);
878   check_one ("     12345", "%*Zd", 10, z);
879   check_one ("0000012345", "%0*Zd", 10, z);
880   check_one ("12345     ", "%*Zd", -10, z);
881   check_one ("12345 and 678", "%Zd and %d", z, 678);
882   check_one ("12345,1,12345,2,12345", "%Zd,%d,%Zd,%d,%Zd", z, 1, z, 2, z);
883 
884   /* from the glibc info docs */
885   mpz_set_si (z, 0L);
886   check_one ("|    0|0    |   +0|+0   |    0|00000|     |   00|0|",
887 	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
888 	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
889   mpz_set_si (z, 1L);
890   check_one ("|    1|1    |   +1|+1   |    1|00001|    1|   01|1|",
891 	     "|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|",
892 	     /**/ z,    z,    z,     z,    z,    z,     z,     z,  z);
893   mpz_set_si (z, -1L);
894   check_one ("|   -1|-1   |   -1|-1   |   -1|-0001|   -1|  -01|-1|",
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, 100000L);
898   check_one ("|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|",
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, 0L);
902   check_one ("|    0|    0|    0|    0|    0|    0|  00000000|",
903 	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
904 	     /**/ z,   z,   z,    z,    z,    z,       z);
905   mpz_set_si (z, 1L);
906   check_one ("|    1|    1|    1|   01|  0x1|  0X1|0x00000001|",
907 	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
908 	     /**/ z,   z,   z,    z,    z,    z,       z);
909   mpz_set_si (z, 100000L);
910   check_one ("|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|",
911 	     "|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|",
912 	     /**/ z,   z,   z,    z,    z,    z,       z);
913 
914   /* %zd for size_t won't be available on old systems, and running something
915      to see if it works might be bad, so only try it on glibc, and only on a
916      new enough version (glibc 2.0 doesn't have %zd) */
917 #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 0)
918   mpz_set_ui (z, 789L);
919   check_one ("456 789 blah", "%zd %Zd blah", (size_t) 456, z);
920 #endif
921 
922   mpz_clear (z);
923   mpf_clear (f);
924 }
925 
926 
927 int
928 main (int argc, char *argv[])
929 {
930   if (argc > 1 && strcmp (argv[1], "-s") == 0)
931     option_check_printf = 1;
932 
933   tests_start ();
934   check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME, "w+");
935   ASSERT_ALWAYS (check_vfprintf_fp != NULL);
936 
937   check_z ();
938   check_q ();
939   check_f ();
940   check_limb ();
941   check_n ();
942   check_misc ();
943 
944   ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0);
945   unlink (CHECK_VFPRINTF_FILENAME);
946   tests_end ();
947   exit (0);
948 }
949