From 993bfe95fb75ddf46491ddc4f59916f424f8a849 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 12 Feb 2014 15:37:06 +0100 Subject: [PATCH] vici: Add a callback based recursive parser function --- src/libcharon/plugins/vici/libvici.c | 95 ++++++++++++++++++++++++++++++++++++ src/libcharon/plugins/vici/libvici.h | 41 ++++++++++++++++ 2 files changed, 136 insertions(+) diff --git a/src/libcharon/plugins/vici/libvici.c b/src/libcharon/plugins/vici/libvici.c index 61ff5b9..9b7ccb1 100644 --- a/src/libcharon/plugins/vici/libvici.c +++ b/src/libcharon/plugins/vici/libvici.c @@ -94,6 +94,8 @@ struct vici_res_t { char *name; /** currently enumerating value */ chunk_t value; + /** section nesting level of callback parser */ + int level; }; /** @@ -495,6 +497,7 @@ void* vici_parse_value(vici_res_t *res, int *len) *len = res->value.len; return res->value.ptr; default: + *len = 0; errno = EINVAL; return NULL; } @@ -522,6 +525,98 @@ char* vici_parse_value_str(vici_res_t *res) } } +int vici_parse_cb(vici_res_t *res, vici_parse_section_cb_t section, + vici_parse_value_cb_t kv, vici_parse_value_cb_t li, + void *user) +{ + char *name, *list = NULL; + void *value; + int base, len, ret; + + base = res->level; + + while (TRUE) + { + switch (vici_parse(res)) + { + case VICI_PARSE_KEY_VALUE: + if (res->level == base) + { + if (kv) + { + name = vici_parse_name(res); + value = vici_parse_value(res, &len); + if (name && value) + { + ret = kv(user, res, name, value, len); + if (ret) + { + return ret; + } + } + } + } + break; + case VICI_PARSE_BEGIN_SECTION: + if (res->level++ == base) + { + if (section) + { + name = vici_parse_name(res); + if (name) + { + ret = section(user, res, name); + if (ret) + { + return ret; + } + } + } + } + break; + case VICI_PARSE_END_SECTION: + if (res->level-- == base) + { + return 0; + } + break; + case VICI_PARSE_END: + res->level = 0; + return 0; + case VICI_PARSE_BEGIN_LIST: + if (res->level == base) + { + list = vici_parse_name(res); + } + break; + case VICI_PARSE_LIST_ITEM: + if (list && li) + { + value = vici_parse_value(res, &len); + if (value) + { + ret = li(user, res, list, value, len); + if (ret) + { + return ret; + } + } + } + break; + case VICI_PARSE_END_LIST: + if (res->level == base) + { + list = NULL; + } + break; + case VICI_PARSE_ERROR: + res->level = 0; + errno = EBADMSG; + return 1; + } + } +} + void* vici_find(vici_res_t *res, int *len, char *fmt, ...) { va_list args; diff --git a/src/libcharon/plugins/vici/libvici.h b/src/libcharon/plugins/vici/libvici.h index 499e9a0..2689b39 100644 --- a/src/libcharon/plugins/vici/libvici.h +++ b/src/libcharon/plugins/vici/libvici.h @@ -124,6 +124,29 @@ typedef enum { typedef void (*vici_event_cb_t)(void *user, char *name, vici_res_t *msg); /** + * Callback function for key/value and list items, invoked by vici_parse_cb(). + * + * @param user user data, as passed to vici_parse_cb() + * @param res message currently parsing + * @param name name of key or list + * @param value value buffer + * @param len length of value buffer + * @return 0 if parsed successfully + */ +typedef int (*vici_parse_value_cb_t)(void *user, vici_res_t *res, char *name, + void *value, int len); + +/** + * Callback function for sections, invoked by vici_parse_cb(). + * + * @param user user data, as passed to vici_parse_cb() + * @param res message currently parsing + * @param name name of the section + * @return 0 if parsed successfully + */ +typedef int (*vici_parse_section_cb_t)(void *user, vici_res_t *res, char *name); + +/** * Open a new vici connection. * * On error, NULL is returned and errno is set appropriately. @@ -309,6 +332,24 @@ void* vici_parse_value(vici_res_t *res, int *len); char* vici_parse_value_str(vici_res_t *res); /** + * Parse a complete message with callbacks. + * + * Any of the callbacks may be NULL to skip this kind of item. Callbacks are + * invoked for the current section level only. To descent into sections, call + * vici_parse_cb() from within a section callback. + * + * @param res message to parse + * @param section callback invoked for each section + * @param kv callback invoked for key/value pairs + * @param li callback invoked for list items + * @param user user data to pass to callbacks + * @return 0 if parsing successful + */ +int vici_parse_cb(vici_res_t *res, vici_parse_section_cb_t section, + vici_parse_value_cb_t kv, vici_parse_value_cb_t li, + void *user); + +/* * Find a blob value in a message for a given key. * * Sections can be selected by prefixing them separated by dots. -- 2.7.4