From 88207b76417252edea82d5958ab11f73fb037e9c Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 20 May 2016 13:32:25 -0300 Subject: [PATCH] sol-bus: Add a helper to parse dictionaries In D-Bus, there isn't the concept of dictionaries, only dictionary entries and arrays, and using them is pretty common, so it makes sense to provide a helper to parse dictionaries. Signed-off-by: Vinicius Costa Gomes --- src/lib/common/sol-bus.c | 64 ++++++++++++++++++++++++++++++++++++++++ src/lib/common/sol-bus.h | 47 +++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+) diff --git a/src/lib/common/sol-bus.c b/src/lib/common/sol-bus.c index 7dd6e61f8..9e9b518d4 100644 --- a/src/lib/common/sol-bus.c +++ b/src/lib/common/sol-bus.c @@ -947,3 +947,67 @@ sol_bus_log_callback(sd_bus_message *reply, void *userdata, return -1; } + +SOL_API int +sol_bus_parse_dict(sd_bus_message *m, const struct sol_bus_dict_entry *dict) +{ + int r; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "{sv}"); + SOL_INT_CHECK(r, < 0, r); + + do { + const struct sol_bus_dict_entry *entry; + const char *member, *contents; + char type; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_DICT_ENTRY, "sv"); + if (r <= 0) { + r = 0; + break; + } + + r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &member); + SOL_INT_CHECK_GOTO(r, < 0, end); + + r = sd_bus_message_peek_type(m, &type, &contents); + SOL_INT_CHECK_GOTO(r, < 0, end); + + for (entry = dict; entry && entry->name; entry++) { + if (streq(entry->name, member)) + break; + } + + if (entry->name) { + size_t len; + + r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents); + SOL_INT_CHECK_GOTO(r, < 0, end); + + len = strlen(contents); + + if (entry->type == 'v' && entry->parse_variant) + r = entry->parse_variant(m, entry->value); + else if (len == 1 && entry->type == contents[0]) + r = sd_bus_message_read_basic(m, entry->type, entry->value); + else { + SOL_WRN("Invalid type in message '%s', expecting '%c'", + contents, entry->type); + r = -EINVAL; + } + SOL_INT_CHECK_GOTO(r, < 0, end); + + r = sd_bus_message_exit_container(m); + SOL_INT_CHECK_GOTO(r, < 0, end); + } else { + r = sd_bus_message_skip(m, "v"); + SOL_INT_CHECK_GOTO(r, < 0, end); + } + + r = sd_bus_message_exit_container(m); + SOL_INT_CHECK_GOTO(r, < 0, end); + } while (1); + +end: + return r; +} diff --git a/src/lib/common/sol-bus.h b/src/lib/common/sol-bus.h index 922829b81..951d1fc60 100644 --- a/src/lib/common/sol-bus.h +++ b/src/lib/common/sol-bus.h @@ -272,3 +272,50 @@ int sol_bus_remove_interfaces_watch(struct sol_bus_client *client, */ int sol_bus_log_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error); + +/** + * @brief Represents an entry in a D-Bus dictionary + * + * A common idiom in D-Bus is having an array of type 'a{sv}', representing + * a dictionary, this struct and sol_bus_parse_dict() help parsing those + * data structures. + */ +struct sol_bus_dict_entry { + /** + * @brief The name of the dictionary entry + */ + const char *name; + /** + * @brief The type of value of the property in the dictionary + * + * It can be any of the basic types, or 'v' (SD_BUS_TYPE_VARIANT), in + * case the type is not basic, in this case, the function parse_variant() will + * be called. + */ + char type; + /** + * @brief In which place to store the parsed value + */ + void *value; + /** + * @brief Function to be called in case the value being parsed is not basic. + */ + int (*parse_variant)(sd_bus_message *m, void *value); +}; + +/** + * @brief Represents the final entry in a dictionary parser. + */ +#define SOL_BUS_DICT_ENTRY_FINAL { .name = NULL } + +/** + * @brief Helper to parse D-Bus dictionaries + * + * @see #sol_bus_dict_entry + * + * @param m D-Bus message containing the D-Bus dictionary array + * @param dict Dictionary representation, informing how to parse the dictionary. + * + * @return 0 on success, -errno otherwise. + */ +int sol_bus_parse_dict(sd_bus_message *m, const struct sol_bus_dict_entry *dict);