From 25b34febb4851f605f35b45df6eaebc45b122a12 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 5 Sep 2009 00:39:41 +0200 Subject: [PATCH 1/1] ucimap: add helper function for resizing lists and freeing items (both using ucimap internal allocation list), add test coverage for config change operations --- test/config/network | 2 - ...imap_example.result => ucimap_example_1.result} | 3 +- test/references/ucimap_example_2.result | 15 +++ test/tests.d/060-ucimap_example | 8 +- ucimap-example.c | 43 ++++++-- ucimap.c | 114 +++++++++++++++++---- ucimap.h | 9 +- 7 files changed, 153 insertions(+), 41 deletions(-) rename test/references/{ucimap_example.result => ucimap_example_1.result} (89%) create mode 100644 test/references/ucimap_example_2.result diff --git a/test/config/network b/test/config/network index 6e2b5cc..426e345 100644 --- a/test/config/network +++ b/test/config/network @@ -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_1.result similarity index 89% rename from test/references/ucimap_example.result rename to test/references/ucimap_example_1.result index 4a20965..9f73ad6 100644 --- a/test/references/ucimap_example.result +++ b/test/references/ucimap_example_1.result @@ -12,5 +12,4 @@ New network section 'wan' ipaddr: 0.0.0.0 test: -1 enabled: on -New alias: c -New alias: d +Configured aliases: c d diff --git a/test/references/ucimap_example_2.result b/test/references/ucimap_example_2.result new file mode 100644 index 0000000..d333b5b --- /dev/null +++ b/test/references/ucimap_example_2.result @@ -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 diff --git a/test/tests.d/060-ucimap_example b/test/tests.d/060-ucimap_example index c517637..984726b 100644 --- a/test/tests.d/060-ucimap_example +++ b/test/tests.d/060-ucimap_example @@ -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 } diff --git a/ucimap-example.c b/ucimap-example.c index c59e72c..1fd9530 100644 --- a/ucimap-example.c +++ b/ucimap-example.c @@ -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 } diff --git a/ucimap.c b/ucimap.c index 9aafe0b..0d16bb4 100644 --- a/ucimap.c +++ b/ucimap.c @@ -19,14 +19,12 @@ #include #include #include +#include #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; diff --git a/ucimap.h b/ucimap.h index d0e8ce9..21aa83e 100644 --- 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 -- 2.11.0