Files
vlibc/tests/test_printf.c
T

735 lines
25 KiB
C

/*
* vlibc — formatted output test, integer conversions (todo 16, task A).
*
* Compares the snprintf/sprintf/dprintf/FILE-output of vfprintf.c against
* golden string literals, all of which were verified against the host glibc
* (a throwaway /tmp/probe.c) EXCEPT the spec'd divergence that %p of NULL is
* "0x0" (glibc prints "(nil)").
*
* Coverage: %d %i %u %o %x %X over 0, +/-1, INT_MIN/MAX, UINT_MAX,
* LONG_MIN/MAX (as %ld), LLONG_MIN/MAX (%lld), ULONG_MAX; %hhd/%hd
* truncation; %zu %zd %tu %td %ju %jd; the '#' prefix rules (including
* %#.0o of 0, %#x of 0, %#o of 0); the - + space 0 flags and their
* interactions with width and precision; %c %s with precision/width and the
* NULL "(null)" spelling; %p of a local (shape check) and of NULL ("0x0");
* %n; width and precision supplied via '*'; %% escaping; snprintf truncation
* (including n == 0 with a NULL buffer); sprintf/vsprintf; fprintf/vfprintf
* to a file; dprintf/vdprintf to a raw descriptor; printf/vprintf through a
* redirected stdout; and (level 2) asprintf/vasprintf.
*
* All diagnostics go through raw SYS_write; errno is never read and never
* deliberately written in the success paths exercised here, so no host TCB
* preservation is needed. Only vlibc headers are included (-Iinclude wins
* over the host's).
*/
#include <float.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../src/internal/syscall.h"
static int failures;
/* Write a NUL-terminated string to fd via the raw syscall layer. */
static void
say(int fd, const char *s)
{
long n = 0;
while (s[n] != '\0')
{
n++;
}
__syscall3(SYS_write, fd, (long)s, n);
}
/* Write v in decimal to fd. */
static void
say_dec(int fd, unsigned long v) // NOLINT(bugprone-easily-swappable-parameters)
{
char buf[24];
int i = (int)sizeof(buf);
buf[--i] = '\0';
do
{
buf[--i] = (char)('0' + (v % 10));
v /= 10;
} while (v != 0);
__syscall3(SYS_write, fd, (long)(buf + i), (long)(sizeof(buf) - 1 - i));
}
static void
check(int cond, const char *what)
{
if (cond)
{
say(1, "PASS: ");
say(1, what);
say(1, "\n");
}
else
{
say(2, "FAIL: ");
say(2, what);
say(2, "\n");
failures++;
}
}
/* Byte-compare two buffers (the produced content need not be NUL-ended). */
static int
mem_eq(const unsigned char *a, const unsigned char *b, unsigned long n)
{
unsigned long i;
for (i = 0; i < n; i++)
{
if (a[i] != b[i])
{
return 0;
}
}
return 1;
}
/* Read a whole small file through raw syscalls into buf; returns size. */
static long
raw_read_all(const char *path, char *buf, unsigned long cap)
{
long fd = __syscall4(SYS_openat, -100, (long)path, 0x0, 0);
long got = -1;
long total = 0;
if (fd < 0)
{
return -1;
}
while (total < (long)cap)
{
got = __syscall3(SYS_read, fd, (long)(buf + total), (long)(cap - (unsigned long)total));
if (got <= 0)
{
break;
}
total += got;
}
__syscall1(SYS_close, fd);
return got < 0 ? -1 : total;
}
/* Forwarding wrappers so the v* functions get exercised with real va_lists. */
static int
run_vprintf(const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
va_list ap;
int rc;
va_start(ap, format);
rc = vprintf(format, ap);
va_end(ap);
return rc;
}
static int
run_vfprintf(FILE *f, const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
va_list ap;
int rc;
va_start(ap, format);
rc = vfprintf(f, format, ap);
va_end(ap);
return rc;
}
static int
run_vsprintf(char *s, const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
va_list ap;
int rc;
va_start(ap, format);
rc = vsprintf(s, format, ap);
va_end(ap);
return rc;
}
static int
run_vdprintf(int fd, const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
va_list ap;
int rc;
va_start(ap, format);
rc = vdprintf(fd, format, ap);
va_end(ap);
return rc;
}
#if VLIBC_LEVEL_GE(2)
static int
run_vasprintf(char **p, const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
va_list ap;
int rc;
va_start(ap, format);
rc = vasprintf(p, format, ap);
va_end(ap);
return rc;
}
#endif
/* A single snprintf result checked against a golden literal. */
static void
golden(const char *want, const char *format, ...) // NOLINT(bugprone-easily-swappable-parameters)
{
char out[64];
va_list ap;
int rc;
va_start(ap, format);
rc = vsnprintf(out, sizeof out, format, ap);
va_end(ap);
check(rc >= 0 && strcmp(out, want) == 0, want);
}
/* 1. Plain integers: d/i/u/o/x/X over the extremes and the sign cases. */
static void
int_scenario(void)
{
char out[64];
int rc;
golden("0", "%d", 0);
golden("1", "%d", 1);
golden("-1", "%d", -1);
golden("-2147483648", "%d", INT_MIN);
golden("2147483647", "%d", INT_MAX);
golden("-7", "%i", -7);
golden("4294967295", "%u", UINT_MAX);
golden("0", "%u", 0);
golden("10", "%o", 8);
golden("ff", "%x", 255);
golden("FF", "%X", 255);
golden("-9223372036854775808", "%ld", LONG_MIN);
golden("9223372036854775807", "%ld", LONG_MAX);
golden("-9223372036854775808", "%lld", LLONG_MIN);
golden("9223372036854775807", "%lld", LLONG_MAX);
golden("18446744073709551615", "%lu", ULONG_MAX);
rc = snprintf(out, sizeof out, "%d%d", 1, 2);
check(rc == 2 && strcmp(out, "12") == 0, "adjacent conversions concatenate");
rc = snprintf(out, sizeof out, "%s%d", "v", -7);
check(rc == 3 && strcmp(out, "v-7") == 0, "literal text between conversions");
}
/* 2. Length modifiers: hh/h truncation and the j/z/t widths. */
static void
length_scenario(void)
{
golden("44", "%hhd", 300);
golden("4464", "%hd", 70000);
golden("44", "%hhu", 300);
golden("-44", "%hhd", -300);
golden("4000000000", "%zu", (size_t)4000000000UL);
golden("-4000000000", "%zd", (ssize_t)-4000000000L);
golden("123456789", "%tu", (ptrdiff_t)123456789L);
golden("-987654321", "%td", (ptrdiff_t)-987654321L);
golden("18446744073709551615", "%ju", (uintmax_t)UINTMAX_MAX);
golden("-9223372036854775807", "%jd", (intmax_t)-9223372036854775807LL);
golden("ffffffffffffffff", "%lx", (unsigned long)ULONG_MAX);
}
/* 3. The '#' prefixes (octal, hex) and the zero value corner cases. */
static void
alt_scenario(void)
{
golden("0x1abc", "%#x", 0x1abc);
golden("0X1ABC", "%#X", 0x1abc);
golden("010", "%#o", 8);
golden("0", "%#.0o", 0);
golden("0", "%#x", 0);
golden("0", "%#o", 0);
golden("00000010", "%#08o", 8);
golden("010", "%#.3o", 8);
golden("", "%#.0x", 0);
golden(" 0", "%#5.0o", 0);
}
/* 4. Flags and their interactions with width and precision. */
static void
flag_scenario(void)
{
golden("42 ", "%-8d", 42);
golden("+42", "%+d", 42);
golden("-42", "%+d", -42);
golden(" 42", "% d", 42);
golden("-42", "% d", -42);
golden("00000042", "%08d", 42);
golden("42 ", "%-08d", 42);
golden("+0000042", "%+08d", 42);
golden(" 042", "%5.3d", 42);
golden("042 ", "%-5.3d", 42);
golden(" ", "%05.0d", 0);
golden(" 42", "%05.0d", 42);
golden(" 000", "%5.3d", 0);
golden(" 42", "%5d", 42);
golden("42 ", "%-5d", 42);
golden("+0042", "%+05d", 42);
golden(" 42", "%*d", 5, 42);
}
/* 5. Characters, strings, pointers, %n, and the literal percent. */
static void
charstr_scenario(void)
{
char out[64];
int marker;
int n;
int rc;
golden("A", "%c", 'A');
golden("hello", "%s", "hello");
golden("hel", "%.3s", "hello");
golden(" hel", "%5.3s", "hello");
golden("hel ", "%-5.3s", "hello");
golden("(null)", "%s", (char *)0);
golden("%", "%%");
golden("0x0", "%p", (void *)0);
n = -1;
rc = snprintf(out, sizeof out, "abc%n", &n);
check(rc == 3 && n == 3 && strcmp(out, "abc") == 0, "%n stores the count so far");
rc = snprintf(out, sizeof out, "%p", (void *)&marker);
if (rc > 2 && out[0] == '0' && out[1] == 'x')
{
int i;
int hex = 1;
for (i = 2; out[i] != '\0'; i++)
{
if (!((out[i] >= '0' && out[i] <= '9') || (out[i] >= 'a' && out[i] <= 'f')))
{
hex = 0;
}
}
check(hex && i > 2, "%p of a local prints 0x + lowercase hex");
}
else
{
check(0, "%p of a local prints 0x + lowercase hex");
}
}
/* 6. Width and precision supplied through '*'. */
static void
star_scenario(void)
{
golden("00042", "%.*d", 5, 42);
golden("042", "%.*d", 3, 42);
golden("42", "%.*d", -1, 42);
golden("hel", "%.*s", 3, "hello");
}
/* 7. snprintf truncation semantics. */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-truncation"
static void
trunc_scenario(void)
{
char b[8];
int rc;
rc = snprintf(b, 5, "%s", "hello world");
check(rc == 11 && strcmp(b, "hell") == 0,
"snprintf truncates at n-1 and returns the full length");
rc = snprintf((char *)0, 0, "%s", "hello world");
check(rc == 11, "snprintf with n == 0 writes nothing and returns the length");
rc = snprintf(b, 1, "%s", "hello world");
check(rc == 11 && b[0] == '\0', "snprintf with n == 1 writes only the NUL");
}
#pragma GCC diagnostic pop
/* 8. sprintf/vsprintf (no bound). */
static void
sprintf_scenario(void)
{
char s[32];
int rc;
rc = sprintf(s, "%d-%s", 7, "x");
check(rc == 3 && strcmp(s, "7-x") == 0, "sprintf writes past the argument bound");
rc = run_vsprintf(s, "%d-%s", 7, "x");
check(rc == 3 && strcmp(s, "7-x") == 0, "vsprintf writes past the argument bound");
}
/* 9. dprintf/vdprintf to a raw descriptor. */
static void
dprintf_scenario(void)
{
const char path[] = "/tmp/vlibc-test-printf-dprintf.txt";
char buf[64];
long fd;
long got;
int r1;
int r2;
fd = __syscall4(SYS_openat, -100, (long)path, (long)(0x1 | 0x40 | 0x200), 0666);
check(fd >= 0, "dprintf openat succeeds");
if (fd < 0)
{
return;
}
r1 = (dprintf((int)fd, "%d %s", 9, "nine") == 6);
r2 = (run_vdprintf((int)fd, " %#x", 0xbeef) == 7);
__syscall1(SYS_close, fd);
check(r1, "dprintf returns the byte count");
check(r2, "vdprintf returns the byte count");
got = raw_read_all(path, buf, sizeof buf);
check(got == 13 &&
mem_eq((const unsigned char *)buf, (const unsigned char *)"9 nine 0xbeef", 13),
"dprintf content reached the file unbuffered");
check(remove(path) == 0, "remove deletes the dprintf file");
}
/* 10. fprintf/vfprintf through a buffered FILE, read back raw. */
static void
file_scenario(void)
{
const char path[] = "/tmp/vlibc-test-printf-file.txt";
char buf[64];
FILE *f;
long got;
int r1;
int r2;
f = fopen(path, "w");
check(f != NULL, "fopen for fprintf succeeds");
if (f == NULL)
{
return;
}
r1 = (fprintf(f, "%s %d", "abc", 123) == 7);
r2 = (run_vfprintf(f, " %x", 255) == 3);
check(r1, "fprintf returns the byte count");
check(r2, "vfprintf returns the byte count");
check(fclose(f) == 0, "fclose flushes the fprintf file");
got = raw_read_all(path, buf, sizeof buf);
check(got == 10 && mem_eq((const unsigned char *)buf, (const unsigned char *)"abc 123 ff", 10),
"fprintf/vfprintf content reached the file");
check(remove(path) == 0, "remove deletes the fprintf file");
}
/* 11. printf/vprintf through a redirected stdout (the flush is explicit). */
static void
stdout_scenario(void)
{
const char path[] = "/tmp/vlibc-test-printf-stdout.txt";
char buf[64];
long saved;
long fd;
long got;
int r1;
int r2;
int r3;
saved = __syscall1(SYS_dup, 1);
check(saved >= 0, "dup(1) for the printf scenario");
if (saved < 0)
{
return;
}
fd = __syscall4(SYS_openat, -100, (long)path, (long)(0x1 | 0x40 | 0x200), 0666);
if (fd < 0)
{
__syscall2(SYS_dup2, saved, 1);
__syscall1(SYS_close, saved);
check(0, "openat for the printf scenario");
return;
}
__syscall2(SYS_dup2, fd, 1);
__syscall1(SYS_close, fd);
/* No check() output while fd 1 names the file. */
r1 = (printf("%d-%s", 1, "x") == 3);
r2 = (run_vprintf("%c%d", 'q', 5) == 2);
r3 = (fflush(stdout) == 0);
__syscall2(SYS_dup2, saved, 1);
__syscall1(SYS_close, saved);
check(r1, "printf to stdout returns its byte count");
check(r2, "vprintf to stdout returns its byte count");
check(r3, "fflush(stdout) after the redirect");
got = raw_read_all(path, buf, sizeof buf);
check(got == 5 && mem_eq((const unsigned char *)buf, (const unsigned char *)"1-xq5", 5),
"printf/vprintf content reached the redirected stdout");
check(remove(path) == 0, "remove deletes the stdout file");
}
#if VLIBC_LEVEL_GE(2)
/* 12. Level 2: asprintf/vasprintf. */
static void
asprintf_scenario(void)
{
char *p = NULL;
int rc;
rc = asprintf(&p, "%d-%s", 5, "x");
check(rc == 3 && p != NULL && strcmp(p, "5-x") == 0, "asprintf allocates and fills");
free(p);
p = NULL;
rc = run_vasprintf(&p, "%u", 42U);
check(rc == 2 && p != NULL && strcmp(p, "42") == 0, "vasprintf allocates and fills");
free(p);
}
#endif /* VLIBC_LEVEL_GE(2) */
/* Bit-pattern constructors for the float scenarios (host arithmetic cannot
* name every subnormal or sign-of-NaN case portably). */
static double
mkdbl(unsigned long long bits)
{
double v;
memcpy(&v, &bits, sizeof v);
return v;
}
static long double
mkldbl(unsigned e15, unsigned neg, unsigned long long sig)
{
unsigned char raw[16];
long double v;
memset(raw, 0, sizeof raw);
memcpy(raw, &sig, 8);
raw[8] = (unsigned char)(e15 & 0xFF);
raw[9] = (unsigned char)((e15 >> 8) | (neg ? 0x80 : 0));
memcpy(&v, raw, sizeof raw);
return v;
}
/* 13. %a/%A hex floats, the long double L length, and the round-half-even
* hex-digit rounding (all goldens verified against host glibc). */
static void
hexfloat_scenario(void)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Woverlength-strings"
static const char *const ldmax_dec =
"11897314953572317650212638530309702051690633222946242004403237338917370055229707"
"22616410290336528882853545697807495577314427443153670288434198125573853743678673"
"59320070697326320191591828296152436552951064679108661431179063216977883889613478"
"65606003991487534332114549111600886798451548665128523401497730376000091254793939"
"66223151383622417838542743917838138717805889487540575168226347659235576974805113"
"72564902088485522249479139937758502601177354918009979622602685950855888360815984"
"69002356451323465944763849398592764562845796617729304078066092291027150460853880"
"87959327781622986827547830768080040150694942303411728957777100335714010559775242"
"12405734700738625166011082837911962300846927720096515350020847447079244384854591"
"28867230006190851264721119513614675276335195629275979572502780029807959041931396"
"03021470997035276467445530922022679656280991498232083329641241038509239184734786"
"12192169721054348428704835340811304257300221642134891734717423480071488075100206"
"43905172342476560047217680964861079949434157034763206435586242074435044243805661"
"36017608837478165389027809576975977286860071487028287955567141404632615832623602"
"76289631617397848425448686060994827086796804807870251185893083854658422304090880"
"59962945945862019037660484467909260022254105307759010657606713472001258464069570"
"30257138960983757998926954553052368560758683179223113639519468850880771872104705"
"20395758748001314313144425494391994017575316933939236688185618912993172910425292"
"12368351599223220509980016771027840353601408292963981151228777681357060457893435"
"35451696539561254048846447169786893211671087229088082778350518228857646062218739"
"70285165508372099234948333443522898475123275372663606621390228126470623407535207"
"17240586650795182173034637826313533937067749019501978416904418247380631628285868"
"57741432581165364040218402724913393320949219498422442730427019873044536620350262"
"38695780468200360144729199712309553005720614186697485284685618651483271597448120"
"31219467516863793430961896151073300655524214851952017628585950910518394725028638"
"71632494167613804996319791441870254302706758495192008837915169401581740046711477"
"87720145964446117520405945350476472180797576111172084627363927960033967047003761"
"33745095531841500737964126050479232516613548412918842113408230154733047540670728"
"18763503617332908005951896325207071673904547777129682265206225651439919376804400"
"29238090311243791261477625596469422198137514696707944687035800439250765945161837"
"98118593920495440361149153107822510726914869798092409467721427270124043771874092"
"16756613634938900451232351668146089322400697993176017805338191849981933008410985"
"99393876029260139091141452600372028487213241195542428210183120421610446740462163"
"53369005836646065911562987647455250681450039329414041314954006776029510059622530"
"22823003631473824681059648442441324864573137437595096416168048024129351876204668"
"13563687753281467553879887177183651289394719533506188500326760735438867336800207"
"43878496570145760903498575712430451020387304948542567024793393228091105260415385"
"28994849203991091946129912491633289917998094380337879522093131466946149705939664"
"15237594928589096048991612194498998638483702248667224914892467841020618336462741"
"69695763076324802355879752452537370354338829608627534277400163334340550835370485"
"07374544819754722228975281083020898682633020285259923084168054539687911418297629"
"98896457648276528750456285492426516521775079951625966922911497778896235667095662"
"71384820181913483216879958636526376209782850700993372943967846398790249145142227"
"42527006363942327998483976739987154418554201562244154926653014515504685489258620"
"27608576183712976335876121538256512963353814166394951655600026415918655485005705"
"26114319529199188079545223946496276356301785808966922264062353828985358675959906"
"47008385687123810329591926494846250768992258419305480763620215089022149220528069"
"84201835084058693849381549890944546197789302911357651677540623227829831403347327"
"66039522316034228247175281818188443048809213219335508698733958612760736708666523"
"75555675803171490108477320096424318780070008797346032906278943553743564448851907"
"19161645514115576193939969076741515640282654366402676009508752394550734155613586"
"79330660317447209244465135323666476497354008519670407711036405381500734868917983"
"64049570606189535005089840913826869535090066783324472578712196604415284924840041"
"85093281190896363417573989716659600075948780061916409485433875852065711654107226"
"09962881501231443779440087493019447443307843889957018427100048083050121771235606"
"22895076269042856800047718893158089358515593863176652948089031267747029662545110"
"86154895839508779675546413794489596052797520987481383976257859210575628440175934"
"93241621483395653501891968113890918437957347032694063428900878058469403524534793"
"98080674273236297887100867175802531561302356064878709259865288416350972529537091"
"11431720488774740553905400942537542411931794417513706468964386151771884986701034"
"15325423859110896247108853858086888377772586485641459342621210866475884892600317"
"62345960769508849149662444156604419552086811989770240";
#pragma GCC diagnostic pop
double pos_inf = mkdbl(0x7FF0000000000000ULL);
double neg_inf = mkdbl(0xFFF0000000000000ULL);
double pos_nan = mkdbl(0x7FF8000000000000ULL);
double neg_nan = mkdbl(0xFFF8000000000000ULL);
double maxsub = mkdbl(0x000FFFFFFFFFFFFFULL);
char out[6000];
int rc;
golden("0x0p+0", "%a", 0.0);
golden("0x1p+0", "%a", 1.0);
golden("0x1.8p+0", "%a", 1.5);
golden("0x1p-1", "%a", 0.5);
golden("0x1.91eb851eb851fp+1", "%a", 3.14);
golden("0x1.fffffffffffffp+1023", "%a", DBL_MAX);
golden("0x2p+1023", "%.0a", DBL_MAX);
golden("0x2.0p+1023", "%.1a", DBL_MAX);
golden("0x0.0000000000001p-1022", "%a", DBL_TRUE_MIN);
golden("0x0.0p-1022", "%.1a", DBL_TRUE_MIN);
golden("0x0p-1022", "%.0a", DBL_TRUE_MIN);
golden("0x0.fffffffffffffp-1022", "%a", maxsub);
golden("0x1.0p-1022", "%.1a", maxsub);
golden("0x1p-1022", "%.0a", maxsub);
golden("0x0.0000p-1022", "%.4a", DBL_TRUE_MIN);
golden("0x1.81cd6e631f8a1p+13", "%a", 12345.6789);
golden("0x1.8000000000000p+0", "%.13a", 1.5);
golden("0x1.8000000000000000p+0", "%.16a", 1.5);
golden("0x2.0p+0", "%.1a", 0x1.fffffffffffffp+0);
golden("0x2p+0", "%.0a", 0x1.8p+0);
golden("0x1p+0", "%.0a", 0x1.4p+0);
golden("0x2p-1", "%.0a", 0x1.fffffffffffffp-1);
golden("0x1.000p+0", "%.3a", 1.0);
golden("0x1.p+0", "%#a", 1.0);
golden("0x2.p+0", "%#.0a", 1.5);
golden("0x0.p+0", "%#.0a", 0.0);
golden("0x0.p+0", "%#a", 0.0);
golden("0x0.000p+0", "%.3a", 0.0);
golden("0x0000000000001.8p+0", "%020a", 1.5);
golden("+0x000000000001.8p+0", "%+020a", 1.5);
golden("+0x1.8p+0", "%+a", 1.5);
golden(" 0x1.8p+0", "% a", 1.5);
golden("+0x1.8p+0 ", "%-+20a", 1.5);
golden("0x1.8p+0 ", "%-20a", 1.5);
golden("0x1.800p+0", "%.3a", 1.5);
golden("+0x1.800p+0", "%+08.3a", 1.5);
golden("0X1.8P+0", "%A", 1.5);
golden("0X1.91EB851EB851FP+1", "%A", 3.14);
golden("0X1.FFFFFFFFFFFFFP+1023", "%A", DBL_MAX);
golden("0X2P+0", "%.0A", 1.5);
golden("inf", "%a", pos_inf);
golden("-inf", "%a", neg_inf);
golden("nan", "%a", pos_nan);
golden("-nan", "%a", neg_nan);
golden("INF", "%A", pos_inf);
golden("NAN", "%A", pos_nan);
golden("inf", "%La", mkldbl(0x7FFF, 0, 0x8000000000000000ULL));
golden("-inf", "%La", mkldbl(0x7FFF, 1, 0x8000000000000000ULL));
golden("-nan", "%La", mkldbl(0x7FFF, 1, 0x0000000000000001ULL));
golden("0x8p-3", "%La", 1.0L);
golden("0xcp-3", "%La", 1.5L);
golden("0xcp-3", "%.0La", 0xcp-3L);
golden("0xc.0p-3", "%.1La", 0xcp-3L);
golden("0x8p-4", "%La", 0.5L);
golden("0xc.8f5c28f5c28f5c3p-2", "%La", 3.14L);
golden("0xf.fffffffffffffffp+16380", "%La", LDBL_MAX);
golden("0x1p+16384", "%.0La", LDBL_MAX);
golden("0x1.0p+16384", "%.1La", LDBL_MAX);
golden("0x8p-16385", "%La", LDBL_MIN);
golden("0x8.0p-16385", "%.1La", LDBL_MIN);
golden("0x0.000000000000001p-16385", "%La", LDBL_TRUE_MIN);
golden("0x0.0p-16385", "%.1La", LDBL_TRUE_MIN);
golden("0x0p-16385", "%.0La", LDBL_TRUE_MIN);
golden("0xc.p-3", "%#.0La", 1.5L);
golden("0x0.p+0", "%#.0La", 0.0L);
golden("-0xcp-3", "%La", -1.5L);
golden("-0x0p+0", "%.0La", -0.0L);
golden("0x0.0p+0", "%.1La", 0.0L);
golden("0xc.000p-3", "%.3La", 1.5L);
golden("0xc.000000000000000p-3", "%.15La", 1.5L);
golden("0x00000000000000cp-3", "%020La", 1.5L);
golden("+0x1p+16384", "%+.0La", LDBL_MAX);
golden("0x1p+4", "%.0La", 0xf.fffffffffffffffp+0L);
golden("0x1.0p+4", "%.1La", 0xf.fffffffffffffffp+0L);
golden("0XCP-3", "%LA", 1.5L);
golden("0XC.8F5C28F5C28F5C3P-2", "%LA", 3.14L);
golden("0xc.0e6b7318fc50481p+10", "%La", 12345.6789L);
golden("0xc.8p-3", "%.1La", 0xc.8p-3L);
golden("0xcp-3", "%.0La", 0xc.8p-3L);
golden("0xc.000000000000001p-3", "%.15La", 0xc.000000000000001p-3L);
golden("1.500000e+00", "%Le", 1.5L);
golden("1.500000", "%Lf", 1.5L);
golden("1.5", "%Lg", 1.5L);
golden("-0.000000e+00", "%Le", -0.0L);
golden("-0.000000", "%Lf", -0.0L);
golden("3.14159", "%Lg", 3.14159L);
golden("3.141590", "%Lf", 3.14159L);
golden("3.141590e+00", "%Le", 3.14159L);
golden("0.500000", "%Lf", 0.5L);
golden("1.000000", "%Lf", 1.0L);
golden("0.0001", "%Lg", 0.0001L);
golden("1.189731e+4932", "%Le", LDBL_MAX);
golden("0.000000", "%Lf", 0.0L);
golden("3.14159", "%.6Lg", 3.14159L);
golden("1.5", "%Lg", 1.5000001L);
rc = snprintf(out, sizeof out, "%.0Lf", LDBL_MAX);
check(rc == 4933 && strcmp(out, ldmax_dec) == 0,
"%.0Lf of LDBL_MAX prints all 4933 digits (no truncation)");
rc = snprintf(out, sizeof out, "%Lf", LDBL_MAX);
check(rc == 4940 && out[0] == '1' && strncmp(out, "11897314953572317650", 20) == 0 &&
out[4933] == '.' && out[4939] == '0',
"%Lf of LDBL_MAX fills the 4933-digit integer part");
}
int
main(void)
{
int_scenario();
length_scenario();
alt_scenario();
flag_scenario();
charstr_scenario();
star_scenario();
trunc_scenario();
sprintf_scenario();
dprintf_scenario();
file_scenario();
stdout_scenario();
#if VLIBC_LEVEL_GE(2)
asprintf_scenario();
#endif
hexfloat_scenario();
if (failures > 0)
{
say(2, "FAILED (");
say_dec(2, (unsigned long)failures);
say(2, " check(s))\n");
return 1;
}
say(1, "all printf tests passed\n");
return 0;
}