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;
261 sd = malloc(sm->alloc_len + sizeof(struct uci_sectmap_data));
265 memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectmap_data));
266 INIT_LIST_HEAD(&sd->list);
270 sd->allocmap = malloc(sm->n_options * sizeof(struct uci_alloc));
274 section_name = strdup(s->e.name);
278 sd->section_name = section_name;
280 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
284 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
285 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)section_name);
286 ucimap_add_alloc(&sd->allocmap[sd->allocmap_len++], (void *)sd->cmap);
288 section = (char *)sd + sizeof(struct uci_sectmap_data);
290 err = sm->init_section(map, section, s);
294 list_add(&sd->list, &map->sdata);
295 err = ucimap_parse_options(map, sm, sd, s);
308 ucimap_free_section(map, sd);
313 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
315 struct uci_package *p = s->package;
317 memset(ptr, 0, sizeof(struct uci_ptr));
319 ptr->package = p->e.name;
322 ptr->section = s->e.name;
325 ptr->option = option;
326 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
330 ucimap_set_changed(void *section, void *field)
332 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
333 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
334 struct uci_sectmap *sm = sd->sm;
335 int ofs = (char *)field - (char *)section;
338 for (i = 0; i < sm->n_options; i++) {
339 if (sm->options[i].offset == ofs) {
340 SET_BIT(sd->cmap, i);
347 ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
349 char *sptr = (char *)section - sizeof(struct uci_sectmap_data);
350 struct uci_sectmap_data *sd = (struct uci_sectmap_data *) sptr;
351 struct uci_sectmap *sm = sd->sm;
352 struct uci_section *s = NULL;
353 struct uci_element *e;
357 uci_foreach_element(&p->sections, e) {
358 if (!strcmp(e->name, sd->section_name)) {
359 s = uci_to_section(e);
364 return UCI_ERR_NOTFOUND;
366 for (i = 0; i < sm->n_options; i++) {
367 struct uci_optmap *om = &sm->options[i];
369 const char *str = NULL;
370 void *p = (char *)section + om->offset;
372 if (!TEST_BIT(sd->cmap, i))
375 ucimap_fill_ptr(&ptr, s, om->name);
376 switch(om->type & UCIMAP_SUBTYPE) {
378 str = *((char **) p);
381 sprintf(buf, "%d", *((int *) p));
385 sprintf(buf, "%d", !!*((bool *)p));
391 ret = uci_set(s->package->ctx, &ptr);
395 CLR_BIT(sd->cmap, i);
402 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
404 struct uci_sectmap_data *sd;
408 list_for_each(p, &map->sdata) {
409 sd = list_entry(p, struct uci_sectmap_data, list);
412 if (strcmp(f->name, sd->section_name) != 0)
414 ret = (char *)sd + sizeof(struct uci_sectmap_data);
421 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
423 struct uci_element *e;
424 struct list_head *p, *tmp;
427 INIT_LIST_HEAD(&map->fixup);
428 uci_foreach_element(&pkg->sections, e) {
429 struct uci_section *s = uci_to_section(e);
431 for (i = 0; i < map->n_sections; i++) {
432 if (strcmp(s->type, map->sections[i]->type) != 0)
434 ucimap_parse_section(map, map->sections[i], s);
437 list_for_each_safe(p, tmp, &map->fixup) {
438 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
439 void *ptr = ucimap_find_section(map, f);
440 struct uci_listmap *li;
445 switch(f->target.type & UCIMAP_TYPE) {
447 *f->target.data.ptr = ptr;
450 li = malloc(sizeof(struct uci_listmap));
451 memset(li, 0, sizeof(struct uci_listmap));
452 INIT_LIST_HEAD(&li->list);
453 li->data.section = ptr;
454 list_add(&li->list, f->target.data.list);
458 list_for_each_safe(p, tmp, &map->sdata) {
459 struct uci_sectmap_data *sd = list_entry(p, struct uci_sectmap_data, list);
465 section = (char *) sd + sizeof(struct uci_sectmap_data);
466 if (sd->sm->add_section(map, section) != 0)
467 ucimap_free_section(map, sd);