From 250a918dc4c8a15d927deecc3b3f6a0604657ae4 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 29 Oct 2013 19:53:43 +0100 Subject: [PATCH] strv: introduce new strv_from_stdarg_alloca() macro to generate a string array from stdarg function parameters This allows us to turn lists of strings passed in easily into string arrays without having to allocate memory. --- src/core/execute.c | 3 +- src/libsystemd-bus/bus-objects.c | 30 ++++-------------- src/shared/conf-files.c | 10 ++---- src/shared/strv.h | 29 +++++++++++++++++ src/test/test-strv.c | 53 ++++++++++++++++++++++---------- 5 files changed, 76 insertions(+), 49 deletions(-) diff --git a/src/core/execute.c b/src/core/execute.c index e04f46f03..3ae28ee08 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -2214,7 +2214,8 @@ int exec_command_set(ExecCommand *c, const char *path, ...) { if (!l) return -ENOMEM; - if (!(p = strdup(path))) { + p = strdup(path); + if (!p) { strv_free(l); return -ENOMEM; } diff --git a/src/libsystemd-bus/bus-objects.c b/src/libsystemd-bus/bus-objects.c index c852ad6c4..31d761e21 100644 --- a/src/libsystemd-bus/bus-objects.c +++ b/src/libsystemd-bus/bus-objects.c @@ -1976,8 +1976,7 @@ int sd_bus_emit_properties_changed( const char *interface, const char *name, ...) { - _cleanup_strv_free_ char **names = NULL; - va_list ap; + char **names; assert_return(bus, -EINVAL); assert_return(object_path_is_valid(path), -EINVAL); @@ -1988,12 +1987,7 @@ int sd_bus_emit_properties_changed( if (!name) return 0; - va_start(ap, name); - names = strv_new_ap(name, ap); - va_end(ap); - - if (!names) - return -ENOMEM; + names = strv_from_stdarg_alloca(name); return sd_bus_emit_properties_changed_strv(bus, path, interface, names); } @@ -2157,20 +2151,14 @@ int sd_bus_emit_interfaces_added_strv(sd_bus *bus, const char *path, char **inte } int sd_bus_emit_interfaces_added(sd_bus *bus, const char *path, const char *interface, ...) { - _cleanup_strv_free_ char **interfaces = NULL; - va_list ap; + char **interfaces; assert_return(bus, -EINVAL); assert_return(object_path_is_valid(path), -EINVAL); assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); - va_start(ap, interface); - interfaces = strv_new_ap(interface, ap); - va_end(ap); - - if (!interfaces) - return -ENOMEM; + interfaces = strv_from_stdarg_alloca(interface); return sd_bus_emit_interfaces_added_strv(bus, path, interfaces); } @@ -2203,20 +2191,14 @@ int sd_bus_emit_interfaces_removed_strv(sd_bus *bus, const char *path, char **in } int sd_bus_emit_interfaces_removed(sd_bus *bus, const char *path, const char *interface, ...) { - _cleanup_strv_free_ char **interfaces = NULL; - va_list ap; + char **interfaces; assert_return(bus, -EINVAL); assert_return(object_path_is_valid(path), -EINVAL); assert_return(BUS_IS_OPEN(bus->state), -ENOTCONN); assert_return(!bus_pid_changed(bus), -ECHILD); - va_start(ap, interface); - interfaces = strv_new_ap(interface, ap); - va_end(ap); - - if (!interfaces) - return -ENOMEM; + interfaces = strv_from_stdarg_alloca(interface); return sd_bus_emit_interfaces_removed_strv(bus, path, interfaces); } diff --git a/src/shared/conf-files.c b/src/shared/conf-files.c index ed4070c66..7ba4bee43 100644 --- a/src/shared/conf-files.c +++ b/src/shared/conf-files.c @@ -148,18 +148,12 @@ int conf_files_list_strv(char ***strv, const char *suffix, const char *root, con } int conf_files_list(char ***strv, const char *suffix, const char *root, const char *dir, ...) { - _cleanup_strv_free_ char **dirs = NULL; - va_list ap; + char **dirs; assert(strv); assert(suffix); - va_start(ap, dir); - dirs = strv_new_ap(dir, ap); - va_end(ap); - - if (!dirs) - return -ENOMEM; + dirs = strv_from_stdarg_alloca(dir); return conf_files_list_strv_internal(strv, suffix, root, dirs); } diff --git a/src/shared/strv.h b/src/shared/strv.h index cccf2e6a9..737728a3c 100644 --- a/src/shared/strv.h +++ b/src/shared/strv.h @@ -85,3 +85,32 @@ bool strv_overlap(char **a, char **b) _pure_; char **strv_sort(char **l); void strv_print(char **l); + +#define strv_from_stdarg_alloca(first) \ + ({ \ + char **_l; \ + \ + if (!first) \ + _l = ((char*[1]) { NULL }); \ + else { \ + unsigned _n; \ + va_list _ap; \ + \ + _n = 1; \ + va_start(_ap, first); \ + while (va_arg(_ap, char*)) \ + _n++; \ + va_end(_ap); \ + \ + _l = newa(char*, _n+1); \ + _l[_n = 0] = (char*) first; \ + va_start(_ap, first); \ + for (;;) { \ + _l[++_n] = va_arg(_ap, char*); \ + if (!_l[_n]) \ + break; \ + } \ + va_end(_ap); \ + } \ + _l; \ + }) diff --git a/src/test/test-strv.c b/src/test/test-strv.c index de5cef0b1..7002b8b1c 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -283,31 +283,31 @@ static void test_strv_append(void) { } static void test_strv_foreach(void) { - _cleanup_strv_free_ char **a; - unsigned i = 0; - char **check; + _cleanup_strv_free_ char **a; + unsigned i = 0; + char **check; - a = strv_new("one", "two", "three", NULL); + a = strv_new("one", "two", "three", NULL); - assert_se(a); + assert_se(a); - STRV_FOREACH(check, a) { - assert_se(streq(*check, input_table_multiple[i++])); - } + STRV_FOREACH(check, a) { + assert_se(streq(*check, input_table_multiple[i++])); + } } static void test_strv_foreach_backwards(void) { - _cleanup_strv_free_ char **a; - unsigned i = 2; - char **check; + _cleanup_strv_free_ char **a; + unsigned i = 2; + char **check; - a = strv_new("one", "two", "three", NULL); + a = strv_new("one", "two", "three", NULL); - assert_se(a); + assert_se(a); - STRV_FOREACH_BACKWARDS(check, a) { - assert_se(streq(*check, input_table_multiple[i--])); - } + STRV_FOREACH_BACKWARDS(check, a) { + assert_se(streq(*check, input_table_multiple[i--])); + } } static void test_strv_foreach_pair(void) { @@ -324,6 +324,26 @@ static void test_strv_foreach_pair(void) { } } +static void test_strv_from_stdarg_alloca_one(const char **l, const char *first, ...) { + char **j; + unsigned i; + + j = strv_from_stdarg_alloca(first); + + for (i = 0;; i++) { + assert_se(streq_ptr(l[i], j[i])); + + if (!l[i]) + break; + } +} + +static void test_strv_from_stdarg_alloca(void) { + test_strv_from_stdarg_alloca_one((const char*[]) { "foo", "bar", NULL }, "foo", "bar", NULL); + test_strv_from_stdarg_alloca_one((const char*[]) { "foo", "bar", NULL }, "foo", "bar", NULL); + test_strv_from_stdarg_alloca_one((const char*[]) { "foo", NULL }, "foo", NULL); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -346,6 +366,7 @@ int main(int argc, char *argv[]) { test_strv_merge(); test_strv_merge_concat(); test_strv_append(); + test_strv_from_stdarg_alloca(); return 0; } -- 2.30.2