From e816e97762ae661684e3c7d01cb3e68985c2db41 Mon Sep 17 00:00:00 2001 From: Gabriel Ravier Date: Thu, 23 Mar 2023 21:58:14 +0100 Subject: [PATCH] Fix printf-family function not treating negative precisions as if they had been omitted The C standard states that, within the context of a printf-family function, when specifying the precision of a conversion specification: > A negative precision argument is taken as if the precision were > omitted. - C Standard, 7.23.6.1. The fprintf function Cosmopolitan currently fails to do so and treats a negative precision as if it had a value of 0, which is non-conforming. This patch fixes this. --- libc/fmt/fmt.c | 4 +++- test/libc/fmt/fmt_test.c | 19 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/libc/fmt/fmt.c b/libc/fmt/fmt.c index 99b8e8afd..b6f90a588 100644 --- a/libc/fmt/fmt.c +++ b/libc/fmt/fmt.c @@ -16,10 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/fmt/fmt.h" + #include "libc/assert.h" #include "libc/errno.h" #include "libc/fmt/conv.h" -#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.internal.h" #include "libc/fmt/internal.h" #include "libc/fmt/itoa.h" @@ -255,6 +256,7 @@ _Hide int __fmt(void *fn, void *arg, const char *format, va_list va) { } if (prec < 0) { prec = 0; + flags &= ~FLAGS_PRECISION; } // evaluate length field diff --git a/test/libc/fmt/fmt_test.c b/test/libc/fmt/fmt_test.c index bccd22e9a..4f481d44f 100644 --- a/test/libc/fmt/fmt_test.c +++ b/test/libc/fmt/fmt_test.c @@ -17,6 +17,7 @@ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ #include "libc/fmt/fmt.h" + #include "libc/limits.h" #include "libc/log/log.h" #include "libc/math.h" @@ -84,6 +85,24 @@ TEST(fmt, b) { } TEST(fmt, s) { + EXPECT_STREQ("123456", _gc(xasprintf("%4.*s", -5, "123456"))); + EXPECT_STREQ("123456789", _gc(xasprintf("%4.*s", -5, "123456789"))); + EXPECT_STREQ("12345678901234567890", + _gc(xasprintf("%4.*s", -5, "12345678901234567890"))); + EXPECT_STREQ("123456789012345678901234567890", + _gc(xasprintf("%4.*s", -5, "123456789012345678901234567890"))); + EXPECT_STREQ( + "1234567890123456789012345678901234567890", + _gc(xasprintf("%4.*s", -5, "1234567890123456789012345678901234567890"))); + EXPECT_STREQ( + "12345678901234567890123456789012345678901234567890", + _gc(xasprintf("%4.*s", -5, + "12345678901234567890123456789012345678901234567890"))); + EXPECT_STREQ( + "123456789012345678901234567890123456789012345678901234567890", + _gc(xasprintf( + "%4.*s", -5, + "123456789012345678901234567890123456789012345678901234567890"))); EXPECT_STREQ("Wide character output test", _gc(xasprintf("%S", L"Wide character output test"))); }