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