vsprintf: Add support for the %pV format-specifier
Add support for the %pV format-specifier which allows printing a struct va_format. This is used by the Linux kernel for recursive printf() formatting and is needed by the ext4l filesystem driver. Add the struct to include/linux/printk.h to match the kernel location. Co-developed-by: Claude <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com>
This commit is contained in:
@@ -258,6 +258,25 @@ Pointers
|
||||
lower case (requires CONFIG_LIB_UUID), e.g. 'system' for a GUID
|
||||
identifying an EFI system partition.
|
||||
|
||||
%pV
|
||||
prints a struct va_format, which contains a format string and a va_list
|
||||
pointer. This allows recursive printf formatting and is used for
|
||||
implementing custom print functions that wrap printf.
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void my_print(const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
printf("prefix: %pV\n", &vaf);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
|
||||
Tiny printf
|
||||
-----------
|
||||
|
||||
@@ -84,4 +84,9 @@
|
||||
#define printk_once(fmt, ...) \
|
||||
printk(fmt, ##__VA_ARGS__)
|
||||
|
||||
struct va_format {
|
||||
const char *fmt;
|
||||
va_list *va;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
/* we use this so that we can do without the ctype library */
|
||||
#define is_digit(c) ((c) >= '0' && (c) <= '9')
|
||||
@@ -508,6 +509,17 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
|
||||
return uuid_string(buf, end, ptr, field_width, precision,
|
||||
flags, fmt);
|
||||
#endif
|
||||
case 'V':
|
||||
{
|
||||
const struct va_format *vaf = ptr;
|
||||
va_list va;
|
||||
|
||||
va_copy(va, *vaf->va);
|
||||
buf += vsnprintf(buf, end > buf ? end - buf : 0,
|
||||
vaf->fmt, va);
|
||||
va_end(va);
|
||||
return buf;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@
|
||||
#include <log.h>
|
||||
#include <mapmem.h>
|
||||
#include <version_string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <vsprintf.h>
|
||||
#include <linux/printk.h>
|
||||
#include <test/common.h>
|
||||
#include <test/test.h>
|
||||
#include <test/ut.h>
|
||||
@@ -376,3 +378,49 @@ static int snprint(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
COMMON_TEST(snprint, 0);
|
||||
|
||||
/* Helper function to test %pV format specifier */
|
||||
static int print_with_va_format(char *buf, size_t size, const char *fmt, ...)
|
||||
{
|
||||
struct va_format vaf;
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
vaf.fmt = fmt;
|
||||
vaf.va = &args;
|
||||
ret = snprintf(buf, size, "prefix: %pV :suffix", &vaf);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Test printing with %pV (struct va_format) */
|
||||
static int print_va_format(struct unit_test_state *uts)
|
||||
{
|
||||
char str[64];
|
||||
int ret;
|
||||
|
||||
/* Basic string */
|
||||
ret = print_with_va_format(str, sizeof(str), "hello");
|
||||
ut_asserteq_str("prefix: hello :suffix", str);
|
||||
ut_asserteq(21, ret);
|
||||
|
||||
/* String with arguments */
|
||||
ret = print_with_va_format(str, sizeof(str), "value=%d", 42);
|
||||
ut_asserteq_str("prefix: value=42 :suffix", str);
|
||||
ut_asserteq(24, ret);
|
||||
|
||||
/* Multiple arguments */
|
||||
ret = print_with_va_format(str, sizeof(str), "%s: %d/%d", "test", 1, 2);
|
||||
ut_asserteq_str("prefix: test: 1/2 :suffix", str);
|
||||
ut_asserteq(25, ret);
|
||||
|
||||
/* Truncation */
|
||||
ret = print_with_va_format(str, 15, "hello world");
|
||||
ut_asserteq_str("prefix: hello ", str);
|
||||
ut_asserteq(27, ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
COMMON_TEST(print_va_format, 0);
|
||||
|
||||
Reference in New Issue
Block a user