From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on gnuweeb.org X-Spam-Level: X-Spam-Status: No, score=-6.2 required=5.0 tests=DKIMWL_WL_HIGH,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_HI,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by gnuweeb.org (Postfix) with ESMTPS id ED9DC7E3D6 for ; Tue, 19 Apr 2022 00:42:30 +0000 (UTC) Authentication-Results: gnuweeb.org; dkim=pass (2048-bit key; unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20201202 header.b=h63Eitfc; dkim-atps=neutral Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 475A061446; Tue, 19 Apr 2022 00:42:30 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 12F46C385CC; Tue, 19 Apr 2022 00:42:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1650328948; bh=DoH+DKwtnZi++mxO5o84y/4hk/LGEST5iJ6GyK18UC0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=h63Eitfcg4e8pOwZFt7DTfsSJ06uSIXYE5YLL40O/JKSKrMo0oeXARlrP8MmY3RcM a/OXGBGzhITZ+Ox8v8UdLnY/SoGf2x5PmIu9djzhmCn1RQosGyoW+BPoqU7Ecm5osq 6HqRwQlR0NXHu6/w3yrJN6D6CBjcLReGpVrwd0BwXW/hr7H1USutuCDYSnIhGzAcUW VSkpj30ZcRiGxWsCqvVlXA3vAbgjAZHXlB84P4PEi+0vsoJyjSsW0+KQvH4yUwhS0B qSje/CfKP/BoGhR3mZ9aEgNN+1tqFUTZkbUYJXv2qezI04Mk1eEPZqXyAzdg0T+uxy s0Ifd5R8PZbTg== Received: by paulmck-ThinkPad-P17-Gen-1.home (Postfix, from userid 1000) id 2DB155C30EA; Mon, 18 Apr 2022 17:42:27 -0700 (PDT) From: "Paul E. McKenney" To: linux-kernel@vger.kernel.org Cc: gwml@vger.gnuweeb.org, kernel-team@fb.com, w@lwt.eu, Willy Tarreau , "Paul E . McKenney" Subject: [PATCH nolibc 21/61] tools/nolibc/stdio: add a minimal [vf]printf() implementation Date: Mon, 18 Apr 2022 17:41:45 -0700 Message-Id: <20220419004225.3952530-21-paulmck@kernel.org> X-Mailer: git-send-email 2.31.1.189.g2e36527f23 In-Reply-To: <20220419004219.GA3952301@paulmck-ThinkPad-P17-Gen-1> References: <20220419004219.GA3952301@paulmck-ThinkPad-P17-Gen-1> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: From: Willy Tarreau This adds a minimal vfprintf() implementation as well as the commonly used fprintf() and printf() that rely on it. For now the function supports: - formats: %s, %c, %u, %d, %x - modifiers: %l and %ll - unknown chars are considered as modifiers and are ignored It is designed to remain minimalist, despite this printf() is 549 bytes on x86_64. It would be wise not to add too many formats. Signed-off-by: Willy Tarreau Signed-off-by: Paul E. McKenney --- tools/include/nolibc/stdio.h | 128 +++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/tools/include/nolibc/stdio.h b/tools/include/nolibc/stdio.h index 996bf89a30d2..a73cf24cb68d 100644 --- a/tools/include/nolibc/stdio.h +++ b/tools/include/nolibc/stdio.h @@ -7,6 +7,8 @@ #ifndef _NOLIBC_STDIO_H #define _NOLIBC_STDIO_H +#include + #include "std.h" #include "arch.h" #include "types.h" @@ -158,4 +160,130 @@ char *fgets(char *s, int size, FILE *stream) return ofs ? s : NULL; } + +/* minimal vfprintf(). It supports the following formats: + * - %[l*]{d,u,c,x} + * - %s + * - unknown modifiers are ignored. + */ +static __attribute__((unused)) +int vfprintf(FILE *stream, const char *fmt, va_list args) +{ + char escape, lpref, c; + unsigned long long v; + unsigned int written; + size_t len, ofs; + char tmpbuf[21]; + const char *outstr; + + written = ofs = escape = lpref = 0; + while (1) { + c = fmt[ofs++]; + + if (escape) { + /* we're in an escape sequence, ofs == 1 */ + escape = 0; + if (c == 'c' || c == 'd' || c == 'u' || c == 'x') { + if (lpref) { + if (lpref > 1) + v = va_arg(args, unsigned long long); + else + v = va_arg(args, unsigned long); + } else + v = va_arg(args, unsigned int); + + if (c == 'd') { + /* sign-extend the value */ + if (lpref == 0) + v = (long long)(int)v; + else if (lpref == 1) + v = (long long)(long)v; + } + + switch (c) { + case 'd': + i64toa_r(v, tmpbuf); + break; + case 'u': + u64toa_r(v, tmpbuf); + break; + case 'x': + u64toh_r(v, tmpbuf); + break; + default: /* 'c' */ + tmpbuf[0] = v; + tmpbuf[1] = 0; + break; + } + outstr = tmpbuf; + } + else if (c == 's') { + outstr = va_arg(args, char *); + } + else if (c == '%') { + /* queue it verbatim */ + continue; + } + else { + /* modifiers or final 0 */ + if (c == 'l') { + /* long format prefix, maintain the escape */ + lpref++; + } + escape = 1; + goto do_escape; + } + len = strlen(outstr); + goto flush_str; + } + + /* not an escape sequence */ + if (c == 0 || c == '%') { + /* flush pending data on escape or end */ + escape = 1; + lpref = 0; + outstr = fmt; + len = ofs - 1; + flush_str: + if (_fwrite(outstr, len, stream) != 0) + break; + + written += len; + do_escape: + if (c == 0) + break; + fmt += ofs; + ofs = 0; + continue; + } + + /* literal char, just queue it */ + } + return written; +} + +static __attribute__((unused)) +int fprintf(FILE *stream, const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vfprintf(stream, fmt, args); + va_end(args); + return ret; +} + +static __attribute__((unused)) +int printf(const char *fmt, ...) +{ + va_list args; + int ret; + + va_start(args, fmt); + ret = vfprintf(stdout, fmt, args); + va_end(args); + return ret; +} + #endif /* _NOLIBC_STDIO_H */ -- 2.31.1.189.g2e36527f23