[PATCH v3 next 12/17] tools/nolibc/printf: Handle "%s" with the numeric formats

From: david . laight . linux

Date: Mon Feb 23 2026 - 06:00:12 EST


From: David Laight <david.laight.linux@xxxxxxxxx>

Avoids the extra va_arg() call with is non-trivial on a lot of
modern ABI.

Signed-off-by: David Laight <david.laight.linux@xxxxxxxxx>
---

Changes for v3:
- Moved to its own patch (part of patch 7 in v2)..
- Fix 32bit compile.

tools/include/nolibc/stdio.h | 22 ++++++++++++----------
1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h
index 6cb106367e3b..6dd27473ab7f 100644
--- a/tools/include/nolibc/stdio.h
+++ b/tools/include/nolibc/stdio.h
@@ -412,13 +412,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list
*/
ch_flag = _NOLIBC_PF_FLAG(ch);
if (((ch >= 'a' && ch <= 'z') || ch == 'X') &&
- _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p')) {
- /* 'long' is needed for pointer conversions and ltz lengths.
+ _NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'c', 'd', 'i', 'u', 'x', 'p', 's')) {
+ /* 'long' is needed for pointer/string conversions and ltz lengths.
* A single test can be used provided 'p' (the same bit as '0')
* is masked from flags.
*/
if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag | (flags & ~_NOLIBC_PF_FLAG('p')),
- 'p', 'l', 't', 'z')) {
+ 'p', 's', 'l', 't', 'z')) {
v = va_arg(args, unsigned long);
signed_v = (long)v;
} else if (_NOLIBC_PF_FLAGS_CONTAIN(flags, 'j', 'q')) {
@@ -437,6 +437,15 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list
goto do_output;
}

+ if (ch == 's') {
+ /* "%s" - character string. */
+ outstr = (const char *)(uintptr_t)v;
+ if (!outstr) {
+ outstr = "(null)";
+ }
+ goto do_strlen_output;
+ }
+
out = outbuf;

if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i')) {
@@ -465,13 +474,6 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list
goto do_strlen_output;
}

- if (ch == 's') {
- outstr = va_arg(args, char *);
- if (!outstr)
- outstr="(null)";
- goto do_strlen_output;
- }
-
if (ch == 'm') {
outstr = strerror(errno);
goto do_strlen_output;
--
2.39.5