From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-wr1-f45.google.com (mail-wr1-f45.google.com [209.85.221.45]) (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 DBFA043C052 for ; Fri, 6 Feb 2026 19:11:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.221.45 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405096; cv=none; b=JitzNXq54bJ4XSQfo743D8bqdsdmx99kXRjmdQK6W3XC6Iz27p+b4q7ri3xTmgc+1H7RfU06SILJhQSksgRNOIHn/a8pTENP0AKIDO4qE5a1HURmjr/wBqCYtMYZsg6rIxCyNTPN1uiQl8CriAAwd7Ukaoiam/JCFi45VALVrrI= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770405096; c=relaxed/simple; bh=Lk4pPt+9/tvAzivujt37uWOMz8gLQk32IeV8vSwdECs=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=fWvUq3S5oWfPND4NtvIwg9+xysL9DwWgV9NUw6nqpHL/ojjQt0pdzx7gBi1Gs+Ei27hp0c4U6ReSrBHmsjpom1RBVPASW1aR+7o6+Wmwr/7EGF80QIc0H4A4k3U3uitP3Qmrvl585yOwMTbe0WsabSNg45fFRCw7b7Fswp9GuvU= 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=VtvUWG3A; arc=none smtp.client-ip=209.85.221.45 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="VtvUWG3A" Received: by mail-wr1-f45.google.com with SMTP id ffacd0b85a97d-436309f1ad7so317723f8f.3 for ; Fri, 06 Feb 2026 11:11:35 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770405094; x=1771009894; 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=eFZ+cHFy2hLLPltnBVp3RolE7ACEEfEz3G83WQBOgOE=; b=VtvUWG3Az8t5rcddAXvXAH4ofHqiRk7pg49rc8BsA75ulFoIV7ht78jMwV0ccyQyr9 8z1pQOSPLGB6B4Fmpscs4uv3yMhEXh7X6GfDEnOHwM+ftvbOOJArsSM50xiSP018IJbC UvPG/2Y+MbDpQnSaHg8256wGm43b3jUtbidUIoNpjX3OnYv/h5PF37JcKqhc7jW3A1A1 h3u5NTcQv/jDN11Vnlzi3kwJp08b0zqBjOdGGLJgKtyGIV+hVPrHeP2F5Arp3+mPmsn6 nc6RhwW+kZiAVK7aJI9/DF3HaZrzsTZjRPyf8W2w0sg+DcJo9injWdP82rZkXxFU4MC4 LghQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770405094; x=1771009894; 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=eFZ+cHFy2hLLPltnBVp3RolE7ACEEfEz3G83WQBOgOE=; b=l4zkcRr43vSz3d/ggf2jL+sIDEMQuw7qTgzJEWJQznVW6pTbLU+by2saCtT7LqsOZC Q9hrpX1indf9CWoqCJBxM5WAcbRMkbUZucay2uVCr3fWPj9UDh1hYJHCe5slcJMAre8W Z0ZKkAwYVFxDMDmuYGJXesRRv6soRmOXpic4JAExdDIfAo6Mb5cF6wYAxgCNdvF5QNUo 6GsOVqqM/yKVGp4hZ4W7SNK1SOL97zozrU5rHvildZ2TYkGE/JZB9iMnNeRU8YZrM4fj g7mOfgb+9Nngg6Ss+T0lHwCW0NzYWPsZpvpKw+ays2HBPibLUaR1l4y2gLwX2BOjaVMS q2jg== X-Forwarded-Encrypted: i=1; AJvYcCWJPWZnykTbQ2+34ptzGHLWDwvJ78ZmNnYWqk/iA2BAlaFXAfw6VKKZz5fcMIOctX4Z1ybhZiZCa3wi4pQ=@vger.kernel.org X-Gm-Message-State: AOJu0YyTFhJHq+QVH3loDcyaRl0iK2xohwvI9oJ7o9J8Op7QuWhLao4F 0qs9CV/rIlzbDGcatXmYZI5sQW5YUUhhHMryiE18E7YObRxeQu+a7xu8 X-Gm-Gg: AZuq6aLhtWDFrcNX2HtuysEbMCthrJ+uk5VmKkYNBjBMUrafYXmsl4v78NSbWVwVGU8 h8mata2lHgQj0xvZHM4V5xJ6/T7ami78VxTiBtmFR372zElMpa0Zqtkrj6ilRTSnHDoaJNqU/ze PRpsh5GE1KNxFPV30nxj32ATl1bhrHpY3QkAgt6lGVsSMqmAp24YV5AQLFc4cHtRqnfAsK6rK3w 8Yg3GBLhwhw8CktWT0s2gGSqBr2kC516ruz9TC1Z3J9lVhASamdcVv6ysCq/G1OWj8XEkT15Tly PzY8bj4TQkAAnzNsZBfAS3nhjxkZ65oUbYTV9BptCGcyVSEyYinFsy25q838FIdiNPrpvXZXQWI YY4kyxem6tG3tFyEWkLBiOZW2y9P7PzG3DDOAY4g2AH4UoZ0mklVRW7im4SKpjvoFcPyBqqvPO9 f2yxVVRgejH04YKtoAS3sO5DmgSbbw16/Oq3w1/Oz0Lqvd5UgZImpA75DHX8d6D4KYfTdbER5w X-Received: by 2002:a05:6000:2601:b0:435:d859:5cf with SMTP id ffacd0b85a97d-4362938a761mr6010373f8f.54.1770405093931; Fri, 06 Feb 2026 11:11:33 -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-4362972fb81sm8703681f8f.20.2026.02.06.11.11.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 06 Feb 2026 11:11:33 -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 v2 next 08/11] tools/nolibc/printf: Add support for zero padding and field precision Date: Fri, 6 Feb 2026 19:11:18 +0000 Message-Id: <20260206191121.3602-9-david.laight.linux@gmail.com> X-Mailer: git-send-email 2.39.5 In-Reply-To: <20260206191121.3602-1-david.laight.linux@gmail.com> References: <20260206191121.3602-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: 8bit From: David Laight Include support for variable field widths (eg "%*.*d") and the special processing required for zero especially when the precision is 0. Zero padding is limited to 30 zero characters. This is wider than the largest numeric field so shouldn't be a problem. When processing "%#01x" subtracting the number of 'sign' characters from the field width generates a negative precision. Fix by making all the variables 'signed int'. This also makes the code smaller. The space padding can then optimised as well (saves another 60 bytes of code). All the standard printf formats are now supported except octal and floating point. Signed-off-by: David Laight --- Changes for v2: - These changes were previously in patch 9. However you need to apply the old patch 10 to get anything like the same source. The files then more of less match apart from 'c' being renamed 'ch' and the 'magic' #defines. tools/include/nolibc/stdio.h | 103 +++++++++++++++++++++++++++-------- 1 file changed, 80 insertions(+), 23 deletions(-) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 032416e900ee..d85607942784 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -241,13 +241,12 @@ char *fgets(char *s, int size, FILE *stream) /* printf(). Supports most of the normal integer and string formats. - * - %[#-+ ][width][{l,t,z,ll,L,j,q}]{d,i,u,c,x,X,p,s,m,%} + * - %[#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 zero padding, precision or variable widths. * - No support for wide characters. * - invalid formats are copied to the output buffer. */ @@ -282,9 +281,8 @@ static __attribute__((unused, format(printf, 3, 0))) int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list args) { char ch; - unsigned int written, width; + int len, written, width, precision; unsigned int flags, ch_flag; - size_t len; char tmpbuf[32 + 24]; const char *outstr; @@ -314,12 +312,24 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list flags |= ch_flag; } - /* width */ - while (ch >= '0' && ch <= '9') { - width *= 10; - width += ch - '0'; - - ch = *fmt++; + /* Width and precision */ + for (;; ch = *fmt++) { + if (ch == '*') { + precision = va_arg(args, unsigned int); + ch = *fmt++; + } else { + for (precision = 0; ch >= '0' && ch <= '9'; ch = *fmt++) + precision = precision * 10 + (ch - '0'); + } + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) + break; + width = precision; + if (ch != '.') { + /* Default precision for strings */ + precision = INT_MAX; + break; + } + flags |= _NOLIBC_PF_FLAG('.'); } /* Length modifier. @@ -388,12 +398,13 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list /* "%s" - character string. */ if (!v) { outstr = "(null)"; - len = 6; + /* Match glibc, nothing output if precision too small */ + len = precision >= 6 ? 6 : 0; goto do_output; } outstr = (void *)v; do_strnlen_output: - len = strnlen(outstr, INT_MAX); + len = strnlen(outstr, precision); goto do_output; } @@ -410,19 +421,64 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list } } - /* Convert the number to ascii in the required base. */ - if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { - /* Base 10 */ - len = u64toa_r(v, out); + if (v == 0) { + /* There are special rules for zero. */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p')) { + /* "%p" match glibc, precision is ignored */ + outstr = "(nil)"; + len = 5; + goto do_output; + } + if (!precision) { + /* Explicit %nn.0d, no digits output */ + len = 0; + goto prepend_sign; + } + /* All formats (including "%#x") just output "0". */ + *out = '0'; + len = 1; } else { - /* Base 16 */ - if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) { - /* "%p" and "%#x" need "0x" prepending. */ - sign = 'x' | '0' << 8; + /* Convert the number to ascii in the required base. */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'd', 'i', 'u')) { + /* Base 10 */ + len = u64toa_r(v, out); + } else { + /* Base 16 */ + if (_NOLIBC_PF_FLAGS_CONTAIN(ch_flag, 'p', '#' - 1)) { + /* "%p" and "%#x" need "0x" prepending. */ + sign = 'x' | '0' << 8; + } + len = u64toh_r(v, out); + } + } + + /* Add zero padding */ + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '0', '.')) { + if (!_NOLIBC_PF_FLAGS_CONTAIN(flags, '.')) { + if (_NOLIBC_PF_FLAGS_CONTAIN(flags, '-')) + /* Left justify overrides zero pad */ + goto prepend_sign; + /* eg "%05d", Zero pad to field width less sign */ + precision = width; + if (sign) { + precision--; + if (sign >= 256) + precision--; + } + } + if (precision > 30) + /* Don't run off the start of tmpbuf[] */ + precision = 30; + for (; len < precision; len++) { + /* Stop gcc generating horrid code and memset(). + * This is OPTIMIZER_HIDE_VAR() from compiler.h. + */ + __asm__ volatile("" : "=r"(len) : "0"(len)); + *--out = '0'; } - len = u64toh_r(v, out); } +prepend_sign: /* Add 0, 1 or 2 ("0x") sign characters left of any zero padding */ for (; sign; sign >>= 8) { len++; @@ -465,11 +521,12 @@ int __nolibc_printf(__nolibc_printf_cb cb, void *state, const char *fmt, va_list __asm__ volatile("" : "=r"(len) : "0"(len)); /* Output 'left pad', 'value' then 'right pad'. */ + width -= len; flags = _NOLIBC_PF_FLAGS_CONTAIN(flags, '-'); if (flags && cb(state, outstr, len) != 0) return -1; - while (width > len) { - unsigned int pad_len = ((width - len - 1) & 15) + 1; + while (width > 0) { + int pad_len = ((width - 1) & 15) + 1; width -= pad_len; written += pad_len; if (cb(state, " ", pad_len) != 0) -- 2.39.5