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_sectionmap *sm;
32 enum ucimap_type type;
33 union ucimap_data *data;
36 struct uci_sectionmap_data {
37 struct list_head list;
39 struct uci_sectionmap *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);
97 ucimap_is_custom(enum ucimap_type type)
99 return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
103 ucimap_section_ptr(struct uci_sectionmap_data *sd)
109 static inline union ucimap_data *
110 ucimap_get_data(struct uci_sectionmap_data *sd, struct uci_optmap *om)
114 data = (char *) ucimap_section_ptr(sd) + om->offset;
119 ucimap_init(struct uci_map *map)
121 INIT_LIST_HEAD(&map->sdata);
122 INIT_LIST_HEAD(&map->fixup);
127 ucimap_free_item(struct uci_alloc *a)
129 switch(a->type & UCIMAP_TYPE) {
138 ucimap_add_alloc(struct uci_sectionmap_data *sd, void *ptr)
140 struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
141 a->type = UCIMAP_SIMPLE;
146 ucimap_free_section(struct uci_map *map, struct uci_sectionmap_data *sd)
151 section = ucimap_section_ptr(sd);
152 if (!list_empty(&sd->list))
156 sd->sm->free(map, section);
158 for (i = 0; i < sd->allocmap_len; i++) {
159 ucimap_free_item(&sd->allocmap[i]);
167 ucimap_cleanup(struct uci_map *map)
169 struct list_head *ptr, *tmp;
171 list_for_each_safe(ptr, tmp, &map->sdata) {
172 struct uci_sectionmap_data *sd = list_entry(ptr, struct uci_sectionmap_data, list);
173 ucimap_free_section(map, sd);
178 ucimap_add_fixup(struct uci_map *map, union ucimap_data *data, struct uci_optmap *om, const char *str)
182 f = malloc(sizeof(struct uci_fixup));
186 INIT_LIST_HEAD(&f->list);
191 list_add(&f->list, &map->fixup);
195 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct uci_sectionmap_data *sd, const char *str)
197 union ucimap_data tdata = *data;
202 if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type))
203 data = &data->list->item[data->list->n_items++];
205 switch(om->type & UCIMAP_SUBTYPE) {
207 if ((om->data.s.maxlen > 0) &&
208 (strlen(str) > om->data.s.maxlen))
213 ucimap_add_alloc(sd, s);
217 if (strcmp(str, "on"))
219 else if (strcmp(str, "1"))
221 else if (strcmp(str, "enabled"))
223 else if (strcmp(str, "off"))
225 else if (strcmp(str, "0"))
227 else if (strcmp(str, "disabled"))
235 val = strtol(str, &eptr, om->data.i.base);
236 if (!eptr || *eptr == '\0')
242 ucimap_add_fixup(sd->map, data, om, str);
245 tdata.s = (char *) data;
249 if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
252 if (ucimap_is_custom(om->type))
254 memcpy(data, &tdata, sizeof(union ucimap_data));
259 ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct uci_sectionmap_data *sd, struct uci_section *s)
261 struct uci_element *e, *l;
262 struct uci_option *o;
263 union ucimap_data *data;
265 uci_foreach_element(&s->options, e) {
266 struct uci_optmap *om = NULL, *tmp;
268 ucimap_foreach_option(sm, tmp) {
269 if (strcmp(e->name, tmp->name) == 0) {
277 data = ucimap_get_data(sd, om);
278 o = uci_to_option(e);
279 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
280 ucimap_add_value(data, om, sd, o->v.string);
281 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
282 uci_foreach_element(&o->v.list, l) {
283 ucimap_add_value(data, om, sd, l->name);
293 ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct uci_section *s)
295 struct uci_sectionmap_data *sd = NULL;
296 struct uci_optmap *om;
302 sd = malloc(sm->alloc_len + sizeof(struct uci_sectionmap_data));
306 memset(sd, 0, sm->alloc_len + sizeof(struct uci_sectionmap_data));
307 INIT_LIST_HEAD(&sd->list);
309 ucimap_foreach_option(sm, om) {
310 if (ucimap_is_list(om->type)) {
311 union ucimap_data *data;
312 struct uci_element *e;
316 data = ucimap_get_data(sd, om);
317 uci_foreach_element(&s->options, e) {
318 struct uci_option *o = uci_to_option(e);
319 struct uci_element *tmp;
321 if (strcmp(e->name, om->name) != 0)
324 uci_foreach_element(&o->v.list, tmp) {
329 n_alloc += n_elements + 1;
330 size = sizeof(struct ucimap_list) +
331 n_elements * sizeof(union ucimap_data);
332 data->list = malloc(size);
333 memset(data->list, 0, size);
334 } else if (ucimap_is_alloc(om->type)) {
341 sd->allocmap = malloc(n_alloc * sizeof(struct uci_alloc));
345 section_name = strdup(s->e.name);
349 sd->section_name = section_name;
351 sd->cmap = malloc(BITFIELD_SIZE(sm->n_options));
355 memset(sd->cmap, 0, BITFIELD_SIZE(sm->n_options));
356 ucimap_add_alloc(sd, (void *)section_name);
357 ucimap_add_alloc(sd, (void *)sd->cmap);
358 ucimap_foreach_option(sm, om) {
359 if (!ucimap_is_list(om->type))
362 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
365 section = ucimap_section_ptr(sd);
367 err = sm->init(map, section, s);
371 list_add(&sd->list, &map->sdata);
372 err = ucimap_parse_options(map, sm, sd, s);
385 ucimap_free_section(map, sd);
390 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
392 struct uci_package *p = s->package;
394 memset(ptr, 0, sizeof(struct uci_ptr));
396 ptr->package = p->e.name;
399 ptr->section = s->e.name;
402 ptr->option = option;
403 return uci_lookup_ptr(p->ctx, ptr, NULL, false);
407 ucimap_set_changed(void *section, void *field)
409 char *sptr = (char *)section - sizeof(struct uci_sectionmap_data);
410 struct uci_sectionmap_data *sd = (struct uci_sectionmap_data *) sptr;
411 struct uci_sectionmap *sm = sd->sm;
412 struct uci_optmap *om;
413 int ofs = (char *)field - (char *)section;
416 ucimap_foreach_option(sm, om) {
417 if (om->offset == ofs) {
418 SET_BIT(sd->cmap, i);
426 ucimap_store_section(struct uci_map *map, struct uci_package *p, void *section)
428 char *sptr = (char *)section - sizeof(struct uci_sectionmap_data);
429 struct uci_sectionmap_data *sd = (struct uci_sectionmap_data *) sptr;
430 struct uci_sectionmap *sm = sd->sm;
431 struct uci_section *s = NULL;
432 struct uci_optmap *om;
433 struct uci_element *e;
438 uci_foreach_element(&p->sections, e) {
439 if (!strcmp(e->name, sd->section_name)) {
440 s = uci_to_section(e);
445 return UCI_ERR_NOTFOUND;
447 ucimap_foreach_option(sm, om) {
448 union ucimap_data *data;
450 const char *str = NULL;
452 if (ucimap_is_list(om->type))
455 data = ucimap_get_data(sd, om);
456 if (!TEST_BIT(sd->cmap, i))
459 ucimap_fill_ptr(&ptr, s, om->name);
460 switch(om->type & UCIMAP_SUBTYPE) {
465 sprintf(buf, "%d", data->i);
469 sprintf(buf, "%d", !!data->b);
477 ret = uci_set(s->package->ctx, &ptr);
481 CLR_BIT(sd->cmap, i);
489 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
491 struct uci_sectionmap_data *sd;
495 list_for_each(p, &map->sdata) {
496 sd = list_entry(p, struct uci_sectionmap_data, list);
499 if (strcmp(f->name, sd->section_name) != 0)
501 ret = (char *)sd + sizeof(struct uci_sectionmap_data);
508 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
510 struct uci_element *e;
511 struct list_head *p, *tmp;
514 INIT_LIST_HEAD(&map->fixup);
515 uci_foreach_element(&pkg->sections, e) {
516 struct uci_section *s = uci_to_section(e);
518 for (i = 0; i < map->n_sections; i++) {
519 if (strcmp(s->type, map->sections[i]->type) != 0)
521 ucimap_parse_section(map, map->sections[i], s);
524 list_for_each_safe(p, tmp, &map->fixup) {
525 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
526 void *ptr = ucimap_find_section(map, f);
527 struct ucimap_list *list;
532 switch(f->type & UCIMAP_TYPE) {
534 f->data->section = ptr;
537 list = f->data->list;
538 list->item[list->n_items++].section = ptr;
543 list_for_each_safe(p, tmp, &map->sdata) {
544 struct uci_sectionmap_data *sd = list_entry(p, struct uci_sectionmap_data, list);
550 section = (char *) sd + sizeof(struct uci_sectionmap_data);
551 if (sd->sm->add(map, section) != 0)
552 ucimap_free_section(map, sd);