All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nikos Nikoleris <nikos.nikoleris@arm.com>
To: kvm@vger.kernel.org, kvmarm@lists.linux.dev, andrew.jones@linux.dev
Cc: pbonzini@redhat.com, alexandru.elisei@arm.com,
	ricarkol@google.com, Andrew Jones <drjones@redhat.com>
Subject: [PATCH v4 17/30] lib/printf: Support for precision modifier in printf
Date: Mon, 13 Feb 2023 10:17:46 +0000	[thread overview]
Message-ID: <20230213101759.2577077-18-nikos.nikoleris@arm.com> (raw)
In-Reply-To: <20230213101759.2577077-1-nikos.nikoleris@arm.com>

This follows the typical format of:

printf("%.Ns", *str);

Where N might be a decimal digit string or '*'. This feature is used
by a future change.

See also: man 3 printf

Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-by: Andrew Jones <drjones@redhat.com>
---
 lib/printf.c | 95 ++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 78 insertions(+), 17 deletions(-)

diff --git a/lib/printf.c b/lib/printf.c
index 383799ec..d600199b 100644
--- a/lib/printf.c
+++ b/lib/printf.c
@@ -6,6 +6,7 @@
  */
 
 #include "libcflat.h"
+#include "ctype.h"
 
 #define BUFSZ 2000
 
@@ -19,6 +20,7 @@ typedef struct strprops {
 	char pad;
 	int npad;
 	bool alternate;
+	int precision;
 } strprops_t;
 
 static void addchar(pstream_t *p, char c)
@@ -43,7 +45,7 @@ static void print_str(pstream_t *p, const char *s, strprops_t props)
 		}
 	}
 
-	while (*s)
+	while (*s && props.precision--)
 		addchar(p, *s++);
 
 	if (npad < 0) {
@@ -73,12 +75,13 @@ static void print_int(pstream_t *ps, long long n, int base, strprops_t props)
 		n /= base;
 	}
 
+	while (p == buf || (p - buf < props.precision))
+		*p++ = '0';
+	props.precision = -1;
+
 	if (s)
 		*p++ = '-';
 
