vici: Add a callback based recursive parser function
authorMartin Willi <martin@revosec.ch>
Wed, 12 Feb 2014 14:37:06 +0000 (15:37 +0100)
committerMartin Willi <martin@revosec.ch>
Wed, 7 May 2014 12:13:35 +0000 (14:13 +0200)
src/libcharon/plugins/vici/libvici.c
src/libcharon/plugins/vici/libvici.h

index 61ff5b9..9b7ccb1 100644 (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;
index 499e9a0..2689b39 100644 (file)
@@ -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.