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.
21 enum ucimap_type type;
24 struct list_head *list;
29 struct list_head list;
30 struct uci_sectmap *sm;
32 struct uci_alloc target;
35 struct uci_sectmap_data {
36 struct list_head list;
38 struct uci_sectmap *sm;
39 const char *section_name;
41 /* list of allocations done by ucimap */
42 struct uci_alloc *allocmap;
43 unsigned long allocmap_len;
45 /* map for changed fields */
52 ucimap_init(struct uci_map *map)
54 INIT_LIST_HEAD(&map->sdata);
55 INIT_LIST_HEAD(&map->fixup);
60 ucimap_free_item(struct uci_alloc *a)
62 struct list_head *p, *tmp;
63 switch(a->type & UCIMAP_TYPE) {
68 list_for_each_safe(p, tmp, a->data.list) {
69 struct uci_listmap *l = list_entry(p, struct uci_listmap, list);
78 ucimap_add_alloc(struct uci_alloc *a, void *ptr)
80 a->type = UCIMAP_SIMPLE;
85 ucimap_free_section(struct uci_map *map, struct uci_sectmap_data *sd)
90 section = (char *) section + sizeof(struct uci_sectmap_data);
91 if (!list_empty(&sd->list))
94 if (sd->sm->free_section)
95 sd->sm->free_section(map, section);
97 for (i = 0; i < sd->allocmap_len; i++) {
98 ucimap_free_item(&sd->allocmap[i]);
106 ucimap_cleanup(struct uci_map *map)
108 struct list_head *ptr, *tmp;
110 list_for_each_safe(ptr, tmp, &map->sdata) {
111 struct uci_sectmap_data *sd = list_entry(ptr, struct uci_sectmap_data, list);
112 ucimap_free_section(map, sd);
117 ucimap_add_fixup(struct uci_map *map, void *data, struct uci_optmap *om, const char *str)
121 f = malloc(sizeof(struct uci_fixup));
125 INIT_LIST_HEAD(&f->list);
128 f->target.type = om->type;
129 f->target.data.ptr = data;
130 list_add(&f->list, &map->fixup);
134 ucimap_add_value(union uci_datamap *data, struct uci_optmap *om, struct uci_sectmap_data *sd, const char *str)
136 union uci_datamap tdata;
137 struct list_head *list = NULL;
142 if ((om->type & UCIMAP_TYPE) == UCIMAP_LIST) {
143 if ((om->type & UCIMAP_SUBTYPE) == UCIMAP_SECTION) {
144 ucimap_add_fixup(sd->map, data, om, str);
147 memset(&tdata, 0, sizeof(tdata));
152 switch(om->type & UCIMAP_SUBTYPE) {
154 if ((om->data.s.maxlen > 0) &&
155 (strlen(str) > om->data.s.maxlen))
160 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], s);
164 if (strcmp(str, "on"))
166 else if (strcmp(str, "1"))
168 else if (strcmp(str, "enabled"))
170 else if (strcmp(str, "off"))
172 else if (strcmp(str, "0"))
174 else if (strcmp(str, "disabled"))
182 val = strtol(str, &eptr, om->data.i.base);
183 if (!eptr || *eptr == '\0')
189 ucimap_add_fixup(sd->map, data, om, str);
193 if ((om->type & UCIMAP_TYPE) == UCIMAP_LIST) {
194 struct uci_listmap *item;
196 item = malloc(sizeof(struct uci_listmap));
200 INIT_LIST_HEAD(&item->list);
201 memcpy(&item->data, &tdata, sizeof(tdata));
202 list_add(&item->list, list);
208 ucimap_parse_options(struct uci_map *map, struct uci_sectmap *sm, struct uci_sectmap_data *sd, struct uci_section *s)
210 struct uci_element *e, *l;
211 struct uci_option *o;
212 unsigned long section;
213 union uci_datamap *data;
216 section = (unsigned long) sd + sizeof(struct uci_sectmap_data);
217 uci_foreach_element(&s->options, e) {
218 struct uci_optmap *om = NULL;
220 for (i = 0; i < sm->n_options; i++) {
221 if (strcmp(e->name, sm->options[i].name) == 0) {
222 om = &sm->options[i];
229 data = (union uci_datamap *) (section + om->offset);
230 o = uci_to_option(e);
231 if ((o->type == UCI_TYPE_STRING) && ((om->type & UCIMAP_TYPE) == UCIMAP_SIMPLE)) {
232 ucimap_add_value(data, om, sd, o->v.string);
235 if ((o->type == UCI_TYPE_LIST) && ((om->type & UCIMAP_TYPE) == UCIMAP_LIST)) {
236 struct list_head *list;
238 list = (struct list_head *) (section + om->offset);
239 INIT_LIST_HEAD(list);
240 sd->allocmap[sd->allocmap_len].type = UCIMAP_LIST;
241 sd->allocmap[sd->allocmap_len++].data.list = list;
242 uci_foreach_element(&o->v.list, l) {
243 ucimap_add_value(data, om, sd, l->name);
254 ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_section *s)
256 struct uci_sectmap_data *sd = NULL;
257 void *section = NULL;
260 sd = malloc(sm->alloc_len + sizeof(struct uci_sectmap_data));
264 memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data));
265 INIT_LIST_HEAD(&sd->list);
269 sd->allocmap = malloc(sm->n_options * sizeof(struct uci_alloc));
273 sd->section_name = strdup(s->e.name);
274 if (!sd->section_name)
277 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
281 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
282 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)sd->section_name);
283 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)sd->cmap);
285 section = (char *)sd + sizeof(struct uci_sectmap_data);
287 err = sm->init_section(map, section, s);
291 list_add(&sd->list, &map->sdata);
292 err = ucimap_parse_options(map, sm, sd, s);
305 ucimap_free_section(map, sd);
310 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
312 struct uci_package *p = s->package;
314 memset(ptr, 0, sizeof(struct uci_ptr));
316 ptr->package = p->e.name;
319 ptr->section = s->e.name;
322 ptr->option = option;
323 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
327 ucimap_set_changed(void *section, void *field)
329 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
330 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
331 struct uci_sectmap *sm = sd->sm;
332 int ofs = (char *)field - (char *)section;
335 for (i = 0; i < sm->n_options; i++) {
336 if (sm->options[i].offset == ofs) {
337 SET_BIT(sd->cmap, i);
344 ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
346 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
347 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
348 struct uci_sectmap *sm = sd->sm;
349 struct uci_section *s = NULL;
350 struct uci_element *e;
354 uci_foreach_element(&p->sections, e) {
355 if (!strcmp(e->name, sd->section_name)) {
356 s = uci_to_section(e);
361 return UCI_ERR_NOTFOUND;
363 for (i = 0; i < sm->n_options; i++) {
364 struct uci_optmap *om = &sm->options[i];
366 const char *str = NULL;
367 void *p = (char *)section + om->offset;
369 if (!TEST_BIT(sd->cmap, i))
372 ucimap_fill_ptr(&ptr, s, om->name);
373 switch(om->type & UCIMAP_SUBTYPE) {
375 str = *((char **) p);
378 sprintf(buf, "%d", *((int *) p));
382 sprintf(buf, "%d", !!*((bool *)p));
388 ret = uci_set(s->package->ctx, &ptr);
392 CLR_BIT(sd->cmap, i);
399 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
401 struct uci_sectmap_data *sd;
405 list_for_each(p, &map->sdata) {
406 sd = list_entry(p, struct uci_sectmap_data, list);
409 if (strcmp(f->name, sd->section_name) != 0)
411 ret = (char *)sd + sizeof(struct uci_sectmap_data);
418 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
420 struct uci_element *e;
421 struct list_head *p, *tmp;
424 INIT_LIST_HEAD(&map->fixup);
425 uci_foreach_element(&pkg->sections, e) {
426 struct uci_section *s = uci_to_section(e);
428 for (i = 0; i < map->n_sections; i++) {
429 if (strcmp(s->type, map->sections[i]->type) != 0)
431 ucimap_parse_section(map, map->sections[i], s);
434 list_for_each_safe(p, tmp, &map->fixup) {
435 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
436 void *ptr = ucimap_find_section(map, f);
437 struct uci_listmap *li;
442 switch(f->target.type & UCIMAP_TYPE) {
444 *f->target.data.ptr = ptr;
447 li = malloc(sizeof(struct uci_listmap));
448 memset(li, 0, sizeof(struct uci_listmap));
449 INIT_LIST_HEAD(&li->list);
450 li->data.section = ptr;
451 list_add(&li->list, f->target.data.list);
455 list_for_each_safe(p, tmp, &map->sdata) {
456 struct uci_sectmap_data *sd = list_entry(p, struct uci_sectmap_data, list);
462 section = (char *) sd + sizeof(struct uci_sectmap_data);
463 if (sd->sm->add_section(map, section) != 0)
464 ucimap_free_section(map, sd);