Upload Tizen:Base source
[external/gmp.git] / tests / misc / t-printf.c
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.
6
7 The GNU MP Library is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 The GNU MP Library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15 License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along 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
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 = (*__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 = 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 }