ucimap: add helper function for resizing lists and freeing items (both using ucimap...
authorFelix Fietkau <nbd@openwrt.org>
Fri, 4 Sep 2009 22:39:41 +0000 (00:39 +0200)
committerFelix Fietkau <nbd@openwrt.org>
Fri, 4 Sep 2009 22:42:38 +0000 (00:42 +0200)
test/config/network
test/references/ucimap_example.result [deleted file]
test/references/ucimap_example_1.result [new file with mode: 0644]
test/references/ucimap_example_2.result [new file with mode: 0644]
test/tests.d/060-ucimap_example
ucimap-example.c
ucimap.c
ucimap.h

index 6e2b5cc..426e345 100644 (file)
@@ -9,8 +9,6 @@ config 'interface' 'lan'
        option 'ifname' 'eth0'
        option 'test' '123'
        option 'enabled' 'off'
-       list 'aliases' 'a'
-       list 'aliases' 'b'
        option 'ipaddr' '2.3.4.5'
 
 config 'interface' 'wan'
diff --git a/test/references/ucimap_example.result b/test/references/ucimap_example.result
deleted file mode 100644 (file)
index 4a20965..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-New network section 'lan'
-       type: static
-       ifname: eth0
-       ipaddr: 2.3.4.5
-       test: 123
-       enabled: off
-New alias: a
-New alias: b
-New network section 'wan'
-       type: dhcp
-       ifname: eth1
-       ipaddr: 0.0.0.0
-       test: -1
-       enabled: on
-New alias: c
-New alias: d
diff --git a/test/references/ucimap_example_1.result b/test/references/ucimap_example_1.result
new file mode 100644 (file)
index 0000000..9f73ad6
--- /dev/null
@@ -0,0 +1,15 @@
+New network section 'lan'
+       type: static
+       ifname: eth0
+       ipaddr: 2.3.4.5
+       test: 123
+       enabled: off
+New alias: a
+New alias: b
+New network section 'wan'
+       type: dhcp
+       ifname: eth1
+       ipaddr: 0.0.0.0
+       test: -1
+       enabled: on
+Configured aliases: c d
diff --git a/test/references/ucimap_example_2.result b/test/references/ucimap_example_2.result
new file mode 100644 (file)
index 0000000..d333b5b
--- /dev/null
@@ -0,0 +1,15 @@
+New network section 'lan'
+       type: static
+       ifname: eth0
+       ipaddr: 0.0.0.0
+       test: 123
+       enabled: off
+New alias: a
+New alias: b
+New network section 'wan'
+       type: dhcp
+       ifname: eth1
+       ipaddr: 0.0.0.0
+       test: -1
+       enabled: on
+Configured aliases: c d
index c517637..984726b 100644 (file)
@@ -1,5 +1,9 @@
 test_ucimap_example()
 {
-       ( cd ..; ./ucimap-example ) > "${TMP_DIR}/ucimap_example.result"
-       assertSameFile "${TMP_DIR}/ucimap_example.result" "${REF_DIR}/ucimap_example.result"
+       rm -rf ./save
+       ( cd ..; ./ucimap-example -s ) > "${TMP_DIR}/ucimap_example.result"
+       assertSameFile "${TMP_DIR}/ucimap_example.result" "${REF_DIR}/ucimap_example_1.result"
+       ( cd ..; ./ucimap-example -s ) > "${TMP_DIR}/ucimap_example.result"
+       assertSameFile "${TMP_DIR}/ucimap_example.result" "${REF_DIR}/ucimap_example_2.result"
+       rm -rf ./save
 }
index c59e72c..1fd9530 100644 (file)
@@ -68,8 +68,12 @@ network_format_ip(void *sction, struct uci_optmap *om, union ucimap_data *data,
        static char buf[16];
        unsigned char *ip = (unsigned char *) data->data[0];
 
-       sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
-       *str = buf;
+       if (ip) {
+               sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+               *str = buf;
+       } else {
+               *str = NULL;
+       }
 
        return 0;
 }
@@ -234,12 +238,18 @@ int main(int argc, char **argv)
        struct list_head *p;
        struct uci_network *net;
        struct uci_alias *alias;
+       bool set = false;
        int i;
 
        INIT_LIST_HEAD(&ifs);
        ctx = uci_alloc_context();
        ucimap_init(&network_map);
 
+       if ((argc >= 2) && !strcmp(argv[1], "-s")) {
+               uci_set_savedir(ctx, "./test/save");
+               set = true;
+       }
+
        uci_set_confdir(ctx, "./test/config");
        uci_load(ctx, "network", &pkg);
 
@@ -266,16 +276,29 @@ int main(int argc, char **argv)
                        net->test,
                        (net->enabled ? "on" : "off"));
 
-               for (i = 0; i < net->aliases->n_items; i++) {
-                       alias = net->aliases->item[i].ptr;
+               if (net->aliases->n_items > 0) {
+                       printf("Configured aliases:");
+                       for (i = 0; i < net->aliases->n_items; i++) {
+                               alias = net->aliases->item[i].ptr;
+                               printf(" %s", alias->name);
+                       }
+                       printf("\n");
+               }
+               list_for_each_entry(alias, &net->alias, list) {
+                       for (i = 0; i < net->aliases->n_items; i++) {
+                               if (alias == net->aliases->item[i].ptr)
+                                       goto next_alias;
+                       }
                        printf("New alias: %s\n", alias->name);
+next_alias:
+                       continue;
+               }
+               if (set && !strcmp(net->name, "lan")) {
+                       ucimap_free_item(&net->map, &net->ipaddr);
+                       ucimap_set_changed(&net->map, &net->ipaddr);
+                       ucimap_store_section(&network_map, pkg, &net->map);
+                       uci_save(ctx, pkg);
                }
-#if 0
-               memcpy(net->ipaddr, "\x01\x03\x04\x05", 4);
-               ucimap_set_changed(&net->map, &net->ipaddr);
-               ucimap_store_section(&network_map, pkg, &net->map);
-               uci_save(ctx, pkg);
-#endif
        }
 
 
index 9aafe0b..0d16bb4 100644 (file)
--- a/ucimap.c
+++ b/ucimap.c
 #include <limits.h>
 #include <stdio.h>
 #include <ctype.h>
+#include <errno.h>
 #include "ucimap.h"
 #include "uci_internal.h"
 
 struct uci_alloc {
-       enum ucimap_type type;
-       union {
-               void **ptr;
-       } data;
+       void *ptr;
 };
 
 struct uci_alloc_custom {
@@ -124,22 +122,10 @@ ucimap_init(struct uci_map *map)
 }
 
 static void
-ucimap_free_item(struct uci_alloc *a)
-{
-       switch(a->type & UCIMAP_TYPE) {
-       case UCIMAP_SIMPLE:
-       case UCIMAP_LIST:
-               free(a->data.ptr);
-               break;
-       }
-}
-
-static void
 ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr)
 {
        struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
-       a->type = UCIMAP_SIMPLE;
-       a->data.ptr = ptr;
+       a->ptr = ptr;
 }
 
 void
@@ -156,7 +142,7 @@ ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
                sd->sm->free(map, section);
 
        for (i = 0; i < sd->allocmap_len; i++) {
-               ucimap_free_item(&sd->allocmap[i]);
+               free(sd->allocmap[i].ptr);
        }
 
        if (sd->alloc_custom) {
@@ -228,6 +214,81 @@ ucimap_handle_fixup(struct uci_map *map, struct uci_fixup *f)
        return true;
 }
 
