From c8f573b3ac5d17eb2e3d0019acfa42a2b9208d63 Mon Sep 17 00:00:00 2001 From: ahgamut <41098605+ahgamut@users.noreply.github.com> Date: Thu, 16 Jun 2022 09:12:33 +0530 Subject: [PATCH] scan fixed-width integers in vcscanf when a format string like %2x is provided, the width parameter was read correctly as 2, but it was not used when decoding the number from the input string (ie instead of reading 2 characters from the input string, vcscanf read all the characters). this change uses the value of width within the number decoding loop to read fixed number of digits correctly. if width is zero (not provided), the default of width is set as bits. also added a test for this specific use case. --- libc/fmt/vcscanf.c | 4 +++- test/libc/fmt/sscanf_test.c | 8 ++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libc/fmt/vcscanf.c b/libc/fmt/vcscanf.c index 4dda5b761..6098dc2a6 100644 --- a/libc/fmt/vcscanf.c +++ b/libc/fmt/vcscanf.c @@ -177,9 +177,11 @@ int vcscanf(int callback(void *), int unget(int, void *), void *arg, DecodeNumber: if (c != -1) { number = 0; + width = !width ? bits : width; do { diglet = kBase36[(unsigned char)c]; if (1 <= diglet && diglet <= base) { + width -= 1; number *= base; number += diglet - 1; } else if (thousands && diglet == ',') { @@ -187,7 +189,7 @@ int vcscanf(int callback(void *), int unget(int, void *), void *arg, } else { break; } - } while ((c = callback(arg)) != -1); + } while ((c = callback(arg)) != -1 && width > 0); if (!discard) { uint128_t bane = (uint128_t)1 << (bits - 1); if (!(number & ~((bane - 1) | (issigned ? 0 : bane))) || diff --git a/test/libc/fmt/sscanf_test.c b/test/libc/fmt/sscanf_test.c index 7705985d3..2ce8194fa 100644 --- a/test/libc/fmt/sscanf_test.c +++ b/test/libc/fmt/sscanf_test.c @@ -141,3 +141,11 @@ TEST(sscanf, testDiscard_notIncludedInCount) { ASSERT_EQ(1, sscanf("hello there", "%*s %8s", buf)); EXPECT_STREQ("there", buf); } + +TEST(sscanf, testFixedWidthFormat_Integer) { + int r, g, b; + ASSERT_EQ(3, sscanf("#321030", "#%2x%2b%2d", &r, &g, &b)); + ASSERT_EQ(0x32, r); + ASSERT_EQ(2, g); + ASSERT_EQ(30, b); +}