From: Felix Fietkau Date: Sat, 29 Aug 2009 16:34:49 +0000 (+0200) Subject: ucimap: clean up list handling, use arrays instead of linked lists X-Git-Url: http://pilppa.com/gitweb/?a=commitdiff_plain;h=7af0c0eda078866cc0e61e2f437273809ed27596;p=uci.git ucimap: clean up list handling, use arrays instead of linked lists --- diff --git a/ucimap-example.c b/ucimap-example.c index 517a8a2..6a91f0a 100644 --- a/ucimap-example.c +++ b/ucimap-example.c @@ -29,7 +29,7 @@ struct uci_network { const char *ipaddr; int test; bool enabled; - struct list_head aliases; + struct ucimap_list *aliases; }; struct uci_alias { @@ -134,6 +134,7 @@ int main(int argc, char **argv) struct list_head *p, *p2; struct uci_network *net; struct uci_alias *alias; + int i; INIT_LIST_HEAD(&ifs); ctx = uci_alloc_context(); @@ -158,9 +159,8 @@ int main(int argc, char **argv) net->test, (net->enabled ? "on" : "off")); - list_for_each(p2, &net->aliases) { - struct uci_listmap *li = list_entry(p2, struct uci_listmap, list); - alias = li->data.section; + for (i = 0; i < net->aliases->n_items; i++) { + alias = net->aliases->item[i].section; printf("New alias: %s\n", alias->name); } #if 0 diff --git a/ucimap.c b/ucimap.c index e51cd2b..c347b24 100644 --- a/ucimap.c +++ b/ucimap.c @@ -12,6 +12,7 @@ * GNU General Public License for more details. */ #include +#include #include #include #include @@ -21,7 +22,6 @@ struct uci_alloc { enum ucimap_type type; union { void **ptr; - struct list_head *list; } data; }; @@ -29,7 +29,8 @@ struct uci_fixup { struct list_head list; struct uci_sectmap *sm; const char *name; - struct uci_alloc target; + enum ucimap_type type; + union ucimap_data *data; }; struct uci_sectmap_data { @@ -48,6 +49,59 @@ struct uci_sectmap_data { }; +#define ucimap_foreach_option(_sm, _o) \ + if (!(_sm)->options_size) \ + (_sm)->options_size = sizeof(struct uci_optmap); \ + for (_o = &(_sm)->options[0]; \ + ((char *)(_o)) < ((char *) &(_sm)->options[0] + \ + (_sm)->options_size * (_sm)->n_options); \ + _o = (struct uci_optmap *) ((char *)(_o) + \ + (_sm)->options_size)) + + +static inline bool +ucimap_is_alloc(enum ucimap_type type) +{ + switch(type & UCIMAP_SUBTYPE) { + case UCIMAP_STRING: + return true; + default: + return false; + } +} + +static inline bool +ucimap_is_fixup(enum ucimap_type type) +{ + switch(type & UCIMAP_SUBTYPE) { + case UCIMAP_SECTION: + return true; + default: + return false; + } +} + +static inline bool +ucimap_is_simple(enum ucimap_type type) +{ + return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE); +} + +static inline bool +ucimap_is_list(enum ucimap_type type) +{ + return ((type & UCIMAP_TYPE) == UCIMAP_LIST); +} + +static inline union ucimap_data * +ucimap_get_data(struct uci_sectmap_data *sd, struct uci_optmap *om) +{ + void *data; + + data = (char *) sd + sizeof(struct uci_sectmap_data) + om->offset; + return data; +} + int ucimap_init(struct uci_map *map) { @@ -59,24 +113,18 @@ ucimap_init(struct uci_map *map) static void ucimap_free_item(struct uci_alloc *a) { - struct list_head *p, *tmp; switch(a->type & UCIMAP_TYPE) { case UCIMAP_SIMPLE: - free(a->data.ptr); - break; case UCIMAP_LIST: - list_for_each_safe(p, tmp, a->data.list) { - struct uci_listmap *l = list_entry(p, struct uci_listmap, list); - list_del(p); - free(l); - } + free(a->data.ptr); break; } } -static inline void -ucimap_add_alloc(struct uci_alloc *a, void *ptr) +static void +ucimap_add_alloc(struct uci_sectmap_data *sd, void *ptr) { + struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++]; a->type = UCIMAP_SIMPLE; a->data.ptr = ptr; } @@ -114,7 +162,7 @@ ucimap_cleanup(struct uci_map *map) } static void -ucimap_add_fixup(struct uci_map *map, void *data, struct uci_optmap *om, const char *str) +ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str) { struct uci_fixup *f; @@ -125,29 +173,21 @@ ucimap_add_fixup(struct uci_map *map, void *data, struct uci_optmap *om, const c INIT_LIST_HEAD(&f->list); f->sm = om->data.sm; f->name = str; - f->target.type = om->type; - f->target.data.ptr = data; + f->type = om->type; + f->data = data; list_add(&f->list, &map->fixup); } static void -ucimap_add_value(union uci_datamap *data, struct uci_optmap *om, struct uci_sectmap_data *sd, const char *str) +ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sectmap_data *sd, const char *str) { - union uci_datamap tdata; - struct list_head *list = NULL; + union ucimap_data *tdata = data; char *eptr = NULL; char *s; int val; - if ((om->type & UCIMAP_TYPE) == UCIMAP_LIST) { - if ((om->type & UCIMAP_SUBTYPE) == UCIMAP_SECTION) { - ucimap_add_fixup(sd->map, data, om, str); - return; - } - memset(&tdata, 0, sizeof(tdata)); - list = &data->list; - data = &tdata; - } + if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) + tdata = &data->list->item[data->list->n_items++]; switch(om->type & UCIMAP_SUBTYPE) { case UCIMAP_STRING: @@ -156,8 +196,8 @@ ucimap_add_value(union uci_datamap *data, struct uci_optmap *om, struct uci_sect return; s = strdup(str); - data->s = s; - ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], s); + tdata->s = s; + ucimap_add_alloc(sd, s); break; case UCIMAP_BOOL: val = -1; @@ -176,12 +216,12 @@ ucimap_add_value(union uci_datamap *data, struct uci_optmap *om, struct uci_sect if (val == -1) return; - data->b = val; + tdata->b = val; break; case UCIMAP_INT: val = strtol(str, &eptr, om->data.i.base); if (!eptr || *eptr == '\0') - data->i = val; + tdata->i = val; else return; break; @@ -189,18 +229,6 @@ ucimap_add_value(union uci_datamap *data, struct uci_optmap *om, struct uci_sect ucimap_add_fixup(sd->map, data, om, str); break; } - - if ((om->type & UCIMAP_TYPE) == UCIMAP_LIST) { - struct uci_listmap *item; - - item = malloc(sizeof(struct uci_listmap)); - if (!item) - return; - - INIT_LIST_HEAD(&item->list); - memcpy(&item->data, &tdata, sizeof(tdata)); - list_add(&item->list, list); - } } @@ -209,48 +237,28 @@ ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec { struct uci_element *e, *l; struct uci_option *o; - unsigned long section; - union uci_datamap *data; - int i; + union ucimap_data *data; - section = (unsigned long) sd + sizeof(struct uci_sectmap_data); uci_foreach_element(&s->options, e) { - struct uci_optmap *om = NULL; - void *ptr = sm->options; - int size = sm->options_size; - - if (!size) - size = sizeof(struct uci_optmap); - - for (i = 0; i < sm->n_options; i++) { - struct uci_optmap *tmp = ptr; + struct uci_optmap *om = NULL, *tmp; + ucimap_foreach_option(sm, tmp) { if (strcmp(e->name, tmp->name) == 0) { - om = ptr; + om = tmp; break; } - ptr = (unsigned char *)ptr + size; } if (!om) continue; - data = (union uci_datamap *) (section + om->offset); + data = ucimap_get_data(sd, om); o = uci_to_option(e); - if ((o->type == UCI_TYPE_STRING) && ((om->type & UCIMAP_TYPE) == UCIMAP_SIMPLE)) { + if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) { ucimap_add_value(data, om, sd, o->v.string); - continue; - } - if ((o->type == UCI_TYPE_LIST) && ((om->type & UCIMAP_TYPE) == UCIMAP_LIST)) { - struct list_head *list; - - list = (struct list_head *) (section + om->offset); - INIT_LIST_HEAD(list); - sd->allocmap[sd->allocmap_len].type = UCIMAP_LIST; - sd->allocmap[sd->allocmap_len++].data.list = list; + } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) { uci_foreach_element(&o->v.list, l) { ucimap_add_value(data, om, sd, l->name); } - continue; } } @@ -262,8 +270,10 @@ static int ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_section *s) { struct uci_sectmap_data *sd = NULL; - void *section = NULL; + struct uci_optmap *om; char *section_name; + void *section; + int n_alloc = 2; int err; sd = malloc(sm->alloc_len + sizeof(struct uci_sectmap_data)); @@ -273,9 +283,39 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data)); INIT_LIST_HEAD(&sd->list); + ucimap_foreach_option(sm, om) { + if (ucimap_is_list(om->type)) { + union ucimap_data *data; + struct uci_element *e; + int n_elements = 0; + int size; + + data = ucimap_get_data(sd, om); + uci_foreach_element(&s->options, e) { + struct uci_option *o = uci_to_option(e); + struct uci_element *tmp; + + if (strcmp(e->name, om->name) != 0) + continue; + + uci_foreach_element(&o->v.list, tmp) { + n_elements++; + } + break; + } + n_alloc += n_elements + 1; + 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++; + } + } + sd->map = map; sd->sm = sm; - sd->allocmap = malloc(sm->n_options * sizeof(struct uci_alloc)); + sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc)); if (!sd->allocmap) goto error_mem; @@ -290,8 +330,14 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec goto error_mem; memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options)); - ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)section_name); - ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)sd->cmap); + ucimap_add_alloc(sd, (void *)section_name); + ucimap_add_alloc(sd, (void *)sd->cmap); + ucimap_foreach_option(sm, om) { + if (!ucimap_is_list(om->type)) + continue; + + ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list); + } section = (char *)sd + sizeof(struct uci_sectmap_data); @@ -340,11 +386,12 @@ ucimap_set_changed(void *section, void *field) char *sptr = (char *)section - sizeof(struct uci_sectmap_data); struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr; struct uci_sectmap *sm = sd->sm; + struct uci_optmap *om; int ofs = (char *)field - (char *)section; int i; - for (i = 0; i < sm->n_options; i++) { - if (sm->options[i].offset == ofs) { + ucimap_foreach_option(sm, om) { + if (om->offset == ofs) { SET_BIT(sd->cmap, i); break; } @@ -358,9 +405,11 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr; struct uci_sectmap *sm = sd->sm; struct uci_section *s = NULL; + struct uci_optmap *om; struct uci_element *e; struct uci_ptr ptr; - int i, ret; + int i = 0; + int ret; uci_foreach_element(&p->sections, e) { if (!strcmp(e->name, sd->section_name)) { @@ -371,26 +420,26 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) if (!s) return UCI_ERR_NOTFOUND; - for (i = 0; i < sm->n_options; i++) { - struct uci_optmap *om = &sm->options[i]; + ucimap_foreach_option(sm, om) { + union ucimap_data *data; static char buf[32]; const char *str = NULL; - void *p = (char *)section + om->offset; + data = ucimap_get_data(sd, om); if (!TEST_BIT(sd->cmap, i)) continue; ucimap_fill_ptr(&ptr, s, om->name); switch(om->type & UCIMAP_SUBTYPE) { case UCIMAP_STRING: - str = *((char **) p); + str = data->s; break; case UCIMAP_INT: - sprintf(buf, "%d", *((int *) p)); + sprintf(buf, "%d", data->i); str = buf; break; case UCIMAP_BOOL: - sprintf(buf, "%d", !!*((bool *)p)); + sprintf(buf, "%d", !!data->b); str = buf; break; } @@ -401,6 +450,7 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) return ret; CLR_BIT(sd->cmap, i); + i++; } return 0; @@ -445,21 +495,18 @@ ucimap_parse(struct uci_map *map, struct uci_package *pkg) list_for_each_safe(p, tmp, &map->fixup) { struct uci_fixup *f = list_entry(p, struct uci_fixup, list); void *ptr = ucimap_find_section(map, f); - struct uci_listmap *li; + struct ucimap_list *list; if (!ptr) continue; - switch(f->target.type & UCIMAP_TYPE) { + switch(f->type & UCIMAP_TYPE) { case UCIMAP_SIMPLE: - *f->target.data.ptr = ptr; + f->data->section = ptr; break; case UCIMAP_LIST: - li = malloc(sizeof(struct uci_listmap)); - memset(li, 0, sizeof(struct uci_listmap)); - INIT_LIST_HEAD(&li->list); - li->data.section = ptr; - list_add(&li->list, f->target.data.list); + list = f->data->list; + list->item[list->n_items++].section = ptr; break; } } diff --git a/ucimap.h b/ucimap.h index 001ae1b..9409500 100644 --- a/ucimap.h +++ b/ucimap.h @@ -42,6 +42,7 @@ struct uci_sectmap; struct uci_optmap; +struct ucimap_list; struct uci_map { struct uci_sectmap **sections; @@ -66,17 +67,17 @@ enum ucimap_type { UCIMAP_SUBTYPE = 0xf, /* subtype mask */ }; -union uci_datamap { +union ucimap_data { int i; bool b; const char *s; void *section; - struct list_head list; + struct ucimap_list *list; }; struct uci_listmap { struct list_head list; - union uci_datamap data; + union ucimap_data data; }; struct uci_sectmap { @@ -118,6 +119,11 @@ struct uci_optmap { } data; }; +struct ucimap_list { + int n_items; + union ucimap_data item[]; +}; + extern int ucimap_init(struct uci_map *map); extern void ucimap_cleanup(struct uci_map *map); extern void ucimap_set_changed(void *section, void *field);