X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=ucimap.c;h=7478b70677a83ac78750687796356035b60aa547;hb=41d24d850ba51f6449f1f8abcf265f180792ee46;hp=7637bd5572d2fd22f2c1127dc80bd21c3cd98f29;hpb=2a8229347cfc804196648cf601a2a275f5d89ade;p=project%2Fuci.git diff --git a/ucimap.c b/ucimap.c index 7637bd5..7478b70 100644 --- a/ucimap.c +++ b/ucimap.c @@ -17,8 +17,10 @@ #include #include #include +#include #include #include "ucimap.h" +#include "uci_internal.h" struct uci_alloc { enum ucimap_type type; @@ -109,6 +111,7 @@ ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om) int ucimap_init(struct uci_map *map) { + INIT_LIST_HEAD(&map->pending); INIT_LIST_HEAD(&map->sdata); INIT_LIST_HEAD(&map->fixup); return 0; @@ -179,6 +182,14 @@ ucimap_find_section(struct uci_map *map, struct uci_fixup *f) continue; return ucimap_section_ptr(sd); } + list_for_each(p, &map->pending) { + 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; } @@ -193,20 +204,21 @@ ucimap_handle_fixup(struct uci_map *map, struct uci_fixup *f) switch(f->type & UCIMAP_TYPE) { case UCIMAP_SIMPLE: - f->data->section = ptr; + f->data->ptr = ptr; break; case UCIMAP_LIST: list = f->data->list; - list->item[list->n_items++].section = ptr; + list->item[list->n_items++].ptr = ptr; break; } return true; } static void -ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str) +ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct uci_optmap *om, const char *str) { struct uci_fixup *f, tmp; + struct uci_map *map = sd->map; INIT_LIST_HEAD(&tmp.list); tmp.sm = om->data.sm; @@ -275,7 +287,7 @@ ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_s return; break; case UCIMAP_SECTION: - ucimap_add_fixup(sd->map, data, om, str); + ucimap_add_fixup(sd, data, om, str); return; case UCIMAP_CUSTOM: tdata.s = (char *) data; @@ -357,6 +369,84 @@ ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucim return 0; } +static void +ucimap_add_section(struct ucimap_section_data *sd) +{ + struct uci_map *map = sd->map; + + if (sd->sm->add(map, ucimap_section_ptr(sd)) < 0) + ucimap_free_section(map, sd); + else + list_add_tail(&sd->list, &map->sdata); +} + +static const char *ucimap_type_names[] = { + [UCIMAP_STRING] = "string", + [UCIMAP_INT] = "integer", + [UCIMAP_BOOL] = "boolean", + [UCIMAP_SECTION] = "section", + [UCIMAP_LIST] = "list", +}; + +static inline const char * +ucimap_get_type_name(int type) +{ + static char buf[32]; + const char *name; + + if (ucimap_is_list(type)) + return ucimap_type_names[UCIMAP_LIST]; + + name = ucimap_type_names[type & UCIMAP_SUBTYPE]; + if (!name) { + sprintf(buf, "Unknown (%d)", type & UCIMAP_SUBTYPE); + name = buf; + } + + return name; +} + +static bool +ucimap_check_optmap_type(struct uci_sectionmap *sm, struct uci_optmap *om) +{ + unsigned int type; + + if (om->detected_type < 0) + return true; + + if (ucimap_is_custom(om->type)) + return true; + + if (ucimap_is_list(om->type) != + ucimap_is_list(om->detected_type)) + goto failed; + + if (ucimap_is_list(om->type)) + return true; + + type = om->type & UCIMAP_SUBTYPE; + switch(type) { + case UCIMAP_STRING: + case UCIMAP_INT: + case UCIMAP_BOOL: + if (type != om->detected_type) + goto failed; + break; + case UCIMAP_SECTION: + goto failed; + default: + break; + } + return true; + +failed: + DPRINTF("Invalid type in option '%s' of section type '%s', " + "declared type is %s, detected type is %s\n", + om->name, sm->type, + ucimap_get_type_name(om->type), + ucimap_get_type_name(om->detected_type)); + return false; +} int ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s) @@ -372,6 +462,9 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim sd->sm = sm; ucimap_foreach_option(sm, om) { + if (!ucimap_check_optmap_type(sm, om)) + continue; + if (ucimap_is_list(om->type)) { union ucimap_data *data; struct uci_element *e; @@ -452,7 +545,12 @@ ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucim if (err) goto error; - list_add(&sd->list, &map->sdata); + if (map->parsed) { + ucimap_add_section(sd); + } else { + list_add_tail(&sd->list, &map->pending); + } + err = ucimap_parse_options(map, sm, sd, s); if (err) goto error; @@ -613,21 +711,20 @@ ucimap_parse(struct uci_map *map, struct uci_package *pkg) ucimap_parse_section(map, sm, sd, s); } } + map->parsed = true; + list_for_each_safe(p, tmp, &map->fixup) { struct uci_fixup *f = list_entry(p, struct uci_fixup, list); ucimap_handle_fixup(map, f); list_del(&f->list); free(f); } - list_for_each_safe(p, tmp, &map->sdata) { - struct ucimap_section_data *sd = list_entry(p, struct ucimap_section_data, list); - void *section; - if (sd->done) - continue; + list_for_each_safe(p, tmp, &map->pending) { + struct ucimap_section_data *sd; + sd = list_entry(p, struct ucimap_section_data, list); - section = ucimap_section_ptr(sd); - if (sd->sm->add(map, section) != 0) - ucimap_free_section(map, sd); + list_del_init(&sd->list); + ucimap_add_section(sd); } }