vici: Add generic callback based vici message parsing
This commit is contained in:
@@ -412,6 +412,100 @@ METHOD(vici_message_t, get_encoding, chunk_t,
|
||||
return this->encoding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Private parse context data
|
||||
*/
|
||||
struct vici_parse_context_t {
|
||||
/** current section nesting level */
|
||||
int level;
|
||||
/** parse enumerator */
|
||||
enumerator_t *e;
|
||||
};
|
||||
|
||||
METHOD(vici_message_t, parse, bool,
|
||||
private_vici_message_t *this, vici_parse_context_t *ctx,
|
||||
vici_section_cb_t section, vici_value_cb_t kv, vici_value_cb_t li,
|
||||
void *user)
|
||||
{
|
||||
vici_parse_context_t root = {};
|
||||
char *name, *list = NULL;
|
||||
vici_type_t type;
|
||||
chunk_t value;
|
||||
int base;
|
||||
bool ok = TRUE;
|
||||
|
||||
if (!ctx)
|
||||
{
|
||||
ctx = &root;
|
||||
root.e = create_enumerator(this);
|
||||
}
|
||||
|
||||
base = ctx->level;
|
||||
|
||||
while (ok)
|
||||
{
|
||||
ok = ctx->e->enumerate(ctx->e, &type, &name, &value);
|
||||
if (ok)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case VICI_KEY_VALUE:
|
||||
if (ctx->level == base && kv)
|
||||
{
|
||||
name = strdup(name);
|
||||
this->strings->insert_last(this->strings, name);
|
||||
ok = kv(user, &this->public, name, value);
|
||||
}
|
||||
continue;
|
||||
case VICI_LIST_START:
|
||||
if (ctx->level == base)
|
||||
{
|
||||
list = strdup(name);
|
||||
this->strings->insert_last(this->strings, list);
|
||||
}
|
||||
continue;
|
||||
case VICI_LIST_ITEM:
|
||||
if (list && li)
|
||||
{
|
||||
name = strdup(name);
|
||||
this->strings->insert_last(this->strings, name);
|
||||
ok = li(user, &this->public, list, value);
|
||||
}
|
||||
continue;
|
||||
case VICI_LIST_END:
|
||||
if (ctx->level == base)
|
||||
{
|
||||
list = NULL;
|
||||
}
|
||||
continue;
|
||||
case VICI_SECTION_START:
|
||||
if (ctx->level++ == base && section)
|
||||
{
|
||||
name = strdup(name);
|
||||
this->strings->insert_last(this->strings, name);
|
||||
ok = section(user, &this->public, ctx, name);
|
||||
}
|
||||
continue;
|
||||
case VICI_SECTION_END:
|
||||
if (ctx->level-- == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
case VICI_END:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (ctx == &root)
|
||||
{
|
||||
root.e->destroy(root.e);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
METHOD(vici_message_t, dump, bool,
|
||||
private_vici_message_t *this, char *label, FILE *out)
|
||||
{
|
||||
@@ -506,6 +600,7 @@ vici_message_t *vici_message_create_from_data(chunk_t data, bool cleanup)
|
||||
.get_value = _get_value,
|
||||
.vget_value = _vget_value,
|
||||
.get_encoding = _get_encoding,
|
||||
.parse = _parse,
|
||||
.dump = _dump,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <library.h>
|
||||
|
||||
typedef struct vici_message_t vici_message_t;
|
||||
typedef struct vici_parse_context_t vici_parse_context_t;
|
||||
typedef enum vici_type_t vici_type_t;
|
||||
|
||||
/**
|
||||
@@ -47,6 +48,30 @@ enum vici_type_t {
|
||||
VICI_END
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback function for key/value and list items, invoked by parse().
|
||||
*
|
||||
* @param user user data, as passed to parse()
|
||||
* @param message message currently parsing
|
||||
* @param name name of key or list
|
||||
* @param value parsed value
|
||||
* @return TRUE if parsed successfully
|
||||
*/
|
||||
typedef bool (*vici_value_cb_t)(void *user, vici_message_t *message,
|
||||
char *name, chunk_t value);
|
||||
|
||||
/**
|
||||
* Callback function for sections, invoked by parse().
|
||||
*
|
||||
* @param user user data, as passed to parse()
|
||||
* @param message message currently parsing
|
||||
* @param ctx parse context, to pass to recursive parse() invocations.
|
||||
* @param name name of the section
|
||||
* @return TRUE if parsed successfully
|
||||
*/
|
||||
typedef bool (*vici_section_cb_t)(void *user, vici_message_t *message,
|
||||
vici_parse_context_t *ctx, char *name);
|
||||
|
||||
/**
|
||||
* Names for vici encoding types
|
||||
*/
|
||||
@@ -137,6 +162,25 @@ struct vici_message_t {
|
||||
*/
|
||||
chunk_t (*get_encoding)(vici_message_t *this);
|
||||
|
||||
/**
|
||||
* Parse a message using callback functions.
|
||||
*
|
||||
* 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 parse() from within a section callback using the provided parse
|
||||
* context.
|
||||
*
|
||||
* @param ctx parse context, NULL for root level
|
||||
* @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 TRUE if parsed successfully
|
||||
*/
|
||||
bool (*parse)(vici_message_t *this, vici_parse_context_t *ctx,
|
||||
vici_section_cb_t section, vici_value_cb_t kv,
|
||||
vici_value_cb_t li, void *user);
|
||||
|
||||
/**
|
||||
* Dump a message text representation to a FILE stream.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user