diff --git a/include/common/buf.h b/include/common/buf.h index bcbc8301..a75c1144 100644 --- a/include/common/buf.h +++ b/include/common/buf.h @@ -43,6 +43,13 @@ void buf_expand_tilde(struct buf *s); */ void buf_expand_shell_variables(struct buf *s); +/** + * buf_add_fmt - add format string to C string buffer + * @s: buffer + * @fmt: format string to be added + */ +void buf_add_fmt(struct buf *s, const char *fmt, ...); + /** * buf_add - add data to C string buffer * @s: buffer diff --git a/src/common/buf.c b/src/common/buf.c index ecdddc6e..d36f64d5 100644 --- a/src/common/buf.c +++ b/src/common/buf.c @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only #include #include +#include #include +#include #include #include "common/buf.h" #include "common/macros.h" @@ -95,6 +97,38 @@ buf_expand(struct buf *s, int new_alloc) s->alloc = new_alloc; } +void +buf_add_fmt(struct buf *s, const char *fmt, ...) +{ + if (string_null_or_empty(fmt)) { + return; + } + size_t size = 0; + va_list ap; + + va_start(ap, fmt); + int n = vsnprintf(NULL, size, fmt, ap); + va_end(ap); + + if (n < 0) { + return; + } + + size = (size_t)n + 1; + buf_expand(s, s->len + size); + + va_start(ap, fmt); + n = vsnprintf(s->data + s->len, size, fmt, ap); + va_end(ap); + + if (n < 0) { + return; + } + + s->len += n; + s->data[s->len] = 0; +} + void buf_add(struct buf *s, const char *data) { diff --git a/t/buf-simple.c b/t/buf-simple.c index 47722116..3993ae83 100644 --- a/t/buf-simple.c +++ b/t/buf-simple.c @@ -55,10 +55,25 @@ test_expand_title(void **state) free(s.data); } +static void +test_buf_add_fmt(void **state) +{ + (void)state; + + struct buf s = BUF_INIT; + + buf_add(&s, "foo"); + buf_add_fmt(&s, " %s baz %d", "bar", 10); + assert_string_equal(s.data, "foo bar baz 10"); + + buf_reset(&s); +} + int main(int argc, char **argv) { const struct CMUnitTest tests[] = { cmocka_unit_test(test_expand_title), + cmocka_unit_test(test_buf_add_fmt), }; return cmocka_run_group_tests(tests, NULL, NULL);