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_sectmap
*sm
;
32 enum ucimap_type type
;
33 union ucimap_data
*data
;
36 struct uci_sectmap_data
{
37 struct list_head list
;
39 struct uci_sectmap
*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_sectmap_data
*sd
)
109 static inline union ucimap_data
*
110 ucimap_get_data(struct uci_sectmap_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_sectmap_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_sectmap_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_sectmap_data
*sd
= list_entry(ptr
, struct uci_sectmap_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_sectmap_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_sectmap
*sm
, struct uci_sectmap_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_sectmap
*sm
, struct uci_section
*s
)
295 struct uci_sectmap_data
*sd
= NULL
;
296 struct uci_optmap
*om
;
302 sd
= malloc(sm
->alloc_len
+ sizeof(struct uci_sectmap_data
));
306 memset(sd
, 0, sm
->alloc_len
+ sizeof(struct uci_sectmap_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_sectmap_data
);
410 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
411 struct uci_sectmap
*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_sectmap_data
);
429 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
430 struct uci_sectmap
*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_sectmap_data
*sd
;
495 list_for_each(p
, &map
->sdata
) {
496 sd
= list_entry(p
, struct uci_sectmap_data
, list
);
499 if (strcmp(f
->name
, sd
->section_name
) != 0)
501 ret
= (char *)sd
+ sizeof(struct uci_sectmap_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_sectmap_data
*sd
= list_entry(p
, struct uci_sectmap_data
, list
);
550 section
= (char *) sd
+ sizeof(struct uci_sectmap_data
);
551 if (sd
->sm
->add(map
, section
) != 0)
552 ucimap_free_section(map
, sd
);