xref: /netbsd-src/external/lgpl3/gmp/dist/tests/misc/t-printf.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /* Test gmp_printf and related functions.
2 
3 Copyright 2001, 2002, 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 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 
64 int   option_check_printf = 0;
65 
66 
67 #define CHECK_VFPRINTF_FILENAME  "t-printf.tmp"
68 FILE  *check_vfprintf_fp;
69 
70 
71 /* From any of the tests run here. */
72 #define MAX_OUTPUT  1024
73 
74 
75 void
76 #if HAVE_STDARG
77 check_plain (const char *want, const char *fmt_orig, ...)
78 #else
79 check_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 = (char *) (*__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 
150 void
151 check_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 
171 void
172 check_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 
209 void
210 check_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 
265 void
266 check_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 
287 void
288 check_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 = (char *) 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 
320 void
321 #if HAVE_STDARG
322 check_one (const char *want, const char *fmt, ...)
323 #else
324 check_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 
353 void
354 check_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 
464 void
465 check_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 
571 void
572 check_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 
734 void
735 check_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 
771 void
772 check_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 
886 void
887 check_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 
958 int
959 main (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