From 6c05c721c77c70f25c46fa20b5d5e4c817e8a651 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 4 Sep 2009 03:59:11 +0200 Subject: [PATCH] ucimap: add custom free() callbacks for options, only used on custom datatypes --- ucimap-example.c | 27 ++++++++++++++++++---- ucimap.c | 60 ++++++++++++++++++++++++++++++++++++++++++------ ucimap.h | 8 ++++++- 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/ucimap-example.c b/ucimap-example.c index bf70eb1..c59e72c 100644 --- a/ucimap-example.c +++ b/ucimap-example.c @@ -27,7 +27,7 @@ struct uci_network { const char *name; const char *proto; const char *ifname; - unsigned char ipaddr[4]; + unsigned char *ipaddr; int test; bool enabled; struct ucimap_list *aliases; @@ -44,13 +44,18 @@ struct uci_alias { static int network_parse_ip(void *section, struct uci_optmap *om, union ucimap_data *data, const char *str) { - unsigned char *target = (unsigned char *) data->s; + unsigned char *target; int tmp[4]; int i; if (sscanf(str, "%d.%d.%d.%d", &tmp[0], &tmp[1], &tmp[2], &tmp[3]) != 4) return -1; + target = malloc(4); + if (!target) + return -1; + + *data->data = target; for (i = 0; i < 4; i++) target[i] = (char) tmp[i]; @@ -61,7 +66,7 @@ static int network_format_ip(void *sction, struct uci_optmap *om, union ucimap_data *data, char **str) { static char buf[16]; - unsigned char *ip = (unsigned char *) data->s; + unsigned char *ip = (unsigned char *) data->data[0]; sprintf(buf, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); *str = buf; @@ -69,6 +74,12 @@ network_format_ip(void *sction, struct uci_optmap *om, union ucimap_data *data, return 0; } +static void +network_free_ip(void *section, struct uci_optmap *om, void *ptr) +{ + free(ptr); +} + static int network_init_interface(struct uci_map *map, void *section, struct uci_section *s) { @@ -151,6 +162,7 @@ static struct my_optmap network_interface_options[] = { .name = "ipaddr", .parse = network_parse_ip, .format = network_format_ip, + .free = network_free_ip, } }, { @@ -234,7 +246,13 @@ int main(int argc, char **argv) ucimap_parse(&network_map, pkg); list_for_each(p, &ifs) { + const unsigned char *ipaddr; + net = list_entry(p, struct uci_network, list); + ipaddr = net->ipaddr; + if (!ipaddr) + ipaddr = (const unsigned char *) "\x00\x00\x00\x00"; + printf("New network section '%s'\n" " type: %s\n" " ifname: %s\n" @@ -244,8 +262,7 @@ int main(int argc, char **argv) net->name, net->proto, net->ifname, - net->ipaddr[0], net->ipaddr[1], - net->ipaddr[2], net->ipaddr[3], + ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3], net->test, (net->enabled ? "on" : "off")); diff --git a/ucimap.c b/ucimap.c index 5751156..6d97b07 100644 --- a/ucimap.c +++ b/ucimap.c @@ -29,6 +29,12 @@ struct uci_alloc { } data; }; +struct uci_alloc_custom { + void *section; + struct uci_optmap *om; + void *ptr; +}; + struct uci_fixup { struct list_head list; struct uci_sectionmap *sm; @@ -153,6 +159,14 @@ ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd) ucimap_free_item(&sd->allocmap[i]); } + if (sd->alloc_custom) { + for (i = 0; i < sd->alloc_custom_len; i++) { + struct uci_alloc_custom *a = &sd->alloc_custom[i]; + a->om->free(a->section, a->om, a->ptr); + } + free(sd->alloc_custom); + } + free(sd->allocmap); free(sd); } @@ -236,6 +250,16 @@ ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct list_add_tail(&f->list, &map->fixup); } +static void +ucimap_add_custom_alloc(struct ucimap_section_data *sd, struct uci_optmap *om, void *ptr) +{ + struct uci_alloc_custom *a = &sd->alloc_custom[sd->alloc_custom_len++]; + + a->section = ucimap_section_ptr(sd); + a->om = om; + a->ptr = ptr; +} + static void ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str) { @@ -296,6 +320,10 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_s if (om->parse) { if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0) return; + if (ucimap_is_custom(om->type) && om->free) { + if (tdata.ptr != data->ptr) + ucimap_add_custom_alloc(sd, om, data->ptr); + } } if (ucimap_is_custom(om->type)) return; @@ -448,6 +476,15 @@ failed: return false; } +static void +ucimap_count_alloc(struct uci_optmap *om, int *n_alloc, int *n_custom) +{ + if (ucimap_is_alloc(om->type)) + (*n_alloc)++; + else if (ucimap_is_custom(om->type) && om->free) + (*n_custom)++; +} + int ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s) { @@ -455,6 +492,7 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim char *section_name; void *section; int n_alloc = 2; + int n_alloc_custom = 0; int err; INIT_LIST_HEAD(&sd->list); @@ -469,6 +507,7 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim union ucimap_data *data; struct uci_element *e; int n_elements = 0; + int n_elements_custom = 0; int size; data = ucimap_get_data(sd, om); @@ -481,7 +520,7 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim if (o->type == UCI_TYPE_LIST) { uci_foreach_element(&o->v.list, tmp) { - n_elements++; + ucimap_count_alloc(om, &n_elements, &n_elements_custom); } } else if ((o->type == UCI_TYPE_STRING) && ucimap_is_list_auto(om->type)) { @@ -494,43 +533,50 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim break; n_elements++; + ucimap_count_alloc(om, &n_elements, &n_elements_custom); while (*data && !isspace(*data)) data++; } while (*data); /* for the duplicated data string */ - if (n_elements > 0) + if (n_elements) n_alloc++; } break; } /* add one more for the ucimap_list */ n_alloc += n_elements + 1; + n_alloc_custom += n_elements_custom; size = sizeof(struct ucimap_list) + n_elements * sizeof(union ucimap_data); data->list = malloc(size); memset(data->list, 0, size); - } else if (ucimap_is_alloc(om->type)) { - n_alloc++; + } else { + ucimap_count_alloc(om, &n_alloc, &n_alloc_custom); } } - sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc)); + sd->allocmap = calloc(n_alloc, sizeof(struct uci_alloc)); if (!sd->allocmap) goto error_mem; + if (n_alloc_custom > 0) { + sd->alloc_custom = calloc(n_alloc_custom, sizeof(struct uci_alloc_custom)); + if (!sd->alloc_custom) + goto error_mem; + } + section_name = strdup(s->e.name); if (!section_name) goto error_mem; sd->section_name = section_name; - sd->cmap = malloc(BITFIELD_SIZE(sm->n_options)); + sd->cmap = calloc(1, BITFIELD_SIZE(sm->n_options)); if (!sd->cmap) goto error_mem; - memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options)); ucimap_add_alloc(sd, (void *)section_name); ucimap_add_alloc(sd, (void *)sd->cmap); ucimap_foreach_option(sm, om) { diff --git a/ucimap.h b/ucimap.h index fd40865..2195e78 100644 --- a/ucimap.h +++ b/ucimap.h @@ -84,6 +84,8 @@ struct uci_sectionmap; struct uci_optmap; struct ucimap_list; +struct uci_alloc; +struct uci_alloc_custom; struct uci_map { struct uci_sectionmap **sections; @@ -121,6 +123,7 @@ union ucimap_data { bool b; char *s; void *ptr; + void **data; struct ucimap_list *list; }; @@ -132,7 +135,9 @@ struct ucimap_section_data { /* list of allocations done by ucimap */ struct uci_alloc *allocmap; - unsigned long allocmap_len; + struct uci_alloc_custom *alloc_custom; + unsigned int allocmap_len; + unsigned int alloc_custom_len; /* map for changed fields */ unsigned char *cmap; @@ -181,6 +186,7 @@ struct uci_optmap { int detected_type; int (*parse)(void *section, struct uci_optmap *om, union ucimap_data *data, const char *string); int (*format)(void *section, struct uci_optmap *om, union ucimap_data *data, char **string); + void (*free)(void *section, struct uci_optmap *om, void *ptr); union { struct { int base; -- 2.41.1