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.
23 enum ucimap_type type;
30 struct list_head list;
31 struct uci_sectionmap *sm;
33 enum ucimap_type type;
34 union ucimap_data *data;
37 #define ucimap_foreach_option(_sm, _o) \
38 if (!(_sm)->options_size) \
39 (_sm)->options_size = sizeof(struct uci_optmap); \
40 for (_o = &(_sm)->options[0]; \
41 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
42 (_sm)->options_size * (_sm)->n_options); \
43 _o = (struct uci_optmap *) ((char *)(_o) + \
48 ucimap_is_alloc(enum ucimap_type type)
50 switch(type & UCIMAP_SUBTYPE) {
59 ucimap_is_fixup(enum ucimap_type type)
61 switch(type & UCIMAP_SUBTYPE) {
70 ucimap_is_simple(enum ucimap_type type)
72 return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE);
76 ucimap_is_list(enum ucimap_type type)
78 return ((type & UCIMAP_TYPE) == UCIMAP_LIST);
82 ucimap_is_custom(enum ucimap_type type)
84 return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
88 ucimap_section_ptr(struct ucimap_section_data *sd)
90 return ((char *) sd - sd->sm->smap_offset);
93 static inline union ucimap_data *
94 ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om)
98 data = (char *) ucimap_section_ptr(sd) + om->offset;
103 ucimap_init(struct uci_map *map)
105 INIT_LIST_HEAD(&map->sdata);
106 INIT_LIST_HEAD(&map->fixup);
111 ucimap_free_item(struct uci_alloc *a)
113 switch(a->type & UCIMAP_TYPE) {
122 ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr)
124 struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
125 a->type = UCIMAP_SIMPLE;
130 ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
135 section = ucimap_section_ptr(sd);
136 if (!list_empty(&sd->list))
140 sd->sm->free(map, section);
142 for (i = 0; i < sd->allocmap_len; i++) {
143 ucimap_free_item(&sd->allocmap[i]);
151 ucimap_cleanup(struct uci_map *map)
153 struct list_head *ptr, *tmp;
155 list_for_each_safe(ptr, tmp, &map->sdata) {
156 struct ucimap_section_data *sd = list_entry(ptr, struct ucimap_section_data, list);
157 ucimap_free_section(map, sd);
162 ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str)
166 f = malloc(sizeof(struct uci_fixup));
170 INIT_LIST_HEAD(&f->list);
175 list_add(&f->list, &map->fixup);
179 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
181 union ucimap_data tdata = *data;
187 if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type))
188 data = &data->list->item[data->list->n_items++];
190 switch(om->type & UCIMAP_SUBTYPE) {
192 if ((om->data.s.maxlen > 0) &&
193 (strlen(str) > om->data.s.maxlen))
198 ucimap_add_alloc(sd, s);
201 if (!strcmp(str, "on"))
203 else if (!strcmp(str, "1"))
205 else if (!strcmp(str, "enabled"))
207 else if (!strcmp(str, "off"))
209 else if (!strcmp(str, "0"))
211 else if (!strcmp(str, "disabled"))
219 lval = strtol(str, &eptr, om->data.i.base);
220 if (lval < INT_MIN || lval > INT_MAX)
223 if (!eptr || *eptr == '\0')
224 tdata.i = (int) lval;
229 ucimap_add_fixup(sd->map, data, om, str);
232 tdata.s = (char *) data;
236 if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
239 if (ucimap_is_custom(om->type))
241 memcpy(data, &tdata, sizeof(union ucimap_data));
246 ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
248 struct uci_element *e, *l;
249 struct uci_option *o;
250 union ucimap_data *data;
252 uci_foreach_element(&s->options, e) {
253 struct uci_optmap *om = NULL, *tmp;
255 ucimap_foreach_option(sm, tmp) {
256 if (strcmp(e->name, tmp->name) == 0) {
264 data = ucimap_get_data(sd, om);
265 o = uci_to_option(e);
266 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
267 ucimap_add_value(data, om, sd, o->v.string);
268 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
269 uci_foreach_element(&o->v.list, l) {
270 ucimap_add_value(data, om, sd, l->name);
280 ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct uci_section *s)
282 struct ucimap_section_data *sd = NULL;
283 struct uci_optmap *om;
290 sd = sm->alloc(map, sm, s);
291 memset(sd, 0, sizeof(struct ucimap_section_data));
293 sd = malloc(sm->alloc_len);
294 memset(sd, 0, sm->alloc_len);
300 INIT_LIST_HEAD(&sd->list);
304 ucimap_foreach_option(sm, om) {
305 if (ucimap_is_list(om->type)) {
306 union ucimap_data *data;
307 struct uci_element *e;
311 data = ucimap_get_data(sd, om);
312 uci_foreach_element(&s->options, e) {
313 struct uci_option *o = uci_to_option(e);
314 struct uci_element *tmp;
316 if (strcmp(e->name, om->name) != 0)
319 uci_foreach_element(&o->v.list, tmp) {
324 n_alloc += n_elements + 1;
325 size = sizeof(struct ucimap_list) +
326 n_elements * sizeof(union ucimap_data);
327 data->list = malloc(size);
328 memset(data->list, 0, size);
329 } else if (ucimap_is_alloc(om->type)) {
334 sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc));
338 section_name = strdup(s->e.name);
342 sd->section_name = section_name;
344 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
348 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
349 ucimap_add_alloc(sd, (void *)section_name);
350 ucimap_add_alloc(sd, (void *)sd->cmap);
351 ucimap_foreach_option(sm, om) {
352 if (!ucimap_is_list(om->type))
355 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
358 section = ucimap_section_ptr(sd);
359 err = sm->init(map, section, s);
363 list_add(&sd->list, &map->sdata);
364 err = ucimap_parse_options(map, sm, sd, s);
377 ucimap_free_section(map, sd);
382 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
384 struct uci_package *p = s->package;
386 memset(ptr, 0, sizeof(struct uci_ptr));
388 ptr->package = p->e.name;
391 ptr->section = s->e.name;
394 ptr->option = option;
395 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
399 ucimap_set_changed(struct ucimap_section_data *sd, void *field)
401 void *section = ucimap_section_ptr(sd);
402 struct uci_sectionmap *sm = sd->sm;
403 struct uci_optmap *om;
404 int ofs = (char *)field - (char *)section;
407 ucimap_foreach_option(sm, om) {
408 if (om->offset == ofs) {
409 SET_BIT(sd->cmap, i);
417 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
419 struct uci_sectionmap *sm = sd->sm;
420 struct uci_section *s = NULL;
421 struct uci_optmap *om;
422 struct uci_element *e;
427 uci_foreach_element(&p->sections, e) {
428 if (!strcmp(e->name, sd->section_name)) {
429 s = uci_to_section(e);
434 return UCI_ERR_NOTFOUND;
436 ucimap_foreach_option(sm, om) {
437 union ucimap_data *data;
442 if (ucimap_is_list(om->type))
445 data = ucimap_get_data(sd, om);
446 if (!TEST_BIT(sd->cmap, i - 1))
449 ucimap_fill_ptr(&ptr, s, om->name);
450 switch(om->type & UCIMAP_SUBTYPE) {
455 sprintf(buf, "%d", data->i);
459 sprintf(buf, "%d", !!data->b);
468 union ucimap_data tdata, *data;
470 data = ucimap_get_data(sd, om);
471 if (ucimap_is_custom(om->type)) {
472 tdata.s = (char *)data;
476 if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
483 ret = uci_set(s->package->ctx, &ptr);
487 CLR_BIT(sd->cmap, i - 1);
494 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
496 struct ucimap_section_data *sd;
499 list_for_each(p, &map->sdata) {
500 sd = list_entry(p, struct ucimap_section_data, list);
503 if (strcmp(f->name, sd->section_name) != 0)
505 return ucimap_section_ptr(sd);
511 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
513 struct uci_element *e;
514 struct list_head *p, *tmp;
517 INIT_LIST_HEAD(&map->fixup);
518 uci_foreach_element(&pkg->sections, e) {
519 struct uci_section *s = uci_to_section(e);
521 for (i = 0; i < map->n_sections; i++) {
522 if (strcmp(s->type, map->sections[i]->type) != 0)
524 ucimap_parse_section(map, map->sections[i], s);
527 list_for_each_safe(p, tmp, &map->fixup) {
528 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
529 void *ptr = ucimap_find_section(map, f);
530 struct ucimap_list *list;
535 switch(f->type & UCIMAP_TYPE) {
537 f->data->section = ptr;
540 list = f->data->list;
541 list->item[list->n_items++].section = ptr;
546 list_for_each_safe(p, tmp, &map->sdata) {
547 struct ucimap_section_data *sd = list_entry(p, struct ucimap_section_data, list);
553 section = ucimap_section_ptr(sd);
554 if (sd->sm->add(map, section) != 0)
555 ucimap_free_section(map, sd);