summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lamparter <equinox@diac24.net>2021-03-02 20:45:57 +0100
committerDavid Lamparter <equinox@diac24.net>2021-03-30 22:32:59 +0200
commit9c4380daee0e495ea63d161af61d7f7e70c9d9ea (patch)
tree6399c667867d1f6618d15894f5bb1b1f42cfdf7a
parentcb4928ce77c089ae521301776ed90e994c29800c (diff)
lib: add `%pVA` recursive printfrr
Analogous to Linux kernel `%pV` (but our mechanism expects 2 specifier chars and `%pVA` is clearer anyway.) Signed-off-by: David Lamparter <equinox@diac24.net>
-rw-r--r--doc/developer/logging.rst2
-rw-r--r--lib/printf/glue.c18
-rw-r--r--lib/printfrr.h11
-rw-r--r--tests/lib/test_printfrr.c17
4 files changed, 48 insertions, 0 deletions
diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst
index a35e60619c..5e8cb79cc2 100644
--- a/doc/developer/logging.rst
+++ b/doc/developer/logging.rst
@@ -65,6 +65,8 @@ Extensions
+-----------+--------------------------+----------------------------------------------+
| ``%Ld`` | ``int64_t`` | ``-12345`` |
+-----------+--------------------------+----------------------------------------------+
+| ``%pVA`` | ``struct va_format *`` | (recursive printfrr) |
++-----------+--------------------------+----------------------------------------------+
| ``%pI4`` | ``struct in_addr *`` | ``1.2.3.4`` |
| | | |
| | ``in_addr_t *`` | |
diff --git a/lib/printf/glue.c b/lib/printf/glue.c
index 389f503c33..2c97dd639e 100644
--- a/lib/printf/glue.c
+++ b/lib/printf/glue.c
@@ -255,3 +255,21 @@ ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea,
}
return -1;
}
+
+printfrr_ext_autoreg_p("VA", printfrr_va)
+static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ const struct va_format *vaf = ptr;
+ va_list ap;
+
+ if (!vaf || !vaf->fmt || !vaf->va)
+ return bputs(buf, "NULL");
+
+ /* make sure we don't alter the data passed in - especially since
+ * bprintfrr (and thus this) might be called on the same format twice,
+ * when allocating a larger buffer in asnprintfrr()
+ */
+ va_copy(ap, *vaf->va);
+ return vbprintfrr(buf, vaf->fmt, ap);
+}
diff --git a/lib/printfrr.h b/lib/printfrr.h
index 8245a664b3..6ca4d963c4 100644
--- a/lib/printfrr.h
+++ b/lib/printfrr.h
@@ -251,6 +251,17 @@ static inline ssize_t bputch(struct fbuf *buf, char ch)
return 1;
}
+/* %pVA extension, equivalent to Linux kernel %pV */
+
+struct va_format {
+ const char *fmt;
+ va_list *va;
+};
+
+#ifdef _FRR_ATTRIBUTE_PRINTFRR
+#pragma FRR printfrr_ext "%pVA" (struct va_format *)
+#endif
+
/* when using non-ISO-C compatible extension specifiers... */
#ifdef _FRR_ATTRIBUTE_PRINTFRR
diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c
index 5a8d10e9b7..8fa8bfcc23 100644
--- a/tests/lib/test_printfrr.c
+++ b/tests/lib/test_printfrr.c
@@ -128,6 +128,21 @@ static int printchk(const char *ref, const char *fmt, ...)
return 0;
}
+static void test_va(const char *ref, const char *fmt, ...) PRINTFRR(2, 3);
+static void test_va(const char *ref, const char *fmt, ...)
+{
+ struct va_format vaf;
+ va_list ap;
+
+ va_start(ap, fmt);
+ vaf.fmt = fmt;
+ vaf.va = &ap;
+
+ printchk(ref, "VA [%pVA] %s", &vaf, "--");
+
+ va_end(ap);
+}
+
int main(int argc, char **argv)
{
size_t i;
@@ -168,6 +183,8 @@ int main(int argc, char **argv)
printcmp("%p", &ip);
+ test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234);
+
snprintfrr(buf, sizeof(buf), "test%s", "#1");
csnprintfrr(buf, sizeof(buf), "test%s", "#2");
assert(strcmp(buf, "test#1test#2") == 0);