* [PATCH v2 0/2] tools/nolibc: printf left alignment and zero padding
@ 2026-01-28 9:42 licheng.li
2026-01-28 9:42 ` [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf licheng.li
2026-01-28 9:42 ` [PATCH v2 2/2] selftests/nolibc: add tests for printf left alignment and zero padding licheng.li
0 siblings, 2 replies; 10+ messages in thread
From: licheng.li @ 2026-01-28 9:42 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel, im.lechain
This series adds support for left alignment ('-') and zero padding ('0')
to nolibc's printf implementation.
v2 incorporates optimizations suggested by Willy Tarreau to further reduce
binary size, and updates the commit message to accurately reflect the
supported features.
Cheng Li (2):
tools/nolibc: support left alignment (-) and zero padding (0) in
printf
selftests/nolibc: add tests for printf left alignment and zero padding
tools/include/nolibc/stdio.h | 20 ++++++++++++++++----
tools/testing/selftests/nolibc/nolibc-test.c | 2 ++
2 files changed, 18 insertions(+), 4 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-28 9:42 [PATCH v2 0/2] tools/nolibc: printf left alignment and zero padding licheng.li
@ 2026-01-28 9:42 ` licheng.li
2026-01-29 6:41 ` Willy Tarreau
2026-01-29 10:30 ` David Laight
2026-01-28 9:42 ` [PATCH v2 2/2] selftests/nolibc: add tests for printf left alignment and zero padding licheng.li
1 sibling, 2 replies; 10+ messages in thread
From: licheng.li @ 2026-01-28 9:42 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel, im.lechain
From: Cheng Li <im.lechain@gmail.com>
Currently, __nolibc_printf() in nolibc parses the width field but always
pads with spaces on the left. It ignores the '-' flag (left alignment)
and treats leading zeros in the width as part of the number parsing
(resulting in space padding instead of zero padding).
This patch implements support for:
1. The '-' flag: forces left alignment by padding spaces on the right.
2. The '0' flag: forces zero padding on the left instead of spaces.
The implementation reuses the padding character logic to handle both
cases.
Logic behavior:
- "%5d" -> " 12" (unchanged)
- "%-5d" -> "12 " (new: left align)
- "%05d" -> "00012" (new: zero pad)
- "%-05d"-> "12 " (new: left align overrides zero pad)
The code is optimized to keep the binary size impact minimal.
Measuring the nolibc-test binary on x86_64:
text data bss dec hex filename
43552 248 112 43912 ab88 nolibc-test (before)
43677 248 112 44037 ac05 nolibc-test (after)
The net increase is 125 bytes.
Suggested-by: Willy Tarreau <w@1wt.eu>
Signed-off-by: Cheng Li <im.lechain@gmail.com>
---
v2 changes:
- Adopted optimization suggestions from Willy Tarreau:
- Incremented 'written' counter at the start of loops.
- Reordered loop checks to optimize compiler register usage.
- Updated commit message to explicitly mention zero-padding ('0') support.
---
tools/include/nolibc/stdio.h | 20 ++++++++++++++++----
1 file changed, 16 insertions(+), 4 deletions(-)
diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
index 1f16dab2ac88..df8a96e39986 100644
--- a/tools/include/nolibc/stdio.h
+++ b/tools/include/nolibc/stdio.h
@@ -250,7 +250,7 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
static __attribute__((unused, format(printf, 4, 0)))
int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
{
- char escape, lpref, c;
+ char escape, lpref, padc, c;
unsigned long long v;
unsigned int written, width;
size_t len, ofs, w;
@@ -261,11 +261,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
while (1) {
c = fmt[ofs++];
width = 0;
+ padc = ' ';
if (escape) {
/* we're in an escape sequence, ofs == 1 */
escape = 0;
+ if (c == '-' || c == '0') {
+ padc = c;
+ c = fmt[ofs++];
+ }
+
/* width */
while (c >= '0' && c <= '9') {
width *= 10;
@@ -358,13 +364,19 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
if (n) {
w = len < n ? len : n;
n -= w;
- while (width-- > w) {
- if (cb(state, " ", 1) != 0)
- return -1;
+ while (width > w && padc != '-') {
written += 1;
+ if (cb(state, &padc, 1) != 0)
+ return -1;
+ width--;
}
if (cb(state, outstr, w) != 0)
return -1;
+ while (width-- > w) {
+ written += 1;
+ if (cb(state, " ", 1) != 0)
+ return -1;
+ }
}
written += len;
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/2] selftests/nolibc: add tests for printf left alignment and zero padding
2026-01-28 9:42 [PATCH v2 0/2] tools/nolibc: printf left alignment and zero padding licheng.li
2026-01-28 9:42 ` [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf licheng.li
@ 2026-01-28 9:42 ` licheng.li
1 sibling, 0 replies; 10+ messages in thread
From: licheng.li @ 2026-01-28 9:42 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel, im.lechain
From: Cheng Li <im.lechain@gmail.com>
This patch adds validation for the recently added left-alignment ('-')
and zero-padding ('0') flags in printf().
It ensures that:
- Fields are correctly padded with spaces on the right when the '-'
flag is used.
- Integers are correctly padded with zeroes on the left when the '0'
flag is used.
Signed-off-by: Cheng Li <im.lechain@gmail.com>
---
v2 changes:
- Added test cases for zero padding (%08d)
---
tools/testing/selftests/nolibc/nolibc-test.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/tools/testing/selftests/nolibc/nolibc-test.c b/tools/testing/selftests/nolibc/nolibc-test.c
index 3c5a226dad3a..47b20ecf5242 100644
--- a/tools/testing/selftests/nolibc/nolibc-test.c
+++ b/tools/testing/selftests/nolibc/nolibc-test.c
@@ -1723,6 +1723,8 @@ static int run_printf(int min, int max)
CASE_TEST(truncation); EXPECT_VFPRINTF(25, "01234567890123456789", "%s", "0123456789012345678901234"); break;
CASE_TEST(string_width); EXPECT_VFPRINTF(10, " 1", "%10s", "1"); break;
CASE_TEST(number_width); EXPECT_VFPRINTF(10, " 1", "%10d", 1); break;
+ CASE_TEST(leading_zero); EXPECT_VFPRINTF(10, "|00000001|", "|%08d|", 1); break;
+ CASE_TEST(left_align); EXPECT_VFPRINTF(10, "|foo |", "|%-8s|", "foo"); break;
CASE_TEST(width_trunc); EXPECT_VFPRINTF(25, " ", "%25d", 1); break;
CASE_TEST(scanf); EXPECT_ZR(1, test_scanf()); break;
CASE_TEST(strerror); EXPECT_ZR(1, test_strerror()); break;
--
2.52.0
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-28 9:42 ` [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf licheng.li
@ 2026-01-29 6:41 ` Willy Tarreau
2026-01-29 6:57 ` licheng
2026-01-29 10:30 ` David Laight
1 sibling, 1 reply; 10+ messages in thread
From: Willy Tarreau @ 2026-01-29 6:41 UTC (permalink / raw)
To: licheng.li; +Cc: Thomas Weißschuh, linux-kernel
Hi Cheng,
On Wed, Jan 28, 2026 at 05:42:23PM +0800, licheng.li wrote:
> From: Cheng Li <im.lechain@gmail.com>
>
> Currently, __nolibc_printf() in nolibc parses the width field but always
> pads with spaces on the left. It ignores the '-' flag (left alignment)
> and treats leading zeros in the width as part of the number parsing
> (resulting in space padding instead of zero padding).
>
> This patch implements support for:
> 1. The '-' flag: forces left alignment by padding spaces on the right.
> 2. The '0' flag: forces zero padding on the left instead of spaces.
>
> The implementation reuses the padding character logic to handle both
> cases.
>
> Logic behavior:
> - "%5d" -> " 12" (unchanged)
> - "%-5d" -> "12 " (new: left align)
> - "%05d" -> "00012" (new: zero pad)
> - "%-05d"-> "12 " (new: left align overrides zero pad)
>
> The code is optimized to keep the binary size impact minimal.
> Measuring the nolibc-test binary on x86_64:
>
> text data bss dec hex filename
> 43552 248 112 43912 ab88 nolibc-test (before)
> 43677 248 112 44037 ac05 nolibc-test (after)
>
> The net increase is 125 bytes.
Is it normal this didn't change since previous patch, or did you just
forget to update that part of the commit message? In my case I'm seeing
a difference:
text data bss dec hex filename
35964 112 120 36196 8d64 nolibc-test-before
36070 112 120 36302 8dce nolibc-test-after1 <- first patchset: +106
36044 112 120 36276 8db4 nolibc-test-after2 <- this patchset: +80
If it's just an omission, I can edit the commit message if you paste
the new before/after in response, and save you from a respin just for
this! If it didn't change anything, that's possible as well, but
surprising, which is why I preferred to ask.
Thanks,
Willy
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-29 6:41 ` Willy Tarreau
@ 2026-01-29 6:57 ` licheng
2026-01-29 7:07 ` Willy Tarreau
0 siblings, 1 reply; 10+ messages in thread
From: licheng @ 2026-01-29 6:57 UTC (permalink / raw)
To: Willy Tarreau; +Cc: Thomas Weißschuh, linux-kernel
Hi Willy,
Willy Tarreau <w@1wt.eu> 于2026年1月29日周四 14:41写道:
>
> Hi Cheng,
>
> On Wed, Jan 28, 2026 at 05:42:23PM +0800, licheng.li wrote:
> > From: Cheng Li <im.lechain@gmail.com>
> >
> > Currently, __nolibc_printf() in nolibc parses the width field but always
> > pads with spaces on the left. It ignores the '-' flag (left alignment)
> > and treats leading zeros in the width as part of the number parsing
> > (resulting in space padding instead of zero padding).
> >
> > This patch implements support for:
> > 1. The '-' flag: forces left alignment by padding spaces on the right.
> > 2. The '0' flag: forces zero padding on the left instead of spaces.
> >
> > The implementation reuses the padding character logic to handle both
> > cases.
> >
> > Logic behavior:
> > - "%5d" -> " 12" (unchanged)
> > - "%-5d" -> "12 " (new: left align)
> > - "%05d" -> "00012" (new: zero pad)
> > - "%-05d"-> "12 " (new: left align overrides zero pad)
> >
> > The code is optimized to keep the binary size impact minimal.
> > Measuring the nolibc-test binary on x86_64:
> >
> > text data bss dec hex filename
> > 43552 248 112 43912 ab88 nolibc-test (before)
> > 43677 248 112 44037 ac05 nolibc-test (after)
> >
> > The net increase is 125 bytes.
>
> Is it normal this didn't change since previous patch, or did you just
> forget to update that part of the commit message? In my case I'm seeing
> a difference:
>
> text data bss dec hex filename
> 35964 112 120 36196 8d64 nolibc-test-before
> 36070 112 120 36302 8dce nolibc-test-after1 <- first patchset: +106
> 36044 112 120 36276 8db4 nolibc-test-after2 <- this patchset: +80
>
> If it's just an omission, I can edit the commit message if you paste
> the new before/after in response, and save you from a respin just for
> this! If it didn't change anything, that's possible as well, but
> surprising, which is why I preferred to ask.
Thanks for catching this! You are right, I missed updating the binary
size data in the v2 commit message. I performed the previous measurement
using the simplest command: `make -C tools/testing/selftests/nolibc'
The discrepancy in absolute numbers is likely caused by the different compiler
versions and optimization levels between our environments. Since your
environment
shows a more accurate delta for the current upstream state, please feel free to
update the commit message directly to save a respin.
Thank you for your help and for the detailed review!
Best regards, Cheng Li
> Thanks,
> Willy
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-29 6:57 ` licheng
@ 2026-01-29 7:07 ` Willy Tarreau
0 siblings, 0 replies; 10+ messages in thread
From: Willy Tarreau @ 2026-01-29 7:07 UTC (permalink / raw)
To: licheng; +Cc: Thomas Weißschuh, linux-kernel
On Thu, Jan 29, 2026 at 02:57:26PM +0800, licheng wrote:
> Hi Willy,
>
> Willy Tarreau <w@1wt.eu> ?2026?1?29??? 14:41??:
> >
> > Hi Cheng,
> >
> > On Wed, Jan 28, 2026 at 05:42:23PM +0800, licheng.li wrote:
> > > From: Cheng Li <im.lechain@gmail.com>
> > >
> > > Currently, __nolibc_printf() in nolibc parses the width field but always
> > > pads with spaces on the left. It ignores the '-' flag (left alignment)
> > > and treats leading zeros in the width as part of the number parsing
> > > (resulting in space padding instead of zero padding).
> > >
> > > This patch implements support for:
> > > 1. The '-' flag: forces left alignment by padding spaces on the right.
> > > 2. The '0' flag: forces zero padding on the left instead of spaces.
> > >
> > > The implementation reuses the padding character logic to handle both
> > > cases.
> > >
> > > Logic behavior:
> > > - "%5d" -> " 12" (unchanged)
> > > - "%-5d" -> "12 " (new: left align)
> > > - "%05d" -> "00012" (new: zero pad)
> > > - "%-05d"-> "12 " (new: left align overrides zero pad)
> > >
> > > The code is optimized to keep the binary size impact minimal.
> > > Measuring the nolibc-test binary on x86_64:
> > >
> > > text data bss dec hex filename
> > > 43552 248 112 43912 ab88 nolibc-test (before)
> > > 43677 248 112 44037 ac05 nolibc-test (after)
> > >
> > > The net increase is 125 bytes.
> >
> > Is it normal this didn't change since previous patch, or did you just
> > forget to update that part of the commit message? In my case I'm seeing
> > a difference:
> >
> > text data bss dec hex filename
> > 35964 112 120 36196 8d64 nolibc-test-before
> > 36070 112 120 36302 8dce nolibc-test-after1 <- first patchset: +106
> > 36044 112 120 36276 8db4 nolibc-test-after2 <- this patchset: +80
> >
> > If it's just an omission, I can edit the commit message if you paste
> > the new before/after in response, and save you from a respin just for
> > this! If it didn't change anything, that's possible as well, but
> > surprising, which is why I preferred to ask.
>
> Thanks for catching this! You are right, I missed updating the binary
> size data in the v2 commit message. I performed the previous measurement
> using the simplest command: `make -C tools/testing/selftests/nolibc'
OK!
> The discrepancy in absolute numbers is likely caused by the different compiler
> versions and optimization levels between our environments. Since your
> environment
> shows a more accurate delta for the current upstream state, please feel free to
> update the commit message directly to save a respin.
OK will do. I'll handle this this week-end unless Thomas has other
comments or beats me at it. In case I forget, do not hesitate to ping
me early next week ;-)
thanks,
Willy
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-28 9:42 ` [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf licheng.li
2026-01-29 6:41 ` Willy Tarreau
@ 2026-01-29 10:30 ` David Laight
2026-01-30 1:05 ` Cheng Li
1 sibling, 1 reply; 10+ messages in thread
From: David Laight @ 2026-01-29 10:30 UTC (permalink / raw)
To: licheng.li; +Cc: Willy Tarreau, Thomas Weißschuh, linux-kernel
On Wed, 28 Jan 2026 17:42:23 +0800
"licheng.li" <im.lechain@gmail.com> wrote:
> From: Cheng Li <im.lechain@gmail.com>
>
> Currently, __nolibc_printf() in nolibc parses the width field but always
> pads with spaces on the left. It ignores the '-' flag (left alignment)
> and treats leading zeros in the width as part of the number parsing
> (resulting in space padding instead of zero padding).
>
> This patch implements support for:
> 1. The '-' flag: forces left alignment by padding spaces on the right.
> 2. The '0' flag: forces zero padding on the left instead of spaces.
Does that work properly?
I think it is padding zeros the wrong side of the sign (or "0x").
Try testing with a negative number or a pointer.
You might need to limit the width for numeric fields to (say) 32,
make the on-stack buffer 64 bytes and convert into the middle.
Then add pad zeros to the front before adding any "-" or "0x".
It then gets very close to supporting precisions as well as widths.
It might be worth changing the 'pad' loop to:
while (width > w) {
unsigned int pad_len = ((width - w - 1) & 0xf) + 1;
width -= pad_len;
written += pad_len;
if (cb(state, " ", pad_len) != 0)
return -1;
}
while the code is marginally larger writing the pad in blocks of 16
will be much faster.
The linker should merge all the strings of spaces.
I looked at the (existing) version last night.
If the 'l' flag code is moved to after the width is calculated it all
becomes a lot simpler.
Set 'outstr = fmt' at the top of the loop and the code can use *fmt++
and do a 'fast scan' of the format string for a '%' or '\0' then
output the chars from the format string at the bottom.
I didn't size the change, but getting rid of ofs and escape must help.
Might post it later.
David
>
> The implementation reuses the padding character logic to handle both
> cases.
>
> Logic behavior:
> - "%5d" -> " 12" (unchanged)
> - "%-5d" -> "12 " (new: left align)
> - "%05d" -> "00012" (new: zero pad)
> - "%-05d"-> "12 " (new: left align overrides zero pad)
>
> The code is optimized to keep the binary size impact minimal.
> Measuring the nolibc-test binary on x86_64:
>
> text data bss dec hex filename
> 43552 248 112 43912 ab88 nolibc-test (before)
> 43677 248 112 44037 ac05 nolibc-test (after)
>
> The net increase is 125 bytes.
>
> Suggested-by: Willy Tarreau <w@1wt.eu>
> Signed-off-by: Cheng Li <im.lechain@gmail.com>
> ---
> v2 changes:
> - Adopted optimization suggestions from Willy Tarreau:
> - Incremented 'written' counter at the start of loops.
> - Reordered loop checks to optimize compiler register usage.
> - Updated commit message to explicitly mention zero-padding ('0') support.
> ---
> tools/include/nolibc/stdio.h | 20 ++++++++++++++++----
> 1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
> index 1f16dab2ac88..df8a96e39986 100644
> --- a/tools/include/nolibc/stdio.h
> +++ b/tools/include/nolibc/stdio.h
> @@ -250,7 +250,7 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
> static __attribute__((unused, format(printf, 4, 0)))
> int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
> {
> - char escape, lpref, c;
> + char escape, lpref, padc, c;
> unsigned long long v;
> unsigned int written, width;
> size_t len, ofs, w;
> @@ -261,11 +261,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> while (1) {
> c = fmt[ofs++];
> width = 0;
> + padc = ' ';
>
> if (escape) {
> /* we're in an escape sequence, ofs == 1 */
> escape = 0;
>
> + if (c == '-' || c == '0') {
> + padc = c;
> + c = fmt[ofs++];
> + }
> +
> /* width */
> while (c >= '0' && c <= '9') {
> width *= 10;
> @@ -358,13 +364,19 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> if (n) {
> w = len < n ? len : n;
> n -= w;
> - while (width-- > w) {
> - if (cb(state, " ", 1) != 0)
> - return -1;
> + while (width > w && padc != '-') {
> written += 1;
> + if (cb(state, &padc, 1) != 0)
> + return -1;
> + width--;
> }
> if (cb(state, outstr, w) != 0)
> return -1;
> + while (width-- > w) {
> + written += 1;
> + if (cb(state, " ", 1) != 0)
> + return -1;
> + }
> }
>
> written += len;
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-29 10:30 ` David Laight
@ 2026-01-30 1:05 ` Cheng Li
2026-01-30 8:01 ` David Laight
0 siblings, 1 reply; 10+ messages in thread
From: Cheng Li @ 2026-01-30 1:05 UTC (permalink / raw)
To: David Laight; +Cc: Willy Tarreau, Thomas Weißschuh, linux-kernel
David Laight <david.laight.linux@gmail.com> 于2026年1月29日周四 18:30写道:
>
> On Wed, 28 Jan 2026 17:42:23 +0800
> "licheng.li" <im.lechain@gmail.com> wrote:
>
> > From: Cheng Li <im.lechain@gmail.com>
> >
> > Currently, __nolibc_printf() in nolibc parses the width field but always
> > pads with spaces on the left. It ignores the '-' flag (left alignment)
> > and treats leading zeros in the width as part of the number parsing
> > (resulting in space padding instead of zero padding).
> >
> > This patch implements support for:
> > 1. The '-' flag: forces left alignment by padding spaces on the right.
> > 2. The '0' flag: forces zero padding on the left instead of spaces.
>
> Does that work properly?
> I think it is padding zeros the wrong side of the sign (or "0x").
> Try testing with a negative number or a pointer.
>
> You might need to limit the width for numeric fields to (say) 32,
> make the on-stack buffer 64 bytes and convert into the middle.
> Then add pad zeros to the front before adding any "-" or "0x".
You are absolutely right. I just tested printf("%05d", -5) and it
resulted in 000-5,
which is incorrect. Standard behavior should be -0005.
Since nolibc constructs the integer string (including the sign) before
this padding logic,
implementing correct zero-padding for negative numbers would require
parsing the buffer
or refactoring the conversion logic. This would add significant
complexity and size,
which goes against the goal of this small patch.
Proposed solution:
I will drop the implicit support for the '0' flag from this patch and
revert to my original goal: strictly supporting left alignment ('-').
Left alignment pads spaces on the right (-5 ), so it does not suffer
from the sign issue.
> It then gets very close to supporting precisions as well as widths.
> It might be worth changing the 'pad' loop to:
> while (width > w) {
> unsigned int pad_len = ((width - w - 1) & 0xf) + 1;
> width -= pad_len;
> written += pad_len;
> if (cb(state, " ", pad_len) != 0)
> return -1;
> }
> while the code is marginally larger writing the pad in blocks of 16
> will be much faster.
> The linker should merge all the strings of spaces.
>
> I looked at the (existing) version last night.
> If the 'l' flag code is moved to after the width is calculated it all
> becomes a lot simpler.
> Set 'outstr = fmt' at the top of the loop and the code can use *fmt++
> and do a 'fast scan' of the format string for a '%' or '\0' then
> output the chars from the format string at the bottom.
> I didn't size the change, but getting rid of ofs and escape must help.
These are great suggestions for a larger refactoring of printf to
improve performance and standard compliance.
However, to keep this current change minimal and safe, I prefer to
focus on fixing the alignment feature first.
@Willy, I will send a v3 that removes the '0' flag handling logic to
avoid the bug pointed out above.
I will rethink how to implement leading zero pad support.
Best regards,
Cheng
> Might post it later.
>
> David
>
>
> >
> > The implementation reuses the padding character logic to handle both
> > cases.
> >
> > Logic behavior:
> > - "%5d" -> " 12" (unchanged)
> > - "%-5d" -> "12 " (new: left align)
> > - "%05d" -> "00012" (new: zero pad)
> > - "%-05d"-> "12 " (new: left align overrides zero pad)
> >
> > The code is optimized to keep the binary size impact minimal.
> > Measuring the nolibc-test binary on x86_64:
> >
> > text data bss dec hex filename
> > 43552 248 112 43912 ab88 nolibc-test (before)
> > 43677 248 112 44037 ac05 nolibc-test (after)
> >
> > The net increase is 125 bytes.
> >
> > Suggested-by: Willy Tarreau <w@1wt.eu>
> > Signed-off-by: Cheng Li <im.lechain@gmail.com>
> > ---
> > v2 changes:
> > - Adopted optimization suggestions from Willy Tarreau:
> > - Incremented 'written' counter at the start of loops.
> > - Reordered loop checks to optimize compiler register usage.
> > - Updated commit message to explicitly mention zero-padding ('0') support.
> > ---
> > tools/include/nolibc/stdio.h | 20 ++++++++++++++++----
> > 1 file changed, 16 insertions(+), 4 deletions(-)
> >
> > diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
> > index 1f16dab2ac88..df8a96e39986 100644
> > --- a/tools/include/nolibc/stdio.h
> > +++ b/tools/include/nolibc/stdio.h
> > @@ -250,7 +250,7 @@ typedef int (*__nolibc_printf_cb)(intptr_t state, const char *buf, size_t size);
> > static __attribute__((unused, format(printf, 4, 0)))
> > int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char *fmt, va_list args)
> > {
> > - char escape, lpref, c;
> > + char escape, lpref, padc, c;
> > unsigned long long v;
> > unsigned int written, width;
> > size_t len, ofs, w;
> > @@ -261,11 +261,17 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> > while (1) {
> > c = fmt[ofs++];
> > width = 0;
> > + padc = ' ';
> >
> > if (escape) {
> > /* we're in an escape sequence, ofs == 1 */
> > escape = 0;
> >
> > + if (c == '-' || c == '0') {
> > + padc = c;
> > + c = fmt[ofs++];
> > + }
> > +
> > /* width */
> > while (c >= '0' && c <= '9') {
> > width *= 10;
> > @@ -358,13 +364,19 @@ int __nolibc_printf(__nolibc_printf_cb cb, intptr_t state, size_t n, const char
> > if (n) {
> > w = len < n ? len : n;
> > n -= w;
> > - while (width-- > w) {
> > - if (cb(state, " ", 1) != 0)
> > - return -1;
> > + while (width > w && padc != '-') {
> > written += 1;
> > + if (cb(state, &padc, 1) != 0)
> > + return -1;
> > + width--;
> > }
> > if (cb(state, outstr, w) != 0)
> > return -1;
> > + while (width-- > w) {
> > + written += 1;
> > + if (cb(state, " ", 1) != 0)
> > + return -1;
> > + }
> > }
> >
> > written += len;
>
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-30 1:05 ` Cheng Li
@ 2026-01-30 8:01 ` David Laight
2026-01-30 9:52 ` Cheng Li
0 siblings, 1 reply; 10+ messages in thread
From: David Laight @ 2026-01-30 8:01 UTC (permalink / raw)
To: Cheng Li; +Cc: Willy Tarreau, Thomas Weißschuh, linux-kernel
On Fri, 30 Jan 2026 09:05:39 +0800
Cheng Li <im.lechain@gmail.com> wrote:
> David Laight <david.laight.linux@gmail.com> 于2026年1月29日周四 18:30写道:
...
> These are great suggestions for a larger refactoring of printf to
> improve performance and standard compliance.
> However, to keep this current change minimal and safe, I prefer to
> focus on fixing the alignment feature first.
>
> @Willy, I will send a v3 that removes the '0' flag handling logic to
> avoid the bug pointed out above.
>
> I will rethink how to implement leading zero pad support.
You made me look at the code.
A simple refactor saved 98 bytes (about 10%).
I will look at adding support for field precision - which is what
is needed for leading zeros.
Will use up some of the saved space, but probably not all of it.
I'll base any patch on top of your change.
David
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf
2026-01-30 8:01 ` David Laight
@ 2026-01-30 9:52 ` Cheng Li
0 siblings, 0 replies; 10+ messages in thread
From: Cheng Li @ 2026-01-30 9:52 UTC (permalink / raw)
To: David Laight; +Cc: Willy Tarreau, Thomas Weißschuh, linux-kernel
David Laight <david.laight.linux@gmail.com> 于2026年1月30日周五 16:01写道:
>
> On Fri, 30 Jan 2026 09:05:39 +0800
> Cheng Li <im.lechain@gmail.com> wrote:
>
> > David Laight <david.laight.linux@gmail.com> 于2026年1月29日周四 18:30写道:
> ...
> > These are great suggestions for a larger refactoring of printf to
> > improve performance and standard compliance.
> > However, to keep this current change minimal and safe, I prefer to
> > focus on fixing the alignment feature first.
> >
> > @Willy, I will send a v3 that removes the '0' flag handling logic to
> > avoid the bug pointed out above.
> >
> > I will rethink how to implement leading zero pad support.
>
> You made me look at the code.
> A simple refactor saved 98 bytes (about 10%).
>
> I will look at adding support for field precision - which is what
> is needed for leading zeros.
> Will use up some of the saved space, but probably not all of it.
>
> I'll base any patch on top of your change.
Hi David,
Just a heads-up: I actually sent out a patch set implementing zero
padding (with explicit sign handling) right before reading your
message about adding precision support.
However, I agree that implementing full field precision is the cleaner
and more standard way to handle leading zeros. My patch handles it by
parsing the output buffer, which is less elegant.
Also, looking at my just-sent zero-padding patch again, I suspect I
might have missed adjusting the remaining length 'w' after skipping
the sign, which would be a bug.
So, let's stick to the plan:
I will discard my zero-padding attempt and focus on sending a **v4 of
the Left Alignment patch**. I will implement your suggested
optimization (swapping the logic to share the padding loop) to make it
a solid base for your future precision work.
Thanks,
Cheng
> David
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-01-30 9:53 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-01-28 9:42 [PATCH v2 0/2] tools/nolibc: printf left alignment and zero padding licheng.li
2026-01-28 9:42 ` [PATCH v2 1/2] tools/nolibc: support left alignment (-) and zero padding (0) in printf licheng.li
2026-01-29 6:41 ` Willy Tarreau
2026-01-29 6:57 ` licheng
2026-01-29 7:07 ` Willy Tarreau
2026-01-29 10:30 ` David Laight
2026-01-30 1:05 ` Cheng Li
2026-01-30 8:01 ` David Laight
2026-01-30 9:52 ` Cheng Li
2026-01-28 9:42 ` [PATCH v2 2/2] selftests/nolibc: add tests for printf left alignment and zero padding licheng.li
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox