/* Test gmp_printf and related functions.
Copyright 2001 - 2003 , 2015 Free Software Foundation , Inc .
This file is part of the GNU MP Library test suite .
The GNU MP Library test suite is free software ; you can redistribute it
and / or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation ; either version 3 of the License ,
or ( at your option ) any later version .
The GNU MP Library test suite is distributed in the hope that it will be
useful , but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU General
Public License for more details .
You should have received a copy of the GNU General Public License along with
the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
/* Usage: t-printf [-s]
- s Check the data against the system printf , where possible . This is
only an option since we don ' t want to fail if the system printf is
faulty or strange. */
#include "config.h" /* needed for the HAVE_, could also move gmp incls */
#include <stdarg.h>
#include <stddef.h>
/* for ptrdiff_t */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if HAVE_OBSTACK_VPRINTF
#define obstack_chunk_alloc tests_allocate
#define obstack_chunk_free tests_free_nosize
#include <obstack.h>
#endif
#if HAVE_INTTYPES_H
# include <inttypes.h>
/* for intmax_t */
#endif
#if HAVE_STDINT_H
# include <stdint.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
/* for unlink */
#endif
#include "gmp-impl.h"
#include "tests.h"
int option_check_printf =
0 ;
#define CHECK_VFPRINTF_FILENAME
"t-printf.tmp"
FILE *check_vfprintf_fp;
/* From any of the tests run here. */
#define MAX_OUTPUT
1024
void
check_plain (
const char *want,
const char *fmt_orig, ...)
{
char got[MAX_OUTPUT];
int got_len, want_len;
size_t fmtsize;
char *fmt, *q;
const char *p;
va_list ap;
va_start (ap, fmt_orig);
if (! option_check_printf)
return ;
fmtsize = strlen (fmt_orig) +
1 ;
fmt = (
char *) (*__gmp_allocate_func) (fmtsize);
for (p = fmt_orig, q = fmt; *p !=
'\0' ; p++)
{
switch (*p) {
case 'a' :
case 'A' :
/* The exact value of the exponent isn't guaranteed in glibc, and it
and gmp_printf do slightly different things , so don ' t compare
directly. */
goto done;
case 'F' :
if (p > fmt_orig && *(p-
1 ) ==
'.' )
goto done;
/* don't test the "all digits" cases */
/* discard 'F' type */
break ;
case 'Z' :
/* transmute */
*q++ =
'l' ;
break ;
default :
*q++ = *p;
break ;
}
}
*q =
'\0' ;
want_len = strlen (want);
ASSERT_ALWAYS (want_len <
sizeof (got));
got_len = vsprintf (got, fmt, ap);
if (got_len != want_len || strcmp (got, want) !=
0 )
{
printf (
"wanted data doesn't match plain vsprintf\n" );
printf (
" fmt |%s|\n" , fmt);
printf (
" got |%s|\n" , got);
printf (
" want |%s|\n" , want);
printf (
" got_len %d\n" , got_len);
printf (
" want_len %d\n" , want_len);
abort ();
}
done:
(*__gmp_free_func) (fmt, fmtsize);
}
void
check_vsprintf (
const char *want,
const char *fmt, va_list ap)
{
char got[MAX_OUTPUT];
int got_len, want_len;
want_len = strlen (want);
got_len = gmp_vsprintf (got, fmt, ap);
if (got_len != want_len || strcmp (got, want) !=
0 )
{
printf (
"gmp_vsprintf wrong\n" );
printf (
" fmt |%s|\n" , fmt);
printf (
" got |%s|\n" , got);
printf (
" want |%s|\n" , want);
printf (
" got_len %d\n" , got_len);
printf (
" want_len %d\n" , want_len);
abort ();
}
}
void
check_vfprintf (
const char *want,
const char *fmt, va_list ap)
{
char got[MAX_OUTPUT];
int got_len, want_len, fread_len;
long ftell_len;
want_len = strlen (want);
rewind (check_vfprintf_fp);
got_len = gmp_vfprintf (check_vfprintf_fp, fmt, ap);
ASSERT_ALWAYS (got_len != -
1 );
ASSERT_ALWAYS (fflush (check_vfprintf_fp) ==
0 );
ftell_len = ftell (check_vfprintf_fp);
ASSERT_ALWAYS (ftell_len != -
1 );
rewind (check_vfprintf_fp);
ASSERT_ALWAYS (ftell_len <=
sizeof (got));
fread_len = fread (got,
1 , ftell_len, check_vfprintf_fp);
if (got_len != want_len
|| ftell_len != want_len
|| fread_len != want_len
|| memcmp (got, want, want_len) !=
0 )
{
printf (
"gmp_vfprintf wrong\n" );
printf (
" fmt |%s|\n" , fmt);
printf (
" got |%.*s|\n" , fread_len, got);
printf (
" want |%s|\n" , want);
printf (
" got_len %d\n" , got_len);
printf (
" ftell_len %ld\n" , ftell_len);
printf (
" fread_len %d\n" , fread_len);
printf (
" want_len %d\n" , want_len);
abort ();
}
}
void
check_vsnprintf (
const char *want,
const char *fmt, va_list ap)
{
char got[MAX_OUTPUT+
1 ];
int ret, got_len, want_len;
size_t bufsize;
want_len = strlen (want);
bufsize = -
1 ;
for (;;)
{
/* do 0 to 5, then want-5 to want+5 */
bufsize++;
if (bufsize >
5 && bufsize < want_len-
5 )
bufsize = want_len-
5 ;
if (bufsize > want_len +
5 )
break ;
ASSERT_ALWAYS (bufsize+
1 <=
sizeof (got));
got[bufsize] =
'!' ;
ret = gmp_vsnprintf (got, bufsize, fmt, ap);
got_len = MIN (MAX(
1 ,bufsize)-
1 , want_len);
if (got[bufsize] !=
'!' )
{
printf (
"gmp_vsnprintf overwrote bufsize sentinel\n" );
goto error;
}
if (ret != want_len)
{
printf (
"gmp_vsnprintf return value wrong\n" );
goto error;
}
if (bufsize >
0 )
{
if (memcmp (got, want, got_len) !=
0 || got[got_len] !=
'\0' )
{
printf (
"gmp_vsnprintf wrong result string\n" );
error:
printf (
" fmt |%s|\n" , fmt);
printf (
" bufsize %lu\n" , (
unsigned long ) bufsize);
printf (
" got |%s|\n" , got);
printf (
" want |%.*s|\n" , got_len, want);
printf (
" want full |%s|\n" , want);
printf (
" ret %d\n" , ret);
printf (
" want_len %d\n" , want_len);
abort ();
}
}
}
}
void
check_vasprintf (
const char *want,
const char *fmt, va_list ap)
{
char *got;
int got_len, want_len;
want_len = strlen (want);
got_len = gmp_vasprintf (&got, fmt, ap);
if (got_len != want_len || strcmp (got, want) !=
0 )
{
printf (
"gmp_vasprintf wrong\n" );
printf (
" fmt |%s|\n" , fmt);
printf (
" got |%s|\n" , got);
printf (
" want |%s|\n" , want);
printf (
" got_len %d\n" , got_len);
printf (
" want_len %d\n" , want_len);
abort ();
}
(*__gmp_free_func) (got, strlen(got)+
1 );
}
void
check_obstack_vprintf (
const char *want,
const char *fmt, va_list ap)
{
#if HAVE_OBSTACK_VPRINTF
struct obstack ob;
int got_len, want_len, ob_len;
char *got;
want_len = strlen (want);
obstack_init (&ob);
got_len = gmp_obstack_vprintf (&ob, fmt, ap);
got = (
char *) obstack_base (&ob);
ob_len = obstack_object_size (&ob);
if (got_len != want_len
|| ob_len != want_len
|| memcmp (got, want, want_len) !=
0 )
{
printf (
"gmp_obstack_vprintf wrong\n" );
printf (
" fmt |%s|\n" , fmt);
printf (
" got |%s|\n" , got);
printf (
" want |%s|\n" , want);
printf (
" got_len %d\n" , got_len);
printf (
" ob_len %d\n" , ob_len);
printf (
" want_len %d\n" , want_len);
abort ();
}
obstack_free (&ob, NULL);
#endif
}
void
check_one (
const char *want,
const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
/* simplest first */
check_vsprintf (want, fmt, ap);
check_vfprintf (want, fmt, ap);
check_vsnprintf (want, fmt, ap);
check_vasprintf (want, fmt, ap);
check_obstack_vprintf (want, fmt, ap);
}
#define hex_or_octal_p(fmt) \
(strchr (fmt,
'x' ) != NULL \
|| strchr (fmt,
'X' ) != NULL \
|| strchr (fmt,
'o' ) != NULL)
void
check_z (
void )
{
static const struct {
const char *fmt;
const char *z;
const char *want;
} data[] = {
{
"%Zd" ,
"0" ,
"0" },
{
"%Zd" ,
"1" ,
"1" },
{
"%Zd" ,
"123" ,
"123" },
{
"%Zd" ,
"-1" ,
"-1" },
{
"%Zd" ,
"-123" ,
"-123" },
{
"%+Zd" ,
"0" ,
"+0" },
{
"%+Zd" ,
"123" ,
"+123" },
{
"%+Zd" ,
"-123" ,
"-123" },
{
"%Zx" ,
"123" ,
"7b" },
{
"%ZX" ,
"123" ,
"7B" },
{
"%Zx" ,
"-123" ,
"-7b" },
{
"%ZX" ,
"-123" ,
"-7B" },
{
"%Zo" ,
"123" ,
"173" },
{
"%Zo" ,
"-123" ,
"-173" },
{
"%#Zx" ,
"0" ,
"0" },
{
"%#ZX" ,
"0" ,
"0" },
{
"%#Zx" ,
"123" ,
"0x7b" },
{
"%#ZX" ,
"123" ,
"0X7B" },
{
"%#Zx" ,
"-123" ,
"-0x7b" },
{
"%#ZX" ,
"-123" ,
"-0X7B" },
{
"%#Zo" ,
"0" ,
"0" },
{
"%#Zo" ,
"123" ,
"0173" },
{
"%#Zo" ,
"-123" ,
"-0173" },
{
"%10Zd" ,
"0" ,
" 0" },
{
"%10Zd" ,
"123" ,
" 123" },
{
"%10Zd" ,
"-123" ,
" -123" },
{
"%-10Zd" ,
"0" ,
"0 " },
{
"%-10Zd" ,
"123" ,
"123 " },
{
"%-10Zd" ,
"-123" ,
"-123 " },
{
"%+10Zd" ,
"123" ,
" +123" },
{
"%+-10Zd" ,
"123" ,
"+123 " },
{
"%+10Zd" ,
"-123" ,
" -123" },
{
"%+-10Zd" ,
"-123" ,
"-123 " },
{
"%08Zd" ,
"0" ,
"00000000" },
{
"%08Zd" ,
"123" ,
"00000123" },
{
"%08Zd" ,
"-123" ,
"-0000123" },
{
"%+08Zd" ,
"0" ,
"+0000000" },
{
"%+08Zd" ,
"123" ,
"+0000123" },
{
"%+08Zd" ,
"-123" ,
"-0000123" },
{
"%#08Zx" ,
"0" ,
"00000000" },
{
"%#08Zx" ,
"123" ,
"0x00007b" },
{
"%#08Zx" ,
"-123" ,
"-0x0007b" },
{
"%+#08Zx" ,
"0" ,
"+0000000" },
{
"%+#08Zx" ,
"123" ,
"+0x0007b" },
{
"%+#08Zx" ,
"-123" ,
"-0x0007b" },
{
"%.0Zd" ,
"0" ,
"" },
{
"%.1Zd" ,
"0" ,
"0" },
{
"%.2Zd" ,
"0" ,
"00" },
{
"%.3Zd" ,
"0" ,
"000" },
};
int i, j;
mpz_t z;
char *nfmt;
mp_size_t nsize, zeros;
mpz_init (z);
for (i =
0 ; i < numberof (data); i++)
{
mpz_set_str_or_abort (z, data[i].z,
0 );
/* don't try negatives or forced sign in hex or octal */
if (mpz_fits_slong_p (z)
&& ! (hex_or_octal_p (data[i].fmt)
&& (strchr (data[i].fmt,
'+' ) != NULL || mpz_sgn(z) <
0 )))
{
check_plain (data[i].want, data[i].fmt, mpz_get_si (z));
}
check_one (data[i].want, data[i].fmt, z);
/* Same again, with %N and possibly some high zero limbs */
nfmt = __gmp_allocate_strdup (data[i].fmt);
for (j =
0 ; nfmt[j] !=
'\0' ; j++)
if (nfmt[j] ==
'Z' )
nfmt[j] =
'N' ;
for (zeros =
0 ; zeros <=
3 ; zeros++)
{
nsize = ABSIZ(z)+zeros;
MPZ_REALLOC (z, nsize);
nsize = (SIZ(z) >=
0 ? nsize : -nsize);
refmpn_zero (PTR(z)+ABSIZ(z), zeros);
check_one (data[i].want, nfmt, PTR(z), nsize);
}
__gmp_free_func (nfmt, strlen(nfmt)+
1 );
}
mpz_clear (z);
}
void
check_q (
void )
{
static const struct {
const char *fmt;
const char *q;
const char *want;
} data[] = {
{
"%Qd" ,
"0" ,
"0" },
{
"%Qd" ,
"1" ,
"1" },
{
"%Qd" ,
"123" ,
"123" },
{
"%Qd" ,
"-1" ,
"-1" },
{
"%Qd" ,
"-123" ,
"-123" },
{
"%Qd" ,
"3/2" ,
"3/2" },
{
"%Qd" ,
"-3/2" ,
"-3/2" },
{
"%+Qd" ,
"0" ,
"+0" },
{
"%+Qd" ,
"123" ,
"+123" },
{
"%+Qd" ,
"-123" ,
"-123" },
{
"%+Qd" ,
"5/8" ,
"+5/8" },
{
"%+Qd" ,
"-5/8" ,
"-5/8" },
{
"%Qx" ,
"123" ,
"7b" },
{
"%QX" ,
"123" ,
"7B" },
{
"%Qx" ,
"15/16" ,
"f/10" },
{
"%QX" ,
"15/16" ,
"F/10" },
{
"%Qx" ,
"-123" ,
"-7b" },
{
"%QX" ,
"-123" ,
"-7B" },
{
"%Qx" ,
"-15/16" ,
"-f/10" },
{
"%QX" ,
"-15/16" ,
"-F/10" },
{
"%Qo" ,
"123" ,
"173" },
{
"%Qo" ,
"-123" ,
"-173" },
{
"%Qo" ,
"16/17" ,
"20/21" },
{
"%Qo" ,
"-16/17" ,
"-20/21" },
{
"%#Qx" ,
"0" ,
"0" },
{
"%#QX" ,
"0" ,
"0" },
{
"%#Qx" ,
"123" ,
"0x7b" },
{
"%#QX" ,
"123" ,
"0X7B" },
{
"%#Qx" ,
"5/8" ,
"0x5/0x8" },
{
"%#QX" ,
"5/8" ,
"0X5/0X8" },
{
"%#Qx" ,
"-123" ,
"-0x7b" },
{
"%#QX" ,
"-123" ,
"-0X7B" },
{
"%#Qx" ,
"-5/8" ,
"-0x5/0x8" },
{
"%#QX" ,
"-5/8" ,
"-0X5/0X8" },
{
"%#Qo" ,
"0" ,
"0" },
{
"%#Qo" ,
"123" ,
"0173" },
{
"%#Qo" ,
"-123" ,
"-0173" },
{
"%#Qo" ,
"5/7" ,
"05/07" },
{
"%#Qo" ,
"-5/7" ,
"-05/07" },
/* zero denominator and showbase */
{
"%#10Qo" ,
"0/0" ,
" 0/0" },
{
"%#10Qd" ,
"0/0" ,
" 0/0" },
{
"%#10Qx" ,
"0/0" ,
" 0/0" },
{
"%#10Qo" ,
"123/0" ,
" 0173/0" },
{
"%#10Qd" ,
"123/0" ,
" 123/0" },
{
"%#10Qx" ,
"123/0" ,
" 0x7b/0" },
{
"%#10QX" ,
"123/0" ,
" 0X7B/0" },
{
"%#10Qo" ,
"-123/0" ,
" -0173/0" },
{
"%#10Qd" ,
"-123/0" ,
" -123/0" },
{
"%#10Qx" ,
"-123/0" ,
" -0x7b/0" },
{
"%#10QX" ,
"-123/0" ,
" -0X7B/0" },
{
"%10Qd" ,
"0" ,
" 0" },
{
"%-10Qd" ,
"0" ,
"0 " },
{
"%10Qd" ,
"123" ,
" 123" },
{
"%-10Qd" ,
"123" ,
"123 " },
{
"%10Qd" ,
"-123" ,
" -123" },
{
"%-10Qd" ,
"-123" ,
"-123 " },
{
"%+10Qd" ,
"123" ,
" +123" },
{
"%+-10Qd" ,
"123" ,
"+123 " },
{
"%+10Qd" ,
"-123" ,
" -123" },
{
"%+-10Qd" ,
"-123" ,
"-123 " },
{
"%08Qd" ,
"0" ,
"00000000" },
{
"%08Qd" ,
"123" ,
"00000123" },
{
"%08Qd" ,
"-123" ,
"-0000123" },
{
"%+08Qd" ,
"0" ,
"+0000000" },
{
"%+08Qd" ,
"123" ,
"+0000123" },
{
"%+08Qd" ,
"-123" ,
"-0000123" },
{
"%#08Qx" ,
"0" ,
"00000000" },
{
"%#08Qx" ,
"123" ,
"0x00007b" },
{
"%#08Qx" ,
"-123" ,
"-0x0007b" },
{
"%+#08Qx" ,
"0" ,
"+0000000" },
{
"%+#08Qx" ,
"123" ,
"+0x0007b" },
{
"%+#08Qx" ,
"-123" ,
"-0x0007b" },
};
int i;
mpq_t q;
mpq_init (q);
for (i =
0 ; i < numberof (data); i++)
{
mpq_set_str_or_abort (q, data[i].q,
0 );
check_one (data[i].want, data[i].fmt, q);
}
mpq_clear (q);
}
void
check_f (
void )
{
static const struct {
const char *fmt;
const char *f;
const char *want;
} data[] = {
{
"%Ff" ,
"0" ,
"0.000000" },
{
"%Ff" ,
"123" ,
"123.000000" },
{
"%Ff" ,
"-123" ,
"-123.000000" },
{
"%+Ff" ,
"0" ,
"+0.000000" },
{
"%+Ff" ,
"123" ,
"+123.000000" },
{
"%+Ff" ,
"-123" ,
"-123.000000" },
{
"%.0Ff" ,
"0" ,
"0" },
{
"%.0Ff" ,
"123" ,
"123" },
{
"%.0Ff" ,
"-123" ,
"-123" },
{
"%8.0Ff" ,
"0" ,
" 0" },
{
"%8.0Ff" ,
"123" ,
" 123" },
{
"%8.0Ff" ,
"-123" ,
" -123" },
{
"%08.0Ff" ,
"0" ,
"00000000" },
{
"%08.0Ff" ,
"123" ,
"00000123" },
{
"%08.0Ff" ,
"-123" ,
"-0000123" },
{
"%10.2Ff" ,
"0" ,
" 0.00" },
{
"%10.2Ff" ,
"0.25" ,
" 0.25" },
{
"%10.2Ff" ,
"123.25" ,
" 123.25" },
{
"%10.2Ff" ,
"-123.25" ,
" -123.25" },
{
"%-10.2Ff" ,
"0" ,
"0.00 " },
{
"%-10.2Ff" ,
"0.25" ,
"0.25 " },
{
"%-10.2Ff" ,
"123.25" ,
"123.25 " },
{
"%-10.2Ff" ,
"-123.25" ,
"-123.25 " },
{
"%.2Ff" ,
"0.00000000000001" ,
"0.00" },
{
"%.2Ff" ,
"0.002" ,
"0.00" },
{
"%.2Ff" ,
"0.008" ,
"0.01" },
{
"%.0Ff" ,
"123.00000000000001" ,
"123" },
{
"%.0Ff" ,
"123.2" ,
"123" },
{
"%.0Ff" ,
"123.8" ,
"124" },
{
"%.0Ff" ,
"999999.9" ,
"1000000" },
{
"%.0Ff" ,
"3999999.9" ,
"4000000" },
{
"%Fe" ,
"0" ,
"0.000000e+00" },
{
"%Fe" ,
"1" ,
"1.000000e+00" },
{
"%Fe" ,
"123" ,
"1.230000e+02" },
{
"%FE" ,
"0" ,
"0.000000E+00" },
{
"%FE" ,
"1" ,
"1.000000E+00" },
{
"%FE" ,
"123" ,
"1.230000E+02" },
{
"%Fe" ,
"0" ,
"0.000000e+00" },
{
"%Fe" ,
"1" ,
"1.000000e+00" },
{
"%.0Fe" ,
"10000000000" ,
"1e+10" },
{
"%.0Fe" ,
"-10000000000" ,
"-1e+10" },
{
"%.2Fe" ,
"10000000000" ,
"1.00e+10" },
{
"%.2Fe" ,
"-10000000000" ,
"-1.00e+10" },
{
"%8.0Fe" ,
"10000000000" ,
" 1e+10" },
{
"%8.0Fe" ,
"-10000000000" ,
" -1e+10" },
{
"%-8.0Fe" ,
"10000000000" ,
"1e+10 " },
{
"%-8.0Fe" ,
"-10000000000" ,
"-1e+10 " },
{
"%12.2Fe" ,
"10000000000" ,
" 1.00e+10" },
{
"%12.2Fe" ,
"-10000000000" ,
" -1.00e+10" },
{
"%012.2Fe" ,
"10000000000" ,
"00001.00e+10" },
{
"%012.2Fe" ,
"-10000000000" ,
"-0001.00e+10" },
{
"%Fg" ,
"0" ,
"0" },
{
"%Fg" ,
"1" ,
"1" },
{
"%Fg" ,
"-1" ,
"-1" },
{
"%.0Fg" ,
"0" ,
"0" },
{
"%.0Fg" ,
"1" ,
"1" },
{
"%.0Fg" ,
"-1" ,
"-1" },
{
"%.1Fg" ,
"100" ,
"1e+02" },
{
"%.2Fg" ,
"100" ,
"1e+02" },
{
"%.3Fg" ,
"100" ,
"100" },
{
"%.4Fg" ,
"100" ,
"100" },
{
"%Fg" ,
"0.001" ,
"0.001" },
{
"%Fg" ,
"0.0001" ,
"0.0001" },
{
"%Fg" ,
"0.00001" ,
"1e-05" },
{
"%Fg" ,
"0.000001" ,
"1e-06" },
{
"%.4Fg" ,
"1.00000000000001" ,
"1" },
{
"%.4Fg" ,
"100000000000001" ,
"1e+14" },
{
"%.4Fg" ,
"12345678" ,
"1.235e+07" },
{
"%Fa" ,
"0" ,
"0x0p+0" },
{
"%FA" ,
"0" ,
"0X0P+0" },
{
"%Fa" ,
"1" ,
"0x1p+0" },
{
"%Fa" ,
"65535" ,
"0xf.fffp+12" },
{
"%Fa" ,
"65536" ,
"0x1p+16" },
{
"%F.10a" ,
"65536" ,
"0x1.0000000000p+16" },
{
"%F.1a" ,
"65535" ,
"0x1.0p+16" },
{
"%F.0a" ,
"65535" ,
"0x1p+16" },
{
"%.2Ff" ,
"0.99609375" ,
"1.00" },
{
"%.Ff" ,
"0.99609375" ,
"0.99609375" },
{
"%.Fe" ,
"0.99609375" ,
"9.9609375e-01" },
{
"%.Fg" ,
"0.99609375" ,
"0.99609375" },
{
"%.20Fg" ,
"1000000" ,
"1000000" },
{
"%.Fg" ,
"1000000" ,
"1000000" },
{
"%#.0Ff" ,
"1" ,
"1." },
{
"%#.0Fe" ,
"1" ,
"1.e+00" },
{
"%#.0Fg" ,
"1" ,
"1." },
{
"%#.1Ff" ,
"1" ,
"1.0" },
{
"%#.1Fe" ,
"1" ,
"1.0e+00" },
{
"%#.1Fg" ,
"1" ,
"1." },
{
"%#.4Ff" ,
"1234" ,
"1234.0000" },
{
"%#.4Fe" ,
"1234" ,
"1.2340e+03" },
{
"%#.4Fg" ,
"1234" ,
"1234." },
{
"%#.8Ff" ,
"1234" ,
"1234.00000000" },
{
"%#.8Fe" ,
"1234" ,
"1.23400000e+03" },
{
"%#.8Fg" ,
"1234" ,
"1234.0000" },
};
int i;
mpf_t f;
double d;
mpf_init2 (f,
256 L);
for (i =
0 ; i < numberof (data); i++)
{
if (data[i].f[
0 ] ==
'0' && data[i].f[
1 ] ==
'x' )
mpf_set_str_or_abort (f, data[i].f,
16 );
else
mpf_set_str_or_abort (f, data[i].f,
10 );
/* if mpf->double doesn't truncate, then expect same result */
d = mpf_get_d (f);
if (mpf_cmp_d (f, d) ==
0 )
check_plain (data[i].want, data[i].fmt, d);
check_one (data[i].want, data[i].fmt, f);
}
mpf_clear (f);
}
void
check_limb (
void )
{
int i;
mp_limb_t limb;
mpz_t z;
char *s;
check_one (
"0" ,
"%Md" , CNST_LIMB(
0 ));
check_one (
"1" ,
"%Md" , CNST_LIMB(
1 ));
/* "i" many 1 bits, tested against mpz_get_str in decimal and hex */
limb =
1 ;
mpz_init_set_ui (z,
1 L);
for (i =
1 ; i <= GMP_LIMB_BITS; i++)
{
s = mpz_get_str (NULL,
10 , z);
check_one (s,
"%Mu" , limb);
(*__gmp_free_func) (s, strlen (s) +
1 );
s = mpz_get_str (NULL,
16 , z);
check_one (s,
"%Mx" , limb);
(*__gmp_free_func) (s, strlen (s) +
1 );
s = mpz_get_str (NULL, -
16 , z);
check_one (s,
"%MX" , limb);
(*__gmp_free_func) (s, strlen (s) +
1 );
limb =
2 *limb +
1 ;
mpz_mul_2exp (z, z,
1 L);
mpz_add_ui (z, z,
1 L);
}
mpz_clear (z);
}
void
check_n (
void )
{
{
int n = -
1 ;
check_one (
"blah" ,
"%nblah" , &n);
ASSERT_ALWAYS (n ==
0 );
}
{
int n = -
1 ;
check_one (
"hello " ,
"hello %n" , &n);
ASSERT_ALWAYS (n ==
6 );
}
{
int n = -
1 ;
check_one (
"hello world" ,
"hello %n world" , &n);
ASSERT_ALWAYS (n ==
6 );
}
#define CHECK_N(type, string) \
do { \
type x[
2 ]; \
char fmt[
128 ]; \
\
x[
0 ] = ~ (type)
0 ; \
x[
1 ] = ~ (type)
0 ; \
sprintf (fmt,
"%%d%%%sn%%d" , string); \
check_one (
"123456" , fmt,
123 , &x[
0 ],
456 ); \
\
/* should write whole of x[0] and none of x[1] */ \
ASSERT_ALWAYS (x[
0 ] ==
3 ); \
ASSERT_ALWAYS (x[
1 ] == (type) ~ (type)
0 ); \
\
}
while (
0 )
CHECK_N (mp_limb_t,
"M" );
CHECK_N (
char ,
"hh" );
CHECK_N (
long ,
"l" );
#if HAVE_LONG_LONG
CHECK_N (
long long ,
"L" );
#endif
#if HAVE_INTMAX_T
CHECK_N (intmax_t,
"j" );
#endif
#if HAVE_PTRDIFF_T
CHECK_N (ptrdiff_t,
"t" );
#endif
CHECK_N (
short ,
"h" );
CHECK_N (size_t,
"z" );
{
mpz_t x[
2 ];
mpz_init_set_si (x[
0 ], -
987 L);
mpz_init_set_si (x[
1 ],
654 L);
check_one (
"123456" ,
"%d%Zn%d" ,
123 , x[
0 ],
456 );
MPZ_CHECK_FORMAT (x[
0 ]);
MPZ_CHECK_FORMAT (x[
1 ]);
ASSERT_ALWAYS (mpz_cmp_ui (x[
0 ],
3 L) ==
0 );
ASSERT_ALWAYS (mpz_cmp_ui (x[
1 ],
654 L) ==
0 );
mpz_clear (x[
0 ]);
mpz_clear (x[
1 ]);
}
{
mpq_t x[
2 ];
mpq_init (x[
0 ]);
mpq_init (x[
1 ]);
mpq_set_ui (x[
0 ],
987 L,
654 L);
mpq_set_ui (x[
1 ],
4115 L,
226 L);
check_one (
"123456" ,
"%d%Qn%d" ,
123 , x[
0 ],
456 );
MPQ_CHECK_FORMAT (x[
0 ]);
MPQ_CHECK_FORMAT (x[
1 ]);
ASSERT_ALWAYS (mpq_cmp_ui (x[
0 ],
3 L,
1 L) ==
0 );
ASSERT_ALWAYS (mpq_cmp_ui (x[
1 ],
4115 L,
226 L) ==
0 );
mpq_clear (x[
0 ]);
mpq_clear (x[
1 ]);
}
{
mpf_t x[
2 ];
mpf_init (x[
0 ]);
mpf_init (x[
1 ]);
mpf_set_ui (x[
0 ],
987 L);
mpf_set_ui (x[
1 ],
654 L);
check_one (
"123456" ,
"%d%Fn%d" ,
123 , x[
0 ],
456 );
MPF_CHECK_FORMAT (x[
0 ]);
MPF_CHECK_FORMAT (x[
1 ]);
ASSERT_ALWAYS (mpf_cmp_ui (x[
0 ],
3 L) ==
0 );
ASSERT_ALWAYS (mpf_cmp_ui (x[
1 ],
654 L) ==
0 );
mpf_clear (x[
0 ]);
mpf_clear (x[
1 ]);
}
{
mp_limb_t a[
5 ];
mp_limb_t a_want[numberof(a)];
mp_size_t i;
a[
0 ] =
123 ;
check_one (
"blah" ,
"bl%Nnah" , a, (mp_size_t)
0 );
ASSERT_ALWAYS (a[
0 ] ==
123 );
MPN_ZERO (a_want, numberof (a_want));
for (i =
1 ; i < numberof (a); i++)
{
check_one (
"blah" ,
"bl%Nnah" , a, i);
a_want[
0 ] =
2 ;
ASSERT_ALWAYS (mpn_cmp (a, a_want, i) ==
0 );
}
}
}
void
check_misc (
void )
{
mpz_t z;
mpf_t f;
mpz_init (z);
mpf_init2 (f,
128 L);
check_one (
"!" ,
"%c" ,
'!' );
check_one (
"hello world" ,
"hello %s" ,
"world" );
check_one (
"hello:" ,
"%s:" ,
"hello" );
mpz_set_ui (z,
0 L);
check_one (
"hello0" ,
"%s%Zd" ,
"hello" , z, z);
{
static char xs[
801 ];
memset (xs,
'x' ,
sizeof (xs)-
1 );
check_one (xs,
"%s" , xs);
}
{
char *xs;
xs = (
char *) (*__gmp_allocate_func) (MAX_OUTPUT *
2 -
12 );
memset (xs,
'%' , MAX_OUTPUT *
2 -
14 );
xs [MAX_OUTPUT *
2 -
13 ] =
'\0' ;
xs [MAX_OUTPUT *
2 -
14 ] =
'x' ;
check_one (xs + MAX_OUTPUT -
7 , xs, NULL);
(*__gmp_free_func) (xs, MAX_OUTPUT *
2 -
12 );
}
mpz_set_ui (z,
12345 L);
check_one (
" 12345" ,
"%*Zd" ,
10 , z);
check_one (
"0000012345" ,
"%0*Zd" ,
10 , z);
check_one (
"12345 " ,
"%*Zd" , -
10 , z);
check_one (
"12345 and 678" ,
"%Zd and %d" , z,
678 );
check_one (
"12345,1,12345,2,12345" ,
"%Zd,%d,%Zd,%d,%Zd" , z,
1 , z,
2 , z);
/* from the glibc info docs */
mpz_set_si (z,
0 L);
check_one (
"| 0|0 | +0|+0 | 0|00000| | 00|0|" ,
"|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|" ,
/**/ z, z, z, z, z, z, z, z, z);
mpz_set_si (z,
1 L);
check_one (
"| 1|1 | +1|+1 | 1|00001| 1| 01|1|" ,
"|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|" ,
/**/ z, z, z, z, z, z, z, z, z);
mpz_set_si (z, -
1 L);
check_one (
"| -1|-1 | -1|-1 | -1|-0001| -1| -01|-1|" ,
"|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|" ,
/**/ z, z, z, z, z, z, z, z, z);
mpz_set_si (z,
100000 L);
check_one (
"|100000|100000|+100000|+100000| 100000|100000|100000|100000|100000|" ,
"|%5Zd|%-5Zd|%+5Zd|%+-5Zd|% 5Zd|%05Zd|%5.0Zd|%5.2Zd|%Zd|" ,
/**/ z, z, z, z, z, z, z, z, z);
mpz_set_si (z,
0 L);
check_one (
"| 0| 0| 0| 0| 0| 0| 00000000|" ,
"|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|" ,
/**/ z, z, z, z, z, z, z);
mpz_set_si (z,
1 L);
check_one (
"| 1| 1| 1| 01| 0x1| 0X1|0x00000001|" ,
"|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|" ,
/**/ z, z, z, z, z, z, z);
mpz_set_si (z,
100000 L);
check_one (
"|303240|186a0|186A0|0303240|0x186a0|0X186A0|0x000186a0|" ,
"|%5Zo|%5Zx|%5ZX|%#5Zo|%#5Zx|%#5ZX|%#10.8Zx|" ,
/**/ z, z, z, z, z, z, z);
/* %zd for size_t won't be available on old systems, and running something
to see if it works might be bad , so only try it on glibc , and only on a
new enough version (glibc 2.0 doesn't have %zd) */
#if __GLIBC__ >
2 || (__GLIBC__ ==
2 && __GLIBC_MINOR__ >
0 )
mpz_set_ui (z,
789 L);
check_one (
"456 789 blah" ,
"%zd %Zd blah" , (size_t)
456 , z);
#endif
mpz_clear (z);
mpf_clear (f);
}
int
main (
int argc,
char *argv[])
{
if (argc >
1 && strcmp (argv[
1 ],
"-s" ) ==
0 )
option_check_printf =
1 ;
tests_start ();
check_vfprintf_fp = fopen (CHECK_VFPRINTF_FILENAME,
"w+" );
ASSERT_ALWAYS (check_vfprintf_fp != NULL);
check_z ();
check_q ();
check_f ();
check_limb ();
check_n ();
check_misc ();
ASSERT_ALWAYS (fclose (check_vfprintf_fp) ==
0 );
unlink (CHECK_VFPRINTF_FILENAME);
tests_end ();
exit (
0 );
}
Messung V0.5 in Prozent C=94 H=93 G=93
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-10)
¤
*© Formatika GbR, Deutschland