2 * ucimap - library for mapping uci sections into data structures
3 * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
22 enum ucimap_type type;
29 struct list_head list;
30 struct uci_sectionmap *sm;
32 enum ucimap_type type;
33 union ucimap_data *data;
36 #define ucimap_foreach_option(_sm, _o) \
37 if (!(_sm)->options_size) \
38 (_sm)->options_size = sizeof(struct uci_optmap); \
39 for (_o = &(_sm)->options[0]; \
40 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
41 (_sm)->options_size * (_sm)->n_options); \
42 _o = (struct uci_optmap *) ((char *)(_o) + \
47 ucimap_is_alloc(enum ucimap_type type)
49 switch(type & UCIMAP_SUBTYPE) {
58 ucimap_is_fixup(enum ucimap_type type)
60 switch(type & UCIMAP_SUBTYPE) {
69 ucimap_is_simple(enum ucimap_type type)
71 return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE);
75 ucimap_is_list(enum ucimap_type type)
77 return ((type & UCIMAP_TYPE) == UCIMAP_LIST);
81 ucimap_is_custom(enum ucimap_type type)
83 return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
87 ucimap_section_ptr(struct ucimap_section_data *sd)
89 return ((char *) sd - sd->sm->smap_offset);
92 static inline union ucimap_data *
93 ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om)
97 data = (char *) ucimap_section_ptr(sd) + om->offset;
102 ucimap_init(struct uci_map *map)
104 INIT_LIST_HEAD(&map->sdata);
105 INIT_LIST_HEAD(&map->fixup);
110 ucimap_free_item(struct uci_alloc *a)
112 switch(a->type & UCIMAP_TYPE) {
121 ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr)
123 struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
124 a->type = UCIMAP_SIMPLE;
129 ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
134 section = ucimap_section_ptr(sd);
135 if (!list_empty(&sd->list))
139 sd->sm->free(map, section);
141 for (i = 0; i < sd->allocmap_len; i++) {
142 ucimap_free_item(&sd->allocmap[i]);
150 ucimap_cleanup(struct uci_map *map)
152 struct list_head *ptr, *tmp;
154 list_for_each_safe(ptr, tmp, &map->sdata) {
155 struct ucimap_section_data *sd = list_entry(ptr, struct ucimap_section_data, list);
156 ucimap_free_section(map, sd);
161 ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str)
165 f = malloc(sizeof(struct uci_fixup));
169 INIT_LIST_HEAD(&f->list);
174 list_add(&f->list, &map->fixup);
178 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
180 union ucimap_data tdata = *data;
185 if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type))
186 data = &data->list->item[data->list->n_items++];
188 switch(om->type & UCIMAP_SUBTYPE) {
190 if ((om->data.s.maxlen > 0) &&
191 (strlen(str) > om->data.s.maxlen))
196 ucimap_add_alloc(sd, s);
200 if (strcmp(str, "on"))
202 else if (strcmp(str, "1"))
204 else if (strcmp(str, "enabled"))
206 else if (strcmp(str, "off"))
208 else if (strcmp(str, "0"))
210 else if (strcmp(str, "disabled"))
218 val = strtol(str, &eptr, om->data.i.base);
219 if (!eptr || *eptr == '\0')
225 ucimap_add_fixup(sd->map, data, om, str);
228 tdata.s = (char *) data;
232 if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
235 if (ucimap_is_custom(om->type))
237 memcpy(data, &tdata, sizeof(union ucimap_data));
242 ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
244 struct uci_element *e, *l;
245 struct uci_option *o;
246 union ucimap_data *data;
248 uci_foreach_element(&s->options, e) {
249 struct uci_optmap *om = NULL, *tmp;
251 ucimap_foreach_option(sm, tmp) {
252 if (strcmp(e->name, tmp->name) == 0) {
260 data = ucimap_get_data(sd, om);
261 o = uci_to_option(e);
262 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
263 ucimap_add_value(data, om, sd, o->v.string);
264 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
265 uci_foreach_element(&o->v.list, l) {
266 ucimap_add_value(data, om, sd, l->name);
276 ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct uci_section *s)
278 struct ucimap_section_data *sd = NULL;
279 struct uci_optmap *om;
286 sd = sm->alloc(map, sm, s);
287 memset(sd, 0, sizeof(struct ucimap_section_data));
289 sd = malloc(sm->alloc_len);
290 memset(sd, 0, sm->alloc_len);
296 INIT_LIST_HEAD(&sd->list);
300 ucimap_foreach_option(sm, om) {
301 if (ucimap_is_list(om->type)) {
302 union ucimap_data *data;
303 struct uci_element *e;
307 data = ucimap_get_data(sd, om);
308 uci_foreach_element(&s->options, e) {
309 struct uci_option *o = uci_to_option(e);
310 struct uci_element *tmp;
312 if (strcmp(e->name, om->name) != 0)
315 uci_foreach_element(&o->v.list, tmp) {
320 n_alloc += n_elements + 1;
321 size = sizeof(struct ucimap_list) +
322 n_elements * sizeof(union ucimap_data);
323 data->list = malloc(size);
324 memset(data->list, 0, size);
325 } else if (ucimap_is_alloc(om->type)) {
330 sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc));
334 section_name = strdup(s->e.name);
338 sd->section_name = section_name;
340 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
344 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
345 ucimap_add_alloc(sd, (void *)section_name);
346 ucimap_add_alloc(sd, (void *)sd->cmap);
347 ucimap_foreach_option(sm, om) {
348 if (!ucimap_is_list(om->type))
351 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
354 section = ucimap_section_ptr(sd);
355 err = sm->init(map, section, s);
359 list_add(&sd->list, &map->sdata);
360 err = ucimap_parse_options(map, sm, sd, s);
373 ucimap_free_section(map, sd);
378 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
380 struct uci_package *p = s->package;
382 memset(ptr, 0, sizeof(struct uci_ptr));
384 ptr->package = p->e.name;
387 ptr->section = s->e.name;
390 ptr->option = option;
391 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
395 ucimap_set_changed(struct ucimap_section_data *sd, void *field)
397 void *section = ucimap_section_ptr(sd);
398 struct uci_sectionmap *sm = sd->sm;
399 struct uci_optmap *om;
400 int ofs = (char *)field - (char *)section;
403 ucimap_foreach_option(sm, om) {
404 if (om->offset == ofs) {
405 SET_BIT(sd->cmap, i);
413 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
415 struct uci_sectionmap *sm = sd->sm;
416 struct uci_section *s = NULL;
417 struct uci_optmap *om;
418 struct uci_element *e;
423 uci_foreach_element(&p->sections, e) {
424 if (!strcmp(e->name, sd->section_name)) {
425 s = uci_to_section(e);
430 return UCI_ERR_NOTFOUND;
432 ucimap_foreach_option(sm, om) {
433 union ucimap_data *data;
438 if (ucimap_is_list(om->type))
441 data = ucimap_get_data(sd, om);
442 if (!TEST_BIT(sd->cmap, i - 1))
445 ucimap_fill_ptr(&ptr, s, om->name);
446 switch(om->type & UCIMAP_SUBTYPE) {
451 sprintf(buf, "%d", data->i);
455 sprintf(buf, "%d", !!data->b);
464 union ucimap_data tdata, *data;
466 data = ucimap_get_data(sd, om);
467 if (ucimap_is_custom(om->type)) {
468 tdata.s = (char *)data;
472 if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
479 ret = uci_set(s->package->ctx, &ptr);
483 CLR_BIT(sd->cmap, i - 1);
490 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
492 struct ucimap_section_data *sd;
495 list_for_each(p, &map->sdata) {
496 sd = list_entry(p, struct ucimap_section_data, list);
499 if (strcmp(f->name, sd->section_name) != 0)
501 return ucimap_section_ptr(sd);
507 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
509 struct uci_element *e;
510 struct list_head *p, *tmp;
513 INIT_LIST_HEAD(&map->fixup);
514 uci_foreach_element(&pkg->sections, e) {
515 struct uci_section *s = uci_to_section(e);
517 for (i = 0; i < map->n_sections; i++) {
518 if (strcmp(s->type, map->sections[i]->type) != 0)
520 ucimap_parse_section(map, map->sections[i], s);
523 list_for_each_safe(p, tmp, &map->fixup) {
524 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
525 void *ptr = ucimap_find_section(map, f);
526 struct ucimap_list *list;
531 switch(f->type & UCIMAP_TYPE) {
533 f->data->section = ptr;
536 list = f->data->list;
537 list->item[list->n_items++].section = ptr;
542 list_for_each_safe(p, tmp, &map->sdata) {
543 struct ucimap_section_data *sd = list_entry(p, struct ucimap_section_data, list);
549 section = ucimap_section_ptr(sd);
550 if (sd->sm->add(map, section) != 0)
551 ucimap_free_section(map, sd);