X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=ucimap.c;h=7637bd5572d2fd22f2c1127dc80bd21c3cd98f29;hp=191c97c4b9153df2ab589c8fcaf68bcbecbb3021;hb=2a8229347cfc804196648cf601a2a275f5d89ade;hpb=75c9a5d0faf426863f52094fcc77d11e39786581 diff --git a/ucimap.c b/ucimap.c index 191c97c..7637bd5 100644 --- a/ucimap.c +++ b/ucimap.c @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include "ucimap.h" struct uci_alloc { @@ -27,28 +29,12 @@ struct uci_alloc { struct uci_fixup { struct list_head list; - struct uci_sectmap *sm; + struct uci_sectionmap *sm; const char *name; enum ucimap_type type; union ucimap_data *data; }; -struct uci_sectmap_data { - struct list_head list; - struct uci_map *map; - struct uci_sectmap *sm; - const char *section_name; - - /* list of allocations done by ucimap */ - struct uci_alloc *allocmap; - unsigned long allocmap_len; - - /* map for changed fields */ - unsigned char *cmap; - bool done; -}; - - #define ucimap_foreach_option(_sm, _o) \ if (!(_sm)->options_size) \ (_sm)->options_size = sizeof(struct uci_optmap); \ @@ -93,12 +79,30 @@ ucimap_is_list(enum ucimap_type type) return ((type & UCIMAP_TYPE) == UCIMAP_LIST); } +static inline bool +ucimap_is_list_auto(enum ucimap_type type) +{ + return ucimap_is_list(type) && !!(type & UCIMAP_LIST_AUTO); +} + +static inline bool +ucimap_is_custom(enum ucimap_type type) +{ + return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM); +} + +static inline void * +ucimap_section_ptr(struct ucimap_section_data *sd) +{ + return ((char *) sd - sd->sm->smap_offset); +} + static inline union ucimap_data * -ucimap_get_data(struct uci_sectmap_data *sd, struct uci_optmap *om) +ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om) { void *data; - data = (char *) sd + sizeof(struct uci_sectmap_data) + om->offset; + data = (char *) ucimap_section_ptr(sd) + om->offset; return data; } @@ -122,7 +126,7 @@ ucimap_free_item(struct uci_alloc *a) } static void -ucimap_add_alloc(struct uci_sectmap_data *sd, void *ptr) +ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr) { struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++]; a->type = UCIMAP_SIMPLE; @@ -130,12 +134,12 @@ ucimap_add_alloc(struct uci_sectmap_data *sd, void *ptr) } static void -ucimap_free_section(struct uci_map *map, struct uci_sectmap_data *sd) +ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd) { - void *section = sd; + void *section; int i; - section = (char *) section + sizeof(struct uci_sectmap_data); + section = ucimap_section_ptr(sd); if (!list_empty(&sd->list)) list_del(&sd->list); @@ -156,38 +160,81 @@ ucimap_cleanup(struct uci_map *map) struct list_head *ptr, *tmp; list_for_each_safe(ptr, tmp, &map->sdata) { - struct uci_sectmap_data *sd = list_entry(ptr, struct uci_sectmap_data, list); + struct ucimap_section_data *sd = list_entry(ptr, struct ucimap_section_data, list); ucimap_free_section(map, sd); } } +static void * +ucimap_find_section(struct uci_map *map, struct uci_fixup *f) +{ + struct ucimap_section_data *sd; + struct list_head *p; + + list_for_each(p, &map->sdata) { + sd = list_entry(p, struct ucimap_section_data, list); + if (sd->sm != f->sm) + continue; + if (strcmp(f->name, sd->section_name) != 0) + continue; + return ucimap_section_ptr(sd); + } + return NULL; +} + +static bool +ucimap_handle_fixup(struct uci_map *map, struct uci_fixup *f) +{ + void *ptr = ucimap_find_section(map, f); + struct ucimap_list *list; + + if (!ptr) + return false; + + switch(f->type & UCIMAP_TYPE) { + case UCIMAP_SIMPLE: + f->data->section = ptr; + break; + case UCIMAP_LIST: + list = f->data->list; + list->item[list->n_items++].section = ptr; + break; + } + return true; +} + static void ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str) { - struct uci_fixup *f; + struct uci_fixup *f, tmp; + + INIT_LIST_HEAD(&tmp.list); + tmp.sm = om->data.sm; + tmp.name = str; + tmp.type = om->type; + tmp.data = data; + if (ucimap_handle_fixup(map, &tmp)) + return; f = malloc(sizeof(struct uci_fixup)); if (!f) return; - INIT_LIST_HEAD(&f->list); - f->sm = om->data.sm; - f->name = str; - f->type = om->type; - f->data = data; - list_add(&f->list, &map->fixup); + memcpy(f, &tmp, sizeof(tmp)); + list_add_tail(&f->list, &map->fixup); } static void -ucimap_add_value(union ucimap_data *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 ucimap_section_data *sd, const char *str) { - union ucimap_data *tdata = data; + union ucimap_data tdata = *data; char *eptr = NULL; + long lval; char *s; int val; if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) - tdata = &data->list->item[data->list->n_items++]; + data = &data->list->item[data->list->n_items++]; switch(om->type & UCIMAP_SUBTYPE) { case UCIMAP_STRING: @@ -196,44 +243,87 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sect return; s = strdup(str); - tdata->s = s; + tdata.s = s; ucimap_add_alloc(sd, s); break; case UCIMAP_BOOL: - val = -1; - if (strcmp(str, "on")) + if (!strcmp(str, "on")) val = true; - else if (strcmp(str, "1")) + else if (!strcmp(str, "1")) val = true; - else if (strcmp(str, "enabled")) + else if (!strcmp(str, "enabled")) val = true; - else if (strcmp(str, "off")) + else if (!strcmp(str, "off")) val = false; - else if (strcmp(str, "0")) + else if (!strcmp(str, "0")) val = false; - else if (strcmp(str, "disabled")) + else if (!strcmp(str, "disabled")) val = false; - if (val == -1) + else return; - tdata->b = val; + tdata.b = val; break; case UCIMAP_INT: - val = strtol(str, &eptr, om->data.i.base); + lval = strtol(str, &eptr, om->data.i.base); + if (lval < INT_MIN || lval > INT_MAX) + return; + if (!eptr || *eptr == '\0') - tdata->i = val; + tdata.i = (int) lval; else return; break; case UCIMAP_SECTION: ucimap_add_fixup(sd->map, data, om, str); + return; + case UCIMAP_CUSTOM: + tdata.s = (char *) data; break; } + if (om->parse) { + if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0) + return; + } + if (ucimap_is_custom(om->type)) + return; + memcpy(data, &tdata, sizeof(union ucimap_data)); } +static void +ucimap_convert_list(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str) +{ + char *s, *p; + + s = strdup(str); + if (!s) + return; + + ucimap_add_alloc(sd, s); + + do { + while (isspace(*s)) + s++; + + if (!*s) + break; + + p = s; + while (*s && !isspace(*s)) + s++; + + if (isspace(*s)) { + *s = 0; + s++; + } + + ucimap_add_value(data, om, sd, p); + } while (*s); +} + static int -ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sectmap_data *sd, struct uci_section *s) +ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s) { struct uci_element *e, *l; struct uci_option *o; @@ -259,6 +349,8 @@ ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec uci_foreach_element(&o->v.list, l) { ucimap_add_value(data, om, sd, l->name); } + } else if ((o->type == UCI_TYPE_STRING) && ucimap_is_list_auto(om->type)) { + ucimap_convert_list(data, om, sd, o->v.string); } } @@ -266,22 +358,18 @@ ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec } -static int -ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_section *s) +int +ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s) { - struct uci_sectmap_data *sd = 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)); - if (!sd) - return UCI_ERR_MEM; - - memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data)); INIT_LIST_HEAD(&sd->list); + sd->map = map; + sd->sm = sm; ucimap_foreach_option(sm, om) { if (ucimap_is_list(om->type)) { @@ -298,11 +386,33 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec if (strcmp(e->name, om->name) != 0) continue; - uci_foreach_element(&o->v.list, tmp) { - n_elements++; + if (o->type == UCI_TYPE_LIST) { + uci_foreach_element(&o->v.list, tmp) { + n_elements++; + } + } else if ((o->type == UCI_TYPE_STRING) && + ucimap_is_list_auto(om->type)) { + const char *data = o->v.string; + do { + while (isspace(*data)) + data++; + + if (!*data) + break; + + n_elements++; + + while (*data && !isspace(*data)) + data++; + } while (*data); + + /* for the duplicated data string */ + if (n_elements > 0) + n_alloc++; } break; } + /* add one more for the ucimap_list */ n_alloc += n_elements + 1; size = sizeof(struct ucimap_list) + n_elements * sizeof(union ucimap_data); @@ -313,8 +423,6 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec } } - sd->map = map; - sd->sm = sm; sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc)); if (!sd->allocmap) goto error_mem; @@ -339,8 +447,7 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_sec ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list); } - section = (char *)sd + sizeof(struct uci_sectmap_data); - + section = ucimap_section_ptr(sd); err = sm->init(map, section, s); if (err) goto error; @@ -381,11 +488,10 @@ ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option) } void -ucimap_set_changed(void *section, void *field) +ucimap_set_changed(struct ucimap_section_data *sd, 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; + void *section = ucimap_section_ptr(sd); + struct uci_sectionmap *sm = sd->sm; struct uci_optmap *om; int ofs = (char *)field - (char *)section; int i = 0; @@ -400,11 +506,9 @@ ucimap_set_changed(void *section, void *field) } int -ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) +ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd) { - 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_sectionmap *sm = sd->sm; struct uci_section *s = NULL; struct uci_optmap *om; struct uci_element *e; @@ -424,13 +528,14 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) ucimap_foreach_option(sm, om) { union ucimap_data *data; static char buf[32]; - const char *str = NULL; + char *str = NULL; + i++; if (ucimap_is_list(om->type)) continue; data = ucimap_get_data(sd, om); - if (!TEST_BIT(sd->cmap, i)) + if (!TEST_BIT(sd->cmap, i - 1)) continue; ucimap_fill_ptr(&ptr, s, om->name); @@ -446,41 +551,37 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section) sprintf(buf, "%d", !!data->b); str = buf; break; + case UCIMAP_CUSTOM: + break; default: continue; } + if (om->format) { + union ucimap_data tdata, *data; + + data = ucimap_get_data(sd, om); + if (ucimap_is_custom(om->type)) { + tdata.s = (char *)data; + data = &tdata; + } + + if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0) + continue; + } + if (!str) + continue; ptr.value = str; ret = uci_set(s->package->ctx, &ptr); if (ret) return ret; - CLR_BIT(sd->cmap, i); - i++; + CLR_BIT(sd->cmap, i - 1); } return 0; } -void * -ucimap_find_section(struct uci_map *map, struct uci_fixup *f) -{ - struct uci_sectmap_data *sd; - struct list_head *p; - void *ret; - - list_for_each(p, &map->sdata) { - sd = list_entry(p, struct uci_sectmap_data, list); - if (sd->sm != f->sm) - continue; - if (strcmp(f->name, sd->section_name) != 0) - continue; - ret = (char *)sd + sizeof(struct uci_sectmap_data); - return ret; - } - return NULL; -} - void ucimap_parse(struct uci_map *map, struct uci_package *pkg) { @@ -493,38 +594,39 @@ ucimap_parse(struct uci_map *map, struct uci_package *pkg) struct uci_section *s = uci_to_section(e); for (i = 0; i < map->n_sections; i++) { + struct uci_sectionmap *sm = map->sections[i]; + struct ucimap_section_data *sd; + if (strcmp(s->type, map->sections[i]->type) != 0) continue; - ucimap_parse_section(map, map->sections[i], s); + + if (sm->alloc) { + sd = sm->alloc(map, sm, s); + memset(sd, 0, sizeof(struct ucimap_section_data)); + } else { + sd = malloc(sm->alloc_len); + memset(sd, 0, sm->alloc_len); + } + if (!sd) + continue; + + ucimap_parse_section(map, sm, sd, s); } } 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 ucimap_list *list; - - if (!ptr) - continue; - - switch(f->type & UCIMAP_TYPE) { - case UCIMAP_SIMPLE: - f->data->section = ptr; - break; - case UCIMAP_LIST: - list = f->data->list; - list->item[list->n_items++].section = ptr; - break; - } + ucimap_handle_fixup(map, f); + list_del(&f->list); free(f); } list_for_each_safe(p, tmp, &map->sdata) { - struct uci_sectmap_data *sd = list_entry(p, struct uci_sectmap_data, list); + struct ucimap_section_data *sd = list_entry(p, struct ucimap_section_data, list); void *section; if (sd->done) continue; - section = (char *) sd + sizeof(struct uci_sectmap_data); + section = ucimap_section_ptr(sd); if (sd->sm->add(map, section) != 0) ucimap_free_section(map, sd); }