+void
+ucimap_free_item(struct ucimap_section_data *sd, void *item)
+{
+       struct uci_alloc_custom *ac;
+       struct uci_alloc *a;
+       void *ptr = *((void **) item);
+       int i;
+
+       if (!ptr)
+               return;
+
+       *((void **)item) = NULL;
+       for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
+               if (a->ptr != ptr)
+                       continue;
+
+               if (i != sd->allocmap_len - 1)
+                       a->ptr = sd->allocmap[sd->allocmap_len - 1].ptr;
+
+               sd->allocmap_len--;
+               return;
+       }
+
+       for (i = 0, ac = sd->alloc_custom; i < sd->alloc_custom_len; i++, ac++) {
+               if (ac->ptr != ptr)
+                       continue;
+
+               if (i != sd->alloc_custom_len - 1)
+                       memcpy(ac, &sd->alloc_custom[sd->alloc_custom_len - 1],
+                               sizeof(struct uci_alloc_custom));
+
+               ac->om->free(ac->section, ac->om, ac->ptr);
+               sd->alloc_custom_len--;
+               return;
+       }
+}
+
+int
+ucimap_resize_list(struct ucimap_section_data *sd, struct ucimap_list **list, int items)
+{
+       struct ucimap_list *new;
+       struct uci_alloc *a;
+       int i, offset = 0;
+       int size = sizeof(struct ucimap_list) + items * sizeof(union ucimap_data);
+
+       if (!*list) {
+               new = calloc(1, size);
+
+               ucimap_add_alloc(sd, new);
+               goto set;
+       }
+
+       for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
+               if (a->ptr != *list)
+                       continue;
+
+               goto realloc;
+       }
+       return -ENOENT;
+
+realloc:
+       if (items > (*list)->size)
+               offset = (items - (*list)->size) * sizeof(union ucimap_data);
+
+       a->ptr = realloc(a->ptr, size);
+       if (offset)
+               memset((char *) a->ptr + offset, 0, size - offset);
+       new = a->ptr;
+
+set:
+       new->size = items;
+       *list = new;
+       return 0;
+}
+
 static void
 ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct uci_optmap *om, const char *str)
 {
@@ -269,8 +330,15 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_s
        char *s;
        int val;
 
-       if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type))
+       if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) {
+               if (unlikely(data->list->size <= data->list->n_items)) {
+                       /* should not happen */
+                       DPRINTF("ERROR: overflow while filling a list\n");
+                       return;
+               }
+
                data = &data->list->item[data->list->n_items++];
+       }
 
        switch(om->type & UCIMAP_SUBTYPE) {
        case UCIMAP_STRING:
@@ -558,7 +626,12 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim
                        n_alloc_custom += n_elements_custom;
                        size = sizeof(struct ucimap_list) +
                                n_elements * sizeof(union ucimap_data);
+
                        data->list = malloc(size);
+                       if (!data->list)
+                               goto error_mem;
+
+                       data->list->size = n_elements;
                        memset(data->list, 0, size);
                } else {
                        ucimap_count_alloc(om, &n_alloc, &n_alloc_custom);
@@ -719,6 +792,9 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_s
 
                        if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
                                continue;
+
+                       if (!str)
+                               str = "";
                }
                if (!str)
                        continue;
index d0e8ce9..21aa83e 100644 (file)
--- a/ucimap.h
+++ b/ucimap.h
@@ -164,12 +164,6 @@ struct ucimap_section_data {
        bool done;
 };
 
-
-struct uci_listmap {
-       struct list_head list;
-       union ucimap_data data;
-};
-
 struct uci_sectionmap {
        /* type string for the uci section */
        const char *type;
@@ -228,6 +222,7 @@ struct uci_optmap {
 
 struct ucimap_list {
        int n_items;
+       int size;
        union ucimap_data item[];
 };
 
@@ -238,5 +233,7 @@ extern int ucimap_store_section(struct uci_map *map, struct uci_package *p, stru
 extern void ucimap_parse(struct uci_map *map, struct uci_package *pkg);
 extern int ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s);
 extern void ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd);
+extern int ucimap_resize_list(struct ucimap_section_data *sd, struct ucimap_list **list, int items);
+extern void ucimap_free_item(struct ucimap_section_data *sd, void *item);
 
 #endif