-	if (p == buf)
-		*p++ = '0';
-
 	for (i = 0; i < (p - buf) / 2; ++i) {
 		char tmp;
 
@@ -104,8 +107,13 @@ static void print_unsigned(pstream_t *ps, unsigned long long n, int base,
 	}
 
 	if (p == buf)
+		props.alternate = false;
+
+	while (p == buf || (p - buf < props.precision))
 		*p++ = '0';
-	else if (props.alternate && base == 16) {
+	props.precision = -1;
+
+	if (props.alternate && base == 16) {
 		if (props.pad == '0') {
 			addchar(ps, '0');
 			addchar(ps, 'x');
@@ -147,9 +155,56 @@ static int fmtnum(const char **fmt)
 	return num;
 }
 
+/*
+ * Adapted from drivers/firmware/efi/libstub/vsprintf.c
+ */
+static int skip_atoi(const char **s)
+{
+	int i = 0;
+
+	do {
+		i = i*10 + *((*s)++) - '0';
+	} while (isdigit(**s));
+
+	return i;
+}
+
+/*
+ * Adapted from drivers/firmware/efi/libstub/vsprintf.c
+ */
+static int get_int(const char **fmt, va_list *ap)
+{
+	if (isdigit(**fmt))
+		return skip_atoi(fmt);
+
+	if (**fmt == '*') {
+		++(*fmt);
+		/* it's the next argument */
+		return va_arg(*ap, int);
+	}
+	return 0;
+}
+
 int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 {
 	pstream_t s;
+	va_list args;
+
+	/*
+	 * We want to pass our input va_list to helper functions by reference,
+	 * but there's an annoying edge case. If va_list was originally passed
+	 * to us by value, we could just pass &ap down to the helpers. This is
+	 * the case on, for example, X86_32.
+	 * However, on X86_64 (and possibly others), va_list is actually a
+	 * size-1 array containing a structure. Our function parameter ap has
+	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
+	 * which is what will be expected by a function taking a va_list *
+	 * parameter.
+	 * One standard way to solve this mess is by creating a copy in a local
+	 * variable of type va_list and then passing a pointer to that local
+	 * copy instead, which is what we do here.
+	 */
+	va_copy(args, va);
 
 	s.buffer = buf;
 	s.remain = size - 1;
@@ -160,6 +215,7 @@ int vsnprintf(char *buf, int size, const char *fmt, va_list va)
 		strprops_t props;
 		memset(&props, 0, sizeof(props));
 		props.pad = ' ';
+		props.precision = -1;
 
 		if (f != '%') {
 			addchar(&s, f);
@@ -172,11 +228,15 @@ morefmt:
 			addchar(&s, '%');
 			break;
 		case 'c':
-			addchar(&s, va_arg(va, int));
+			addchar(&s, va_arg(args, int));
 			break;
 		case '\0':
 			--fmt;
 			break;
+		case '.':
+			props.pad = ' ';
+			props.precision = get_int(&fmt, &args);
+			goto morefmt;
 		case '#':
 			props.alternate = true;
 			goto morefmt;
@@ -204,54 +264,55 @@ morefmt:
 		case 'd':
 			switch (nlong) {
 			case 0:
-				print_int(&s, va_arg(va, int), 10, props);
+				print_int(&s, va_arg(args, int), 10, props);
 				break;
 			case 1:
-				print_int(&s, va_arg(va, long), 10, props);
+				print_int(&s, va_arg(args, long), 10, props);
 				break;
 			default:
-				print_int(&s, va_arg(va, long long), 10, props);
+				print_int(&s, va_arg(args, long long), 10, props);
 				break;
 			}
 			break;
 		case 'u':
 			switch (nlong) {
 			case 0:
-				print_unsigned(&s, va_arg(va, unsigned), 10, props);
+				print_unsigned(&s, va_arg(args, unsigned int), 10, props);
 				break;
 			case 1:
-				print_unsigned(&s, va_arg(va, unsigned long), 10, props);
+				print_unsigned(&s, va_arg(args, unsigned long), 10, props);
 				break;
 			default:
-				print_unsigned(&s, va_arg(va, unsigned long long), 10, props);
+				print_unsigned(&s, va_arg(args, unsigned long long), 10, props);
 				break;
 			}
 			break;
 		case 'x':
 			switch (nlong) {
 			case 0:
-				print_unsigned(&s, va_arg(va, unsigned), 16, props);
+				print_unsigned(&s, va_arg(args, unsigned int), 16, props);
 				break;
 			case 1:
-				print_unsigned(&s, va_arg(va, unsigned long), 16, props);
+				print_unsigned(&s, va_arg(args, unsigned long), 16, props);
 				break;
 			default:
-				print_unsigned(&s, va_arg(va, unsigned long long), 16, props);
+				print_unsigned(&s, va_arg(args, unsigned long long), 16, props);
 				break;
 			}
 			break;
 		case 'p':
 			props.alternate = true;
-			print_unsigned(&s, (unsigned long)va_arg(va, void *), 16, props);
+			print_unsigned(&s, (unsigned long)va_arg(args, void *), 16, props);
 			break;
 		case 's':
-			print_str(&s, va_arg(va, const char *), props);
+			print_str(&s, va_arg(args, const char *), props);
 			break;
 		default:
 			addchar(&s, f);
 			break;
 		}
 	}
+	va_end(args);
 	*s.buffer = 0;
 	return s.added;
 }
-- 
2.25.1


  parent reply	other threads:[~2023-02-13 10:18 UTC|newest]

Thread overview: 49+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-13 10:17 [PATCH v4 00/30] EFI and ACPI support for arm64 Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 01/30] lib: Move acpi header and implementation to lib Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 02/30] x86: Move x86_64-specific EFI CFLAGS to x86_64 Makefile Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 03/30] arm/Makefile.common: Compile lib/acpi.c if CONFIG_EFI=y Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 04/30] lib: Apply Lindent to acpi.{c,h} Nikos Nikoleris
2023-03-09  7:11   ` Shaoqin Huang
2023-03-21 17:32     ` Andrew Jones
2023-03-22 10:05       ` Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 05/30] lib: Fix style for acpi.{c,h} Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 06/30] lib/acpi: Convert table names to Linux style Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 07/30] x86: Avoid references to fields of ACPI tables Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 08/30] lib/acpi: Ensure all struct definition for ACPI tables are packed Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 09/30] lib/acpi: Add support for the XSDT table Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 10/30] lib/acpi: Extend the definition of the FADT table Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 11/30] devicetree: Check that fdt is not NULL in dt_available() Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 12/30] arm64: Add support for setting up the PSCI conduit through ACPI Nikos Nikoleris
2023-03-21 17:31   ` Andrew Jones
2023-02-13 10:17 ` [PATCH v4 13/30] arm64: Add support for discovering the UART " Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 14/30] arm64: Add support for timer initialization " Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 15/30] arm64: Add support for cpu " Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 16/30] arm64: Add support for gic " Nikos Nikoleris
2023-03-30  6:46   ` Shaoqin Huang
2023-02-13 10:17 ` Nikos Nikoleris [this message]
2023-02-13 10:17 ` [PATCH v4 18/30] lib/printf: Add support for printing wide strings Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 19/30] lib/efi: Add support for getting the cmdline Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 20/30] arm/arm64: Rename etext to _etext Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 21/30] lib: Avoid ms_abi for calls related to EFI on arm64 Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 22/30] arm64: Add a new type of memory type flag MR_F_RESERVED Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 23/30] arm64: Add a setup sequence for systems that boot through EFI Nikos Nikoleris
2023-04-25  7:04   ` Shaoqin Huang
2023-04-25  9:09     ` Nikos Nikoleris
2023-04-25 18:31       ` Andrew Jones
2023-02-13 10:17 ` [PATCH v4 24/30] arm64: Copy code from GNU-EFI Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 25/30] arm64: Change GNU-EFI imported code to use defined types Nikos Nikoleris
2023-03-30  6:49   ` Shaoqin Huang
2023-02-13 10:17 ` [PATCH v4 26/30] arm64: Use code from the gnu-efi when booting with EFI Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 27/30] lib: Avoid external dependency in libelf Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 28/30] arm64: Add support for efi in Makefile Nikos Nikoleris
2023-03-21 18:21   ` Andrew Jones
2023-02-13 10:17 ` [PATCH v4 29/30] lib: arm: Print test exit status Nikos Nikoleris
2023-02-13 10:17 ` [PATCH v4 30/30] arm64: Add an efi/run script Nikos Nikoleris
2023-03-21 18:41   ` Andrew Jones
2023-03-22 10:02     ` Nikos Nikoleris
2023-03-22 11:24       ` Andrew Jones
2023-03-22 11:57         ` Nikos Nikoleris
2023-03-22 12:32           ` Andrew Jones
2023-03-22 19:09             ` Nikos Nikoleris
2023-03-23 17:52               ` Andrew Jones
2023-03-28  9:03                 ` Alexandru Elisei

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230213101759.2577077-18-nikos.nikoleris@arm.com \
    --to=nikos.nikoleris@arm.com \
    --cc=alexandru.elisei@arm.com \
    --cc=andrew.jones@linux.dev \
    --cc=drjones@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=kvmarm@lists.linux.dev \
    --cc=pbonzini@redhat.com \
    --cc=ricarkol@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.