vici: Add a callback based recursive parser function

This commit is contained in:
Martin Willi 2014-02-12 15:37:06 +01:00
parent d9ae1c68e5
commit 993bfe95fb
2 changed files with 136 additions and 0 deletions

View File

@ -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;

View File

@ -123,6 +123,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.
*
@ -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.