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_sectmap *sm;
32 enum ucimap_type type;
33 union ucimap_data *data;
36 struct uci_sectmap_data {
37 struct list_head list;
39 struct uci_sectmap *sm;
40 const char *section_name;
42 /* list of allocations done by ucimap */
43 struct uci_alloc *allocmap;
44 unsigned long allocmap_len;
46 /* map for changed fields */
52 #define ucimap_foreach_option(_sm, _o) \
53 if (!(_sm)->options_size) \
54 (_sm)->options_size = sizeof(struct uci_optmap); \
55 for (_o = &(_sm)->options[0]; \
56 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
57 (_sm)->options_size * (_sm)->n_options); \
58 _o = (struct uci_optmap *) ((char *)(_o) + \
63 ucimap_is_alloc(enum ucimap_type type)
65 switch(type & UCIMAP_SUBTYPE) {
74 ucimap_is_fixup(enum ucimap_type type)
76 switch(type & UCIMAP_SUBTYPE) {
85 ucimap_is_simple(enum ucimap_type type)
87 return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE);
91 ucimap_is_list(enum ucimap_type type)
93 return ((type & UCIMAP_TYPE) == UCIMAP_LIST);
96 static inline union ucimap_data *
97 ucimap_get_data(struct uci_sectmap_data *sd, struct uci_optmap *om)
101 data = (char *) sd + sizeof(struct uci_sectmap_data) + om->offset;
106 ucimap_init(struct uci_map *map)
108 INIT_LIST_HEAD(&map->sdata);
109 INIT_LIST_HEAD(&map->fixup);
114 ucimap_free_item(struct uci_alloc *a)
116 switch(a->type & UCIMAP_TYPE) {
125 ucimap_add_alloc(struct uci_sectmap_data *sd, void *ptr)
127 struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
128 a->type = UCIMAP_SIMPLE;
133 ucimap_free_section(struct uci_map *map, struct uci_sectmap_data *sd)
138 section = (char *) section + sizeof(struct uci_sectmap_data);
139 if (!list_empty(&sd->list))
142 if (sd->sm->free_section)
143 sd->sm->free_section(map, section);
145 for (i = 0; i < sd->allocmap_len; i++) {
146 ucimap_free_item(&sd->allocmap[i]);
154 ucimap_cleanup(struct uci_map *map)
156 struct list_head *ptr, *tmp;
158 list_for_each_safe(ptr, tmp, &map->sdata) {
159 struct uci_sectmap_data *sd = list_entry(ptr, struct uci_sectmap_data, list);
160 ucimap_free_section(map, sd);
165 ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str)
169 f = malloc(sizeof(struct uci_fixup));
173 INIT_LIST_HEAD(&f->list);
178 list_add(&f->list, &map->fixup);
182 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sectmap_data *sd, const char *str)
184 union ucimap_data *tdata = data;
189 if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type))
190 tdata = &data->list->item[data->list->n_items++];
192 switch(om->type & UCIMAP_SUBTYPE) {
194 if ((om->data.s.maxlen > 0) &&
195 (strlen(str) > om->data.s.maxlen))
200 ucimap_add_alloc(sd, s);
204 if (strcmp(str, "on"))
206 else if (strcmp(str, "1"))
208 else if (strcmp(str, "enabled"))
210 else if (strcmp(str, "off"))
212 else if (strcmp(str, "0"))
214 else if (strcmp(str, "disabled"))
222 val = strtol(str, &eptr, om->data.i.base);
223 if (!eptr || *eptr == '\0')
229 ucimap_add_fixup(sd->map, data, om, str);
236 ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sectmap_data *sd, struct uci_section *s)
238 struct uci_element *e, *l;
239 struct uci_option *o;
240 union ucimap_data *data;
242 uci_foreach_element(&s->options, e) {
243 struct uci_optmap *om = NULL, *tmp;
245 ucimap_foreach_option(sm, tmp) {
246 if (strcmp(e->name, tmp->name) == 0) {
254 data = ucimap_get_data(sd, om);
255 o = uci_to_option(e);
256 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
257 ucimap_add_value(data, om, sd, o->v.string);
258 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
259 uci_foreach_element(&o->v.list, l) {
260 ucimap_add_value(data, om, sd, l->name);
270 ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_section *s)
272 struct uci_sectmap_data *sd = NULL;
273 struct uci_optmap *om;
279 sd = malloc(sm->alloc_len + sizeof(struct uci_sectmap_data));
283 memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data));
284 INIT_LIST_HEAD(&sd->list);
286 ucimap_foreach_option(sm, om) {
287 if (ucimap_is_list(om->type)) {
288 union ucimap_data *data;
289 struct uci_element *e;
293 data = ucimap_get_data(sd, om);
294 uci_foreach_element(&s->options, e) {
295 struct uci_option *o = uci_to_option(e);
296 struct uci_element *tmp;
298 if (strcmp(e->name, om->name) != 0)
301 uci_foreach_element(&o->v.list, tmp) {
306 n_alloc += n_elements + 1;
307 size = sizeof(struct ucimap_list) +
308 n_elements * sizeof(union ucimap_data);
309 data->list = malloc(size);
310 memset(data->list, 0, size);
311 } else if (ucimap_is_alloc(om->type)) {
318 sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc));
322 section_name = strdup(s->e.name);
326 sd->section_name = section_name;
328 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
332 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
333 ucimap_add_alloc(sd, (void *)section_name);
334 ucimap_add_alloc(sd, (void *)sd->cmap);
335 ucimap_foreach_option(sm, om) {
336 if (!ucimap_is_list(om->type))
339 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
342 section = (char *)sd + sizeof(struct uci_sectmap_data);
344 err = sm->init_section(map, section, s);
348 list_add(&sd->list, &map->sdata);
349 err = ucimap_parse_options(map, sm, sd, s);
362 ucimap_free_section(map, sd);
367 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
369 struct uci_package *p = s->package;
371 memset(ptr, 0, sizeof(struct uci_ptr));
373 ptr->package = p->e.name;
376 ptr->section = s->e.name;
379 ptr->option = option;
380 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
384 ucimap_set_changed(void *section, void *field)
386 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
387 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
388 struct uci_sectmap *sm = sd->sm;
389 struct uci_optmap *om;
390 int ofs = (char *)field - (char *)section;
393 ucimap_foreach_option(sm, om) {
394 if (om->offset == ofs) {
395 SET_BIT(sd->cmap, i);
402 ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
404 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
405 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
406 struct uci_sectmap *sm = sd->sm;
407 struct uci_section *s = NULL;
408 struct uci_optmap *om;
409 struct uci_element *e;
414 uci_foreach_element(&p->sections, e) {
415 if (!strcmp(e->name, sd->section_name)) {
416 s = uci_to_section(e);
421 return UCI_ERR_NOTFOUND;
423 ucimap_foreach_option(sm, om) {
424 union ucimap_data *data;
426 const char *str = NULL;
428 data = ucimap_get_data(sd, om);
429 if (!TEST_BIT(sd->cmap, i))
432 ucimap_fill_ptr(&ptr, s, om->name);
433 switch(om->type & UCIMAP_SUBTYPE) {
438 sprintf(buf, "%d", data->i);
442 sprintf(buf, "%d", !!data->b);
448 ret = uci_set(s->package->ctx, &ptr);
452 CLR_BIT(sd->cmap, i);
460 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
462 struct uci_sectmap_data *sd;
466 list_for_each(p, &map->sdata) {
467 sd = list_entry(p, struct uci_sectmap_data, list);
470 if (strcmp(f->name, sd->section_name) != 0)
472 ret = (char *)sd + sizeof(struct uci_sectmap_data);
479 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
481 struct uci_element *e;
482 struct list_head *p, *tmp;
485 INIT_LIST_HEAD(&map->fixup);
486 uci_foreach_element(&pkg->sections, e) {
487 struct uci_section *s = uci_to_section(e);
489 for (i = 0; i < map->n_sections; i++) {
490 if (strcmp(s->type, map->sections[i]->type) != 0)
492 ucimap_parse_section(map, map->sections[i], s);
495 list_for_each_safe(p, tmp, &map->fixup) {
496 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
497 void *ptr = ucimap_find_section(map, f);
498 struct ucimap_list *list;
503 switch(f->type & UCIMAP_TYPE) {
505 f->data->section = ptr;
508 list = f->data->list;
509 list->item[list->n_items++].section = ptr;
514 list_for_each_safe(p, tmp, &map->sdata) {
515 struct uci_sectmap_data *sd = list_entry(p, struct uci_sectmap_data, list);
521 section = (char *) sd + sizeof(struct uci_sectmap_data);
522 if (sd->sm->add_section(map, section) != 0)
523 ucimap_free_section(map, sd);