From nobody Sun Feb 8 08:22:39 2026 Received: from mail-wr1-f49.google.com (mail-wr1-f49.google.com [209.85.221.49]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6F0B8323417 for ; Tue, 3 Feb 2026 10:30:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.49 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770114618; cv=none; b=oMcfKkzf5T05L6+DgIhahgfegh/oztE40sCNSmMKuSJyblcNNQJPuCopDAZXs6kK9ZWffTT/xfjRgcdXWsV4JFt9RSaYqWRseMyhIsWk4wHRFpFonvbxCcWtl0/GRLr1U0+wBMqs3unFnm83YE867IWiqqt4Np8G4k3rBejHK8E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770114618; c=relaxed/simple; bh=ujBYucnDXjrVtjPgeaqWCWuXeZOpHx5TUjvONb2SkJA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=g6xokp/bWac31pl1crJz7YFs5+LsptGno5gRdXFJNjFXtFxI55QUEN1Y9xqC4n50OaLTCGFRhHoMDpWNrFW/5v77qjbyC0hr4ft5ILVwfPNi6dv1Es9yPjrJx/7O64OuuhrWgeluGNKfj3JiykvwkpZ6tvLR3sBiH5Pn8q45BQE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=eJRqN5x6; arc=none smtp.client-ip=209.85.221.49 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eJRqN5x6" Received: by mail-wr1-f49.google.com with SMTP id ffacd0b85a97d-43246af170aso395383f8f.0 for ; Tue, 03 Feb 2026 02:30:16 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770114615; x=1770719415; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=k02e3d4dWbP0eABJFgF611l+mJke5v79RIA2KwX/geA=; b=eJRqN5x6HjB+a/KNNjZKcwN21J5iyeUwdleKNT6s/zh2uZN9dJraWZrZfLSrgykUXh 3DP46jX47Ml3VevcqPABywTrWFLHtUQVOGbjufbpiwXqyKgYWaxACNSQx3FdwfPZKNPe IkGGEYQnjbviwdVpLc+Yk/kHdRPay2sZkTJgfgjmiV18kkNCSpC3dDCBGduEEZs1RyEy +wiMFoptnw696v71iN9XTJsqFtBG9VQdeBumciPA8QSaRs0RrIcz5tlrxNE3wvt0QsJ9 ppoNNGhINsfYQYhKN+Qr+TaDgQqnGVEifs49/OOzeeihY0/ElRKfOiRd9pJE91QS1Y5y IB+w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770114615; x=1770719415; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=k02e3d4dWbP0eABJFgF611l+mJke5v79RIA2KwX/geA=; b=qxFFvXCnSYTo/OpeykQiVBKvryjnJ02m7qRxkcJyQdWFd4wsUg/7LrKP2z54Yoe3hN kpVpKW8cDBrRR32n0I+azxeWBX4rcAqZTZePTC93WxnJrfXhRTz2d3xE3NFYjdxsJiD0 vzWEHNgs17vNVuJOiMw2W87Wl4W+qhOmX44JhalZmaVFyBxjTF2gedb1WPFM3k0v1S8M pIpu4/oP+dBIVRK7CTTOG4zANBKgTiJYTB2PjXlWNJFyfA48k7Azi7hwVCyI9lPqqJI0 JL4dmI2341KbqBZCEUrDQtH4bqVZwokCcEW5NlJVCUDBolJ+0uniC+hEjTJwguZ91N+n h16Q== X-Forwarded-Encrypted: i=1; AJvYcCV69U03Bqm+QkpyapVKNGVuLCRbYWAoryIvba9Zrl9pJsyirMlk/seoFAi4GDWiDZ7aGVI4HD62aATvSTQ=@vger.kernel.org X-Gm-Message-State: AOJu0YwpMtSS/ksOAGmxEF/RIRiI+cSWKEGH7MORqN+ttXZS7EuKg623 zxA6F1GWLtyJhQofTnZoCZV7gc/FFXSvFrHjKWZ4gZO6DsfRBZaWMDYqrrljVg== X-Gm-Gg: AZuq6aJjpYWYAkL/umk87Pri9tX7pSEHqrVSIsmLprzhV7pyzjuWyXfXY44vwC39pHk dvUjejFIUcJxmXfiO/Jcj37PKlxw70QU4jtYZ3RgW+OS56za+l+OsRMHGQTSZGbx2AMhoj3Qj6O LAiSoq2Yn6QI64rtEGu+M1EnofTJw1iyLte1E5MRyTev0pw0e6bAWgHaucbCwYhkLt8fu6LfpRd olv5ilq5Kv2FdXATpChtAumPzey6yq/tKIXvkCw3X4IPECZI0K7TiiIIeco4ZUbrUv/jV2QZNQ3 YbT/dpbEiPOK3tJSXazm+SDsizVdFBGA1di1NyqTjOZo3MaHL8qxB0XtJo5BlWF2rxOfVcP+y8y 3t32jBlKYgV48+ZpMXpF9TA2rNAcHa+FGd1GnQY4TBkfK1qg3xrUvWM++WqLg5ltPnf+WSkWBXu kFw5YnjRzzVZmCiufz08dlX33QGnMyNcv1MO4fK4d3B/aQI6ornMPDAOrzuw7V0GA/bd6vinVK X-Received: by 2002:a05:6000:4027:b0:430:fdc8:8bd6 with SMTP id ffacd0b85a97d-43611439846mr4147479f8f.31.1770114614507; Tue, 03 Feb 2026 02:30:14 -0800 (PST) Received: from snowdrop.snailnet.com (82-69-66-36.dsl.in-addr.zen.co.uk. [82.69.66.36]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-435e10edf62sm55940729f8f.13.2026.02.03.02.30.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Feb 2026 02:30:14 -0800 (PST) From: david.laight.linux@gmail.com To: Willy Tarreau , =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= , linux-kernel@vger.kernel.org, Cheng Li Cc: David Laight Subject: [PATCH next 09/12] tools/nolibc/printf: support precision and zero padding Date: Tue, 3 Feb 2026 10:29:57 +0000 Message-Id: <20260203103000.20206-10-david.laight.linux@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260203103000.20206-1-david.laight.linux@gmail.com> References: <20260203103000.20206-1-david.laight.linux@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: David Laight Support '*' for both length and precision. Output "(nil)" for NULL pointers (matches glibc). Output "0" not "0x0" for printf("%#x", 0). Output no digits for printf("%.0d", 0). Signed-off-by: David Laight --- tools/include/nolibc/stdio.h | 114 +++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 25 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index d8b6184ff0f3..bad528921590 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -240,10 +240,15 @@ char *fgets(char *s, int size, FILE *stream) } =20 =20 -/* simple printf(). It supports the following formats: - * - %[-+ ][width][{l,t,z,ll,L,j,q}]{d,i,u,c,x,X,p,s,m} - * - %% - * - invalid formats are copied to the output buffer +/* printf(). Supports most of the normal integer and string formats. + * - %[#0-+ ][width|*[.precision|*]][{l,t,z,ll,L,j,q}]{d,i,u,c,x,X,p,s,m} + * - %% generates a single % + * - %m outputs strerror(errno). + * - # only affects %x and prepends 0x to non-zero values. + * - %o (octal) isn't supported. + * - %X outputs a..f the same as %x. + * - No support for wide characters. + * - invalid formats are copied to the output buffer. */ typedef int (*__nolibc_printf_cb)(void *state, const char *buf, size_t siz= e); =20 @@ -252,7 +257,7 @@ static __attribute__((unused, format(printf, 3, 0))) int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, v= a_list args) { char c; - int len, written, width; + int len, written, width, precision; unsigned int flags; char tmpbuf[32 + 24]; const char *outstr; @@ -277,17 +282,30 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *stat= e, const char *fmt, va_list =20 /* Flag characters */ for (; c >=3D 0x20 && c <=3D 0x3f; c =3D *fmt++) { - if ((__PF_FLAG(c) & (__PF_FLAG('-') | __PF_FLAG(' ') | __PF_FLAG('+'))= ) =3D=3D 0) + if ((__PF_FLAG(c) & (__PF_FLAG('-') | __PF_FLAG(' ') | __PF_FLAG('+') | + __PF_FLAG('#') | __PF_FLAG('0'))) =3D=3D 0) break; flags |=3D __PF_FLAG(c); } =20 - /* width */ - while (c >=3D '0' && c <=3D '9') { - width *=3D 10; - width +=3D c - '0'; - - c =3D *fmt++; + /* width and precision */ + for (;; c =3D *fmt++) { + if (c =3D=3D '*') { + precision =3D va_arg(args, unsigned int); + c =3D *fmt++; + } else { + for (precision =3D 0; c >=3D '0' && c <=3D '9'; c =3D *fmt++) + precision =3D precision * 10 + (c - '0'); + } + if (flags & __PF_FLAG('.')) + break; + width =3D precision; + if (c !=3D '.') { + /* Default precision for strings */ + precision =3D INT_MAX; + break; + } + flags |=3D __PF_FLAG('.'); } =20 /* Length modifiers are lower case except 'L' which is the same a 'q' */ @@ -308,7 +326,7 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state,= const char *fmt, va_list if (!((c >=3D 'a' && c <=3D 'z') || (c =3D=3D 'X' && (c =3D 'x')))) goto bad_conversion_specifier; =20 - /* Conversion specifiers */ + /* Numeric and pointer conversion specifiers */ if (__PF_FLAG(c) & (__PF_FLAG('c') | __PF_FLAG('d') | __PF_FLAG('i') | = __PF_FLAG('u') | __PF_FLAG('x') | __PF_FLAG('p') | __PF_FLAG('s'))) { unsigned long long v; @@ -338,12 +356,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *stat= e, const char *fmt, va_list case 's': if (!v) { outstr =3D "(null)"; - len =3D 6; + /* Match glibc, nothing output if precision too small */ + len =3D precision >=3D 6 ? 6 : 0; goto do_output; } outstr =3D (void *)v; do_strnlen_output: - len =3D strnlen(outstr, INT_MAX); + len =3D strnlen(outstr, precision); goto do_output; case 'd': case 'i': @@ -356,17 +375,62 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *stat= e, const char *fmt, va_list } else if (flags & __PF_FLAG(' ')) { sign =3D ' '; } - __nolibc_fallthrough; - case 'u': - len =3D u64toa_r(v, out); - break; - case 'p': - sign =3D 'x' | '0' << 8; - __nolibc_fallthrough; - default: /* 'x' and 'p' above */ - len =3D u64toh_r(v, out); - break; + c =3D 'u'; + } + + if (v =3D=3D 0) { + /* There are special rules for zero. */ + if (c =3D=3D 'p') { + /* match glibc, precision is ignored */ + outstr =3D "(nil)"; + len =3D 5; + goto do_output; + } + if (!precision) { + /* Explicit %nn.0d, no digits output */ + len =3D 0; + goto prepend_sign; + } + /* "#x" should output "0" not "0x0" */ + *out =3D '0'; + len =3D 1; + } else { + if (c =3D=3D 'u') { + len =3D u64toa_r(v, out); + } else { + len =3D u64toh_r(v, out); + if (c =3D=3D 'p' || (flags & __PF_FLAG('#'))) + sign =3D 'x' | '0' << 8; + } } + + /* Add zero padding */ + if (flags & (__PF_FLAG('0') | __PF_FLAG('.'))) { + if (!(flags & __PF_FLAG('.'))) { + if (flags & __PF_FLAG('-')) + /* Left justify overrides zero pad */ + goto prepend_sign; + /* Zero pad to field width less sign */ + precision =3D width; + if (sign) { + precision--; + if (sign >=3D 256) + precision--; + } + } + if (precision > 30) + /* Don't run off the start of tmpbuf[] */ + precision =3D 30; + for (; len < precision; len++) { + /* Stop gcc generating horrid code and memset(). + * This is OPTIMIZER_HIDE_VAR() from compiler.h. + */ + __asm__ volatile("" : "=3Dr"(len) : "0"(len)); + *--out =3D '0'; + } + } + +prepend_sign: for (; sign; sign >>=3D 8) { len++; *--out =3D sign; --=20 2.39.5