/* * 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 #include #include #include #include #include #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; }