2bff545b4ea895acb8e9f437470a2a321ee09774
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.
24 enum ucimap_type type
;
31 struct list_head list
;
32 struct uci_sectionmap
*sm
;
34 enum ucimap_type type
;
35 union ucimap_data
*data
;
38 #define ucimap_foreach_option(_sm, _o) \
39 if (!(_sm)->options_size) \
40 (_sm)->options_size = sizeof(struct uci_optmap); \
41 for (_o = &(_sm)->options[0]; \
42 ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
43 (_sm)->options_size * (_sm)->n_options); \
44 _o = (struct uci_optmap *) ((char *)(_o) + \
49 ucimap_is_alloc(enum ucimap_type type
)
51 switch(type
& UCIMAP_SUBTYPE
) {
60 ucimap_is_fixup(enum ucimap_type type
)
62 switch(type
& UCIMAP_SUBTYPE
) {
71 ucimap_is_simple(enum ucimap_type type
)
73 return ((type
& UCIMAP_TYPE
) == UCIMAP_SIMPLE
);
77 ucimap_is_list(enum ucimap_type type
)
79 return ((type
& UCIMAP_TYPE
) == UCIMAP_LIST
);
83 ucimap_is_list_auto(enum ucimap_type type
)
85 return ucimap_is_list(type
) && !!(type
& UCIMAP_LIST_AUTO
);
89 ucimap_is_custom(enum ucimap_type type
)
91 return ((type
& UCIMAP_SUBTYPE
) == UCIMAP_CUSTOM
);
95 ucimap_section_ptr(struct ucimap_section_data
*sd
)
97 return ((char *) sd
- sd
->sm
->smap_offset
);
100 static inline union ucimap_data
*
101 ucimap_get_data(struct ucimap_section_data
*sd
, struct uci_optmap
*om
)
105 data
= (char *) ucimap_section_ptr(sd
) + om
->offset
;
110 ucimap_init(struct uci_map
*map
)
112 INIT_LIST_HEAD(&map
->pending
);
113 INIT_LIST_HEAD(&map
->sdata
);
114 INIT_LIST_HEAD(&map
->fixup
);
119 ucimap_free_item(struct uci_alloc
*a
)
121 switch(a
->type
& UCIMAP_TYPE
) {
130 ucimap_add_alloc(struct ucimap_section_data
*sd
, void *ptr
)
132 struct uci_alloc
*a
= &sd
->allocmap
[sd
->allocmap_len
++];
133 a
->type
= UCIMAP_SIMPLE
;
138 ucimap_free_section(struct uci_map
*map
, struct ucimap_section_data
*sd
)
143 section
= ucimap_section_ptr(sd
);
144 if (!list_empty(&sd
->list
))
148 sd
->sm
->free(map
, section
);
150 for (i
= 0; i
< sd
->allocmap_len
; i
++) {
151 ucimap_free_item(&sd
->allocmap
[i
]);
159 ucimap_cleanup(struct uci_map
*map
)
161 struct list_head
*ptr
, *tmp
;
163 list_for_each_safe(ptr
, tmp
, &map
->sdata
) {
164 struct ucimap_section_data
*sd
= list_entry(ptr
, struct ucimap_section_data
, list
);
165 ucimap_free_section(map
, sd
);
170 ucimap_find_section(struct uci_map
*map
, struct uci_fixup
*f
)
172 struct ucimap_section_data
*sd
;
175 list_for_each(p
, &map
->sdata
) {
176 sd
= list_entry(p
, struct ucimap_section_data
, list
);
179 if (strcmp(f
->name
, sd
->section_name
) != 0)
181 return ucimap_section_ptr(sd
);
183 list_for_each(p
, &map
->pending
) {
184 sd
= list_entry(p
, struct ucimap_section_data
, list
);
187 if (strcmp(f
->name
, sd
->section_name
) != 0)
189 return ucimap_section_ptr(sd
);
195 ucimap_handle_fixup(struct uci_map
*map
, struct uci_fixup
*f
)
197 void *ptr
= ucimap_find_section(map
, f
);
198 struct ucimap_list
*list
;
203 switch(f
->type
& UCIMAP_TYPE
) {
208 list
= f
->data
->list
;
209 list
->item
[list
->n_items
++].ptr
= ptr
;
216 ucimap_add_fixup(struct uci_map
*map
, union ucimap_data
*data
, struct uci_optmap
*om
, const char *str
)
218 struct uci_fixup
*f
, tmp
;
220 INIT_LIST_HEAD(&tmp
.list
);
221 tmp
.sm
= om
->data
.sm
;
225 if (ucimap_handle_fixup(map
, &tmp
))
228 f
= malloc(sizeof(struct uci_fixup
));
232 memcpy(f
, &tmp
, sizeof(tmp
));
233 list_add_tail(&f
->list
, &map
->fixup
);
237 ucimap_add_value(union ucimap_data
*data
, struct uci_optmap
*om
, struct ucimap_section_data
*sd
, const char *str
)
239 union ucimap_data tdata
= *data
;
245 if (ucimap_is_list(om
->type
) && !ucimap_is_fixup(om
->type
))
246 data
= &data
->list
->item
[data
->list
->n_items
++];
248 switch(om
->type
& UCIMAP_SUBTYPE
) {
250 if ((om
->data
.s
.maxlen
> 0) &&
251 (strlen(str
) > om
->data
.s
.maxlen
))
256 ucimap_add_alloc(sd
, s
);
259 if (!strcmp(str
, "on"))
261 else if (!strcmp(str
, "1"))
263 else if (!strcmp(str
, "enabled"))
265 else if (!strcmp(str
, "off"))
267 else if (!strcmp(str
, "0"))
269 else if (!strcmp(str
, "disabled"))
277 lval
= strtol(str
, &eptr
, om
->data
.i
.base
);
278 if (lval
< INT_MIN
|| lval
> INT_MAX
)
281 if (!eptr
|| *eptr
== '\0')
282 tdata
.i
= (int) lval
;
287 ucimap_add_fixup(sd
->map
, data
, om
, str
);
290 tdata
.s
= (char *) data
;
294 if (om
->parse(ucimap_section_ptr(sd
), om
, &tdata
, str
) < 0)
297 if (ucimap_is_custom(om
->type
))
299 memcpy(data
, &tdata
, sizeof(union ucimap_data
));
304 ucimap_convert_list(union ucimap_data
*data
, struct uci_optmap
*om
, struct ucimap_section_data
*sd
, const char *str
)
312 ucimap_add_alloc(sd
, s
);
322 while (*s
&& !isspace(*s
))
330 ucimap_add_value(data
, om
, sd
, p
);
335 ucimap_parse_options(struct uci_map
*map
, struct uci_sectionmap
*sm
, struct ucimap_section_data
*sd
, struct uci_section
*s
)
337 struct uci_element
*e
, *l
;
338 struct uci_option
*o
;
339 union ucimap_data
*data
;
341 uci_foreach_element(&s
->options
, e
) {
342 struct uci_optmap
*om
= NULL
, *tmp
;
344 ucimap_foreach_option(sm
, tmp
) {
345 if (strcmp(e
->name
, tmp
->name
) == 0) {
353 data
= ucimap_get_data(sd
, om
);
354 o
= uci_to_option(e
);
355 if ((o
->type
== UCI_TYPE_STRING
) && ucimap_is_simple(om
->type
)) {
356 ucimap_add_value(data
, om
, sd
, o
->v
.string
);
357 } else if ((o
->type
== UCI_TYPE_LIST
) && ucimap_is_list(om
->type
)) {
358 uci_foreach_element(&o
->v
.list
, l
) {
359 ucimap_add_value(data
, om
, sd
, l
->name
);
361 } else if ((o
->type
== UCI_TYPE_STRING
) && ucimap_is_list_auto(om
->type
)) {
362 ucimap_convert_list(data
, om
, sd
, o
->v
.string
);
370 ucimap_add_section(struct ucimap_section_data
*sd
)
372 struct uci_map
*map
= sd
->map
;
374 if (sd
->sm
->add(map
, ucimap_section_ptr(sd
)) < 0)
375 ucimap_free_section(map
, sd
);
377 list_add_tail(&sd
->list
, &map
->sdata
);
382 ucimap_parse_section(struct uci_map
*map
, struct uci_sectionmap
*sm
, struct ucimap_section_data
*sd
, struct uci_section
*s
)
384 struct uci_optmap
*om
;
390 INIT_LIST_HEAD(&sd
->list
);
394 ucimap_foreach_option(sm
, om
) {
395 if (ucimap_is_list(om
->type
)) {
396 union ucimap_data
*data
;
397 struct uci_element
*e
;
401 data
= ucimap_get_data(sd
, om
);
402 uci_foreach_element(&s
->options
, e
) {
403 struct uci_option
*o
= uci_to_option(e
);
404 struct uci_element
*tmp
;
406 if (strcmp(e
->name
, om
->name
) != 0)
409 if (o
->type
== UCI_TYPE_LIST
) {
410 uci_foreach_element(&o
->v
.list
, tmp
) {
413 } else if ((o
->type
== UCI_TYPE_STRING
) &&
414 ucimap_is_list_auto(om
->type
)) {
415 const char *data
= o
->v
.string
;
417 while (isspace(*data
))
425 while (*data
&& !isspace(*data
))
429 /* for the duplicated data string */
435 /* add one more for the ucimap_list */
436 n_alloc
+= n_elements
+ 1;
437 size
= sizeof(struct ucimap_list
) +
438 n_elements
* sizeof(union ucimap_data
);
439 data
->list
= malloc(size
);
440 memset(data
->list
, 0, size
);
441 } else if (ucimap_is_alloc(om
->type
)) {
446 sd
->allocmap
= malloc(n_alloc
* sizeof(struct uci_alloc
));
450 section_name
= strdup(s
->e
.name
);
454 sd
->section_name
= section_name
;
456 sd
->cmap
= malloc(BITFIELD_SIZE(sm
->n_options
));
460 memset(sd
->cmap
, 0, BITFIELD_SIZE(sm
->n_options
));
461 ucimap_add_alloc(sd
, (void *)section_name
);
462 ucimap_add_alloc(sd
, (void *)sd
->cmap
);
463 ucimap_foreach_option(sm
, om
) {
464 if (!ucimap_is_list(om
->type
))
467 ucimap_add_alloc(sd
, ucimap_get_data(sd
, om
)->list
);
470 section
= ucimap_section_ptr(sd
);
471 err
= sm
->init(map
, section
, s
);
476 ucimap_add_section(sd
);
478 list_add_tail(&sd
->list
, &map
->pending
);
481 err
= ucimap_parse_options(map
, sm
, sd
, s
);
494 ucimap_free_section(map
, sd
);
499 ucimap_fill_ptr(struct uci_ptr
*ptr
, struct uci_section
*s
, const char *option
)
501 struct uci_package
*p
= s
->package
;
503 memset(ptr
, 0, sizeof(struct uci_ptr
));
505 ptr
->package
= p
->e
.name
;
508 ptr
->section
= s
->e
.name
;
511 ptr
->option
= option
;
512 return uci_lookup_ptr(p
->ctx
, ptr
, NULL
, false);
516 ucimap_set_changed(struct ucimap_section_data
*sd
, void *field
)
518 void *section
= ucimap_section_ptr(sd
);
519 struct uci_sectionmap
*sm
= sd
->sm
;
520 struct uci_optmap
*om
;
521 int ofs
= (char *)field
- (char *)section
;
524 ucimap_foreach_option(sm
, om
) {
525 if (om
->offset
== ofs
) {
526 SET_BIT(sd
->cmap
, i
);
534 ucimap_store_section(struct uci_map
*map
, struct uci_package
*p
, struct ucimap_section_data
*sd
)
536 struct uci_sectionmap
*sm
= sd
->sm
;
537 struct uci_section
*s
= NULL
;
538 struct uci_optmap
*om
;
539 struct uci_element
*e
;
544 uci_foreach_element(&p
->sections
, e
) {
545 if (!strcmp(e
->name
, sd
->section_name
)) {
546 s
= uci_to_section(e
);
551 return UCI_ERR_NOTFOUND
;
553 ucimap_foreach_option(sm
, om
) {
554 union ucimap_data
*data
;
559 if (ucimap_is_list(om
->type
))
562 data
= ucimap_get_data(sd
, om
);
563 if (!TEST_BIT(sd
->cmap
, i
- 1))
566 ucimap_fill_ptr(&ptr
, s
, om
->name
);
567 switch(om
->type
& UCIMAP_SUBTYPE
) {
572 sprintf(buf
, "%d", data
->i
);
576 sprintf(buf
, "%d", !!data
->b
);
585 union ucimap_data tdata
, *data
;
587 data
= ucimap_get_data(sd
, om
);
588 if (ucimap_is_custom(om
->type
)) {
589 tdata
.s
= (char *)data
;
593 if (om
->format(ucimap_section_ptr(sd
), om
, data
, &str
) < 0)
600 ret
= uci_set(s
->package
->ctx
, &ptr
);
604 CLR_BIT(sd
->cmap
, i
- 1);
611 ucimap_parse(struct uci_map
*map
, struct uci_package
*pkg
)
613 struct uci_element
*e
;
614 struct list_head
*p
, *tmp
;
617 INIT_LIST_HEAD(&map
->fixup
);
618 uci_foreach_element(&pkg
->sections
, e
) {
619 struct uci_section
*s
= uci_to_section(e
);
621 for (i
= 0; i
< map
->n_sections
; i
++) {
622 struct uci_sectionmap
*sm
= map
->sections
[i
];
623 struct ucimap_section_data
*sd
;
625 if (strcmp(s
->type
, map
->sections
[i
]->type
) != 0)
629 sd
= sm
->alloc(map
, sm
, s
);
630 memset(sd
, 0, sizeof(struct ucimap_section_data
));
632 sd
= malloc(sm
->alloc_len
);
633 memset(sd
, 0, sm
->alloc_len
);
638 ucimap_parse_section(map
, sm
, sd
, s
);
643 list_for_each_safe(p
, tmp
, &map
->fixup
) {
644 struct uci_fixup
*f
= list_entry(p
, struct uci_fixup
, list
);
645 ucimap_handle_fixup(map
, f
);
650 list_for_each_safe(p
, tmp
, &map
->pending
) {
651 struct ucimap_section_data
*sd
;
652 sd
= list_entry(p
, struct ucimap_section_data
, list
);
654 list_del_init(&sd
->list
);
655 ucimap_add_section(sd
);