/* Test gmp_printf and related functions. Copyright 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU MP Library. The GNU MP Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU MP Library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU MP Library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* 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" #if HAVE_STDARG #include #else #include #endif #include /* for ptrdiff_t */ #include #include #include #if HAVE_OBSTACK_VPRINTF #define obstack_chunk_alloc tests_allocate #define obstack_chunk_free tests_free_nosize #include #endif #if HAVE_INTTYPES_H # include /* for intmax_t */ #else # if HAVE_STDINT_H # include # endif #endif #if HAVE_UNISTD_H #include /* for unlink */ #endif #include "gmp.h" #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 #if HAVE_STDARG check_plain (const char *want, const char *fmt_orig, ...) #else check_plain (va_alist) va_dcl #endif { char got[MAX_OUTPUT]; int got_len, want_len; size_t fmtsize; char *fmt, *q; const char *p; va_list ap; #if HAVE_STDARG va_start (ap, fmt_orig); #else const char *want; const char *fmt_orig; va_start (ap); want = va_arg (ap, const char *); fmt_orig = va_arg (ap, const char *); #endif if (! option_check_printf) return; fmtsize = strlen (fmt_orig) + 1; fmt = (*__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 %u\n", 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 = 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 #if HAVE_STDARG check_one (const char *want, const char *fmt, ...) #else check_one (va_alist) va_dcl #endif { va_list ap; #if HAVE_STDARG va_start (ap, fmt); #else const char *want; const char *fmt; va_start (ap); want = va_arg (ap, const char *); fmt = va_arg (ap, const char *); #endif /* 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, zeros; mpz_t z; char *nfmt; mp_size_t nsize; 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, 256L); 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_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 (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], -987L); mpz_init_set_si (x[1], 654L); 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], 3L) == 0); ASSERT_ALWAYS (mpz_cmp_ui (x[1], 654L) == 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], -987L, 654L); mpq_set_ui (x[1], 4115L, 226L); 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], 3L, 1L) == 0); ASSERT_ALWAYS (mpq_cmp_ui (x[1], 4115L, 226L) == 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], -987L); mpf_set_ui (x[1], 654L); 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], 3L) == 0); ASSERT_ALWAYS (mpf_cmp_ui (x[1], 654L) == 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, 128L); check_one ("!", "%c", '!'); check_one ("hello world", "hello %s", "world"); check_one ("hello:", "%s:", "hello"); mpz_set_ui (z, 0L); check_one ("hello0", "%s%Zd", "hello", z, z); { static char xs[801]; memset (xs, 'x', sizeof(xs)-1); check_one (xs, "%s", xs); } mpz_set_ui (z, 12345L); 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, 0L); 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, 1L); 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, -1L); 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, 100000L); 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, 0L); 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, 1L); 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, 100000L); 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, 789L); 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_n (); check_misc (); ASSERT_ALWAYS (fclose (check_vfprintf_fp) == 0); unlink (CHECK_VFPRINTF_FILENAME); tests_end (); exit (0); }