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;
219 void *ptr = sm->options;
220 int size = sm->options_size;
223 size = sizeof(struct uci_optmap);
225 for (i = 0; i < sm->n_options; i++) {
226 struct uci_optmap *tmp = ptr;
228 if (strcmp(e->name, tmp->name) == 0) {
232 ptr = (unsigned char *)ptr + size;
237 data = (union uci_datamap *) (section + om->offset);
238 o = uci_to_option(e);
239 if ((o->type == UCI_TYPE_STRING) && ((om->type & UCIMAP_TYPE) == UCIMAP_SIMPLE)) {
240 ucimap_add_value(data, om, sd, o->v.string);
243 if ((o->type == UCI_TYPE_LIST) && ((om->type & UCIMAP_TYPE) == UCIMAP_LIST)) {
244 struct list_head *list;
246 list = (struct list_head *) (section + om->offset);
247 INIT_LIST_HEAD(list);
248 sd->allocmap[sd->allocmap_len].type = UCIMAP_LIST;
249 sd->allocmap[sd->allocmap_len++].data.list = list;
250 uci_foreach_element(&o->v.list, l) {
251 ucimap_add_value(data, om, sd, l->name);
262 ucimap_parse_section(struct uci_map *map, struct uci_sectmap *sm, struct uci_section *s)
264 struct uci_sectmap_data *sd = NULL;
265 void *section = NULL;
269 sd = malloc(sm->alloc_len + sizeof(struct uci_sectmap_data));
273 memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data));
274 INIT_LIST_HEAD(&sd->list);
278 sd->allocmap = malloc(sm->n_options * sizeof(struct uci_alloc));
282 section_name = strdup(s->e.name);
286 sd->section_name = section_name;
288 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
292 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
293 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)section_name);
294 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)sd->cmap);
296 section = (char *)sd + sizeof(struct uci_sectmap_data);
298 err = sm->init_section(map, section, s);
302 list_add(&sd->list, &map->sdata);
303 err = ucimap_parse_options(map, sm, sd, s);
316 ucimap_free_section(map, sd);
321 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
323 struct uci_package *p = s->package;
325 memset(ptr, 0, sizeof(struct uci_ptr));
327 ptr->package = p->e.name;
330 ptr->section = s->e.name;
333 ptr->option = option;
334 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
338 ucimap_set_changed(void *section, void *field)
340 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
341 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
342 struct uci_sectmap *sm = sd->sm;
343 int ofs = (char *)field - (char *)section;
346 for (i = 0; i < sm->n_options; i++) {
347 if (sm->options[i].offset == ofs) {
348 SET_BIT(sd->cmap, i);
355 ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
357 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
358 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
359 struct uci_sectmap *sm = sd->sm;
360 struct uci_section *s = NULL;
361 struct uci_element *e;
365 uci_foreach_element(&p->sections, e) {
366 if (!strcmp(e->name, sd->section_name)) {
367 s = uci_to_section(e);
372 return UCI_ERR_NOTFOUND;
374 for (i = 0; i < sm->n_options; i++) {
375 struct uci_optmap *om = &sm->options[i];
377 const char *str = NULL;
378 void *p = (char *)section + om->offset;
380 if (!TEST_BIT(sd->cmap, i))
383 ucimap_fill_ptr(&ptr, s, om->name);
384 switch(om->type & UCIMAP_SUBTYPE) {
386 str = *((char **) p);
389 sprintf(buf, "%d", *((int *) p));
393 sprintf(buf, "%d", !!*((bool *)p));
399 ret = uci_set(s->package->ctx, &ptr);
403 CLR_BIT(sd->cmap, i);
410 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
412 struct uci_sectmap_data *sd;
416 list_for_each(p, &map->sdata) {
417 sd = list_entry(p, struct uci_sectmap_data, list);
420 if (strcmp(f->name, sd->section_name) != 0)
422 ret = (char *)sd + sizeof(struct uci_sectmap_data);
429 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
431 struct uci_element *e;
432 struct list_head *p, *tmp;
435 INIT_LIST_HEAD(&map->fixup);
436 uci_foreach_element(&pkg->sections, e) {
437 struct uci_section *s = uci_to_section(e);
439 for (i = 0; i < map->n_sections; i++) {
440 if (strcmp(s->type, map->sections[i]->type) != 0)
442 ucimap_parse_section(map, map->sections[i], s);
445 list_for_each_safe(p, tmp, &map->fixup) {
446 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
447 void *ptr = ucimap_find_section(map, f);
448 struct uci_listmap *li;
453 switch(f->target.type & UCIMAP_TYPE) {
455 *f->target.data.ptr = ptr;
458 li = malloc(sizeof(struct uci_listmap));
459 memset(li, 0, sizeof(struct uci_listmap));
460 INIT_LIST_HEAD(&li->list);
461 li->data.section = ptr;
462 list_add(&li->list, f->target.data.list);
466 list_for_each_safe(p, tmp, &map->sdata) {
467 struct uci_sectmap_data *sd = list_entry(p, struct uci_sectmap_data, list);
473 section = (char *) sd + sizeof(struct uci_sectmap_data);
474 if (sd->sm->add_section(map, section) != 0)
475 ucimap_free_section(map, sd);