From 9c4380daee0e495ea63d161af61d7f7e70c9d9ea Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Tue, 2 Mar 2021 20:45:57 +0100 Subject: [PATCH] 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 --- doc/developer/logging.rst | 2 ++ lib/printf/glue.c | 18 ++++++++++++++++++ lib/printfrr.h | 11 +++++++++++ tests/lib/test_printfrr.c | 17 +++++++++++++++++ 4 files changed, 48 insertions(+) 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 = ≈ + + 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); -- 2.39.5