add parser helpers similar to the blobmsg parser in libubox
authorFelix Fietkau <nbd@openwrt.org>
Tue, 5 Apr 2011 01:29:17 +0000 (03:29 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 5 Apr 2011 01:29:21 +0000 (03:29 +0200)
CMakeLists.txt
parse.c [new file with mode: 0644]
uci.h

index 7df3be9..54c5cf2 100644 (file)
@@ -13,7 +13,7 @@ OPTION(BUILD_LUA "build Lua plugin" ON)
 
 CONFIGURE_FILE( ${CMAKE_SOURCE_DIR}/uci_config.h.in ${CMAKE_SOURCE_DIR}/uci_config.h )
 
-SET(LIB_SOURCES libuci.c file.c util.c delta.c)
+SET(LIB_SOURCES libuci.c file.c util.c delta.c parse.c)
 
 ADD_LIBRARY(uci-shared SHARED ${LIB_SOURCES})
 SET_TARGET_PROPERTIES(uci-shared PROPERTIES OUTPUT_NAME uci)
diff --git a/parse.c b/parse.c
new file mode 100644 (file)
index 0000000..d0684f9
--- /dev/null
+++ b/parse.c
@@ -0,0 +1,130 @@
+/*
+ * libuci - Library for the Unified Configuration Interface
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <string.h>
+#include <stdint.h>
+
+#include "uci.h"
+
+void uci_parse_section(struct uci_section *s, struct uci_parse_option *opts,
+                      int n_opts, struct uci_option **tb)
+{
+       struct uci_element *e;
+
+       memset(tb, 0, n_opts * sizeof(*tb));
+
+       uci_foreach_element(&s->options, e) {
+               struct uci_option *o = uci_to_option(e);
+               int i;
+
+               for (i = 0; i < n_opts; i++) {
+                       if (tb[i])
+                               continue;
+
+                       if (strcmp(opts[i].name, o->e.name) != 0)
+                               continue;
+
+                       if (opts[i].type >= 0 && opts[i].type != o->type)
+                               continue;
+
+                       /* match found */
+                       tb[i] = o;
+                       break;
+               }
+       }
+}
+
+//-----------------------------------------------------------------------------
+// MurmurHashNeutral2, by Austin Appleby
+
+// Same as MurmurHash2, but endian- and alignment-neutral.
+static uint32_t hash_murmur2(uint32_t h, const void * key, int len)
+{
+       const unsigned char * data = key;
+       const uint32_t m = 0x5bd1e995;
+       const int r = 24;
+
+       while(len >= 4)
+       {
+               unsigned int k;
+
+               k  = data[0];
+               k |= data[1] << 8;
+               k |= data[2] << 16;
+               k |= data[3] << 24;
+
+               k *= m;
+               k ^= k >> r;
+               k *= m;
+
+               h *= m;
+               h ^= k;
+
+               data += 4;
+               len -= 4;
+       }
+
+       switch(len)
+       {
+       case 3: h ^= data[2] << 16;
+       case 2: h ^= data[1] << 8;
+       case 1: h ^= data[0];
+               h *= m;
+       };
+
+       h ^= h >> 13;
+       h *= m;
+       h ^= h >> 15;
+
+       return h;
+}
+
+static uint32_t uci_hash_list(uint32_t h, struct uci_list *list)
+{
+       struct uci_element *e;
+
+       uci_foreach_element(list, e) {
+               h = hash_murmur2(h, e->name, strlen(e->name) + 1);
+       }
+       return h;
+}
+
+uint32_t uci_hash_options(struct uci_option **tb, int n_opts)
+{
+       uint32_t h = 0xdeadc0de;
+       int i;
+
+       for (i = 0; i < n_opts; i++) {
+               struct uci_option *o = tb[i];
+
+               if (!tb[i])
+                       continue;
+
+               h = hash_murmur2(h, o->e.name, strlen(o->e.name) + 1);
+               h = hash_murmur2(h, &o->type, sizeof(o->type));
+
+               switch (tb[i]->type) {
+               case UCI_TYPE_STRING:
+                       h = hash_murmur2(h, o->v.string, strlen(o->v.string) + 1);
+                       break;
+               case UCI_TYPE_LIST:
+                       h = uci_hash_list(h, &o->v.list);
+                       break;
+               }
+       }
+
+       return h;
+}
+
+
diff --git a/uci.h b/uci.h
index 97bff7d..696f4f6 100644 (file)
--- a/uci.h
+++ b/uci.h
@@ -33,6 +33,7 @@ extern "C" {
 #include <stdbool.h>
 #include <setjmp.h>
 #include <stdio.h>
+#include <stdint.h>
 
 #define UCI_CONFDIR "/etc/config"
 #define UCI_SAVEDIR "/tmp/.uci"
@@ -69,6 +70,7 @@ struct uci_option;
 struct uci_delta;
 struct uci_context;
 struct uci_backend;
+struct uci_parse_option;
 struct uci_parse_context;
 
 
@@ -348,6 +350,23 @@ int uci_parse_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str);
  */
 int uci_lookup_next(struct uci_context *ctx, struct uci_element **e, struct uci_list *list, const char *name);
 
+/**
+ * uci_parse_section: look up a set of options
+ * @s: uci section
+ * @opts: list of options to look up
+ * @n_opts: number of options to look up
+ * @tb: array of pointers to found options
+ */
+void uci_parse_section(struct uci_section *s, struct uci_parse_option *opts,
+                      int n_opts, struct uci_option **tb);
+
+/**
+ * uci_hash_options: build a hash over a list of options
+ * @tb: list of option pointers
+ * @n_opts: number of options
+ */
+uint32_t uci_hash_options(struct uci_option **tb, int n_opts);
+
 
 /* UCI data structures */
 enum uci_type {
@@ -525,6 +544,11 @@ struct uci_plugin
        void *dlh;
 };
 
+struct uci_parse_option {
+       const char *name;
+       enum uci_option_type type;
+};
+
 
 /* linked list handling */
 #ifndef offsetof