[PATCH 3/4] vsprintf: implement %pJP for printing JSONPaths

Ahmad Fatoum a.fatoum at pengutronix.de
Tue Jan 10 00:49:29 PST 2023


We use an array of strings to represnt a JSONPath. Add a new %pJP format
specifier that can be used to print them. This is useful for error
messages when the lookup fails.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 lib/vsprintf.c     | 44 ++++++++++++++++++++++++++++++++++++++++++++
 test/self/printf.c | 17 +++++++++++++++++
 2 files changed, 61 insertions(+)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 693f3c0cc0c8..cdb3906ea2ff 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -197,6 +197,27 @@ static char *string(char *buf, const char *end, const char *s, int field_width,
 	return trailing_spaces(buf, end, len, &field_width, flags);
 }
 
+static __maybe_unused char *string_array(char *buf, const char *end, char *const *s,
+					 int field_width, int precision, int flags,
+					 const char *separator)
+{
+	size_t i, len = strlen(separator);
+
+	while (*s) {
+		buf = string(buf, end, *s, field_width, precision, flags);
+		if (!*++s)
+			break;
+
+		for (i = 0; i < len; ++i) {
+			if (buf < end)
+				*buf = separator[i];
+			++buf;
+		}
+	}
+
+	return buf;
+}
+
 static char *wstring(char *buf, const char *end, const wchar_t *s, int field_width,
 		     int precision, int flags)
 {
@@ -368,6 +389,26 @@ char *hex_string(char *buf, const char *end, const u8 *addr, int field_width,
 	return buf;
 }
 
+static noinline_for_stack
+char *jsonpath_string(char *buf, const char *end, char *const *path, int field_width,
+		 int precision, int flags, const char *fmt)
+{
+	if ((unsigned long)path < PAGE_SIZE)
+		return string(buf, end, "<NULL>", field_width, precision, flags);
+
+	if (buf < end)
+		*buf = '$';
+	++buf;
+
+	if (*path) {
+		if (buf < end)
+			*buf = '.';
+		++buf;
+	}
+
+	return string_array(buf, end, path, field_width, precision, flags, ".");
+}
+
 static noinline_for_stack
 char *address_val(char *buf, const char *end, const void *addr,
 		  int field_width, int precision, int flags, const char *fmt)
@@ -458,6 +499,9 @@ static char *pointer(const char *fmt, char *buf, const char *end, const void *pt
 		if (IS_ENABLED(CONFIG_PRINTF_HEXSTR))
 			return hex_string(buf, end, ptr, field_width, precision, flags, fmt);
 		break;
+	case 'J':
+		if (fmt[1] == 'P' && IS_ENABLED(CONFIG_JSMN))
+			return jsonpath_string(buf, end, ptr, field_width, precision, flags, fmt);
 	}
 
 	return raw_pointer(buf, end, ptr, field_width, precision, flags);
diff --git a/test/self/printf.c b/test/self/printf.c
index 7a74660868c2..eae40ed242c1 100644
--- a/test/self/printf.c
+++ b/test/self/printf.c
@@ -305,6 +305,22 @@ test_pointer(void)
 	errptr();
 }
 
+static void __init
+test_jsonpath(void)
+{
+	if (!IS_ENABLED(CONFIG_JSMN)) {
+		pr_info("skipping jsonpath tests: CONFIG_JSMN disabled in config\n");
+		skipped_tests += 5;
+		return;
+	}
+
+	test("<NULL>", "%pJP",  NULL);
+	test("$", "%pJP",  &(char *[]){ NULL });
+	test("$.1", "%pJP",  &(char *[]){ "1", NULL });
+	test("$.1.23", "%pJP",  &(char *[]){ "1", "23", NULL });
+	test("$.1.23.456", "%pJP",  &(char *[]){ "1", "23", "456", NULL });
+}
+
 static void __init test_printf(void)
 {
 	alloced_buffer = malloc(BUF_SIZE + 2*PAD_SIZE);
@@ -317,6 +333,7 @@ static void __init test_printf(void)
 	test_string();
 	test_pointer();
 	test_hexstr();
+	test_jsonpath();
 
 	free(alloced_buffer);
 }
-- 
2.30.2




More information about the barebox mailing list