From 8df70ee45b1383114cdcaa9b2fe7449cdf5f46d5 Mon Sep 17 00:00:00 2001 From: David Laight Date: Sun, 8 Mar 2026 11:37:36 +0000 Subject: [PATCH] tools/nolibc/printf: Prepend sign to converted number MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Instead of appending the converted number to the sign, convert first and then prepend the sign (or "0x"). Use the length returned by u64toh_r() instead of calling strlen(). Needed so that zero padding can be inserted between the sign and digits in an upcoming patch. Signed-off-by: David Laight Acked-by: Willy Tarreau Link: https://patch.msgid.link/20260308113742.12649-12-david.laight.linux@gmail.com Signed-off-by: Thomas Weißschuh --- tools/include/nolibc/stdio.h | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index a377f164c70d9..3620aa643c814 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -345,9 +345,10 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list long long signed_v; int written, width, len; unsigned int flags, ch_flag; - char outbuf[21]; + char outbuf[2 + 22 + 1]; char *out; const char *outstr; + unsigned int sign_prefix; written = 0; while (1) { @@ -445,32 +446,49 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list goto do_strlen_output; } - out = outbuf; + /* The 'sign_prefix' can be zero, one or two ("0x") characters. + * Prepended least significant byte first stopping on a zero byte. + */ + sign_prefix = 0; if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) { /* "%d" and "%i" - signed decimal numbers. */ if (signed_v < 0) { - *out++ = '-'; + sign_prefix = '-'; v = -(signed_v + 1); v++; } } + /* The value is converted offset into the buffer so that + * the sign/prefix can be added in front. + * The longest digit string is 22 + 1 for octal conversions, the + * space is reserved even though octal isn't currently supported. + */ + out = outbuf + 2; + /* Convert the number to ascii in the required base. */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { /* Base 10 */ - u64toa_r(v, out); + len = u64toa_r(v, out); } else { /* Base 16 */ if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) { - *(out++) = '0'; - *(out++) = 'x'; + /* "%p" needs "0x" prepending. */ + sign_prefix = '0' << 8 | 'x'; } - u64toh_r(v, out); + len = u64toh_r(v, out); } - outstr = outbuf; - goto do_strlen_output; + /* Add the 0, 1 or 2 ("0x") sign/prefix characters at the front. */ + for (; sign_prefix; sign_prefix >>= 8) { + /* Force gcc to increment len inside the loop. */ + _NOLIBC_OPTIMIZER_HIDE_VAR(len); + len++; + *--out = sign_prefix; + } + outstr = out; + goto do_output; } if (ch == 'm') { -- 2.47.3