xref: /netbsd-src/external/lgpl3/gmp/dist/tests/misc/t-printf.c (revision 72c7faa4dbb41dbb0238d6b4a109da0d4b236dd4)
1 /* Test gmp_printf and related functions.
2 
3 Copyright 2001-2003, 2015 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-impl.h"
55 #include "tests.h"
56 
57 
58 int   option_check_printf = 0;
59 
60 
61 #define CHECK_VFPRINTF_FILENAME  "t-printf.tmp"
62 FILE  *check_vfprintf_fp;
63 
64 
65 /* From any of the tests run here. */
66 #define MAX_OUTPUT  1024
67 
68 
69 void
check_plain(const char * want,const char * fmt_orig,...)70 check_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 
131 void
check_vsprintf(const char * want,const char * fmt,va_list ap)132 check_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 
152 void
check_vfprintf(const char * want,const char * fmt,va_list ap)153 check_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 
190 void
check_vsnprintf(const char * want,const char * fmt,va_list ap)191 check_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 
246 void
check_vasprintf(const char * want,const char * fmt,va_list ap)247 check_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 
268 void
check_obstack_vprintf(const char * want,const char * fmt,va_list ap)269 check_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 
301 void
check_one(const char * want,const char * fmt,...)302 check_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 
321 void
check_z(void)322 check_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 
432 void
check_q(void)433 check_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 
539 void
check_f(void)540 check_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 
702 void
check_limb(void)703 check_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 
739 void
check_n(void)740 check_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 
854 void
check_misc(void)855 check_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 
935 int
main(int argc,char * argv[])936 main (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