github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tests/misc/t-printf.c (about)

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