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
;
260 sd
= malloc(sm
->alloc_len
+ sizeof(struct uci_sectmap_data
));
264 memset(sd
, 0, sm
->alloc_len
+ sizeof(struct uci_sectmap_data
));
265 INIT_LIST_HEAD(&sd
->list
);
269 sd
->allocmap
= malloc(sm
->n_options
* sizeof(struct uci_alloc
));
273 sd
->section_name
= strdup(s
->e
.name
);
274 if (!sd
->section_name
)
277 sd
->cmap
= malloc(BITFIELD_SIZE(sm
->n_options
));
281 memset(sd
->cmap
, 0, BITFIELD_SIZE(sm
->n_options
));
282 ucimap_add_alloc(&sd
->allocmap
[sd
->allocmap_len
++], (void *)sd
->section_name
);
283 ucimap_add_alloc(&sd
->allocmap
[sd
->allocmap_len
++], (void *)sd
->cmap
);
285 section
= (char *)sd
+ sizeof(struct uci_sectmap_data
);
287 err
= sm
->init_section(map
, section
, s
);
291 list_add(&sd
->list
, &map
->sdata
);
292 err
= ucimap_parse_options(map
, sm
, sd
, s
);
305 ucimap_free_section(map
, sd
);
310 ucimap_fill_ptr(struct uci_ptr
*ptr
, struct uci_section
*s
, const char *option
)
312 struct uci_package
*p
= s
->package
;
314 memset(ptr
, 0, sizeof(struct uci_ptr
));
316 ptr
->package
= p
->e
.name
;
319 ptr
->section
= s
->e
.name
;
322 ptr
->option
= option
;
323 return uci_lookup_ptr(p
->ctx
, ptr
, NULL
, false);
327 ucimap_set_changed(void *section
, void *field
)
329 char *sptr
= (char *)section
- sizeof(struct uci_sectmap_data
);
330 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
331 struct uci_sectmap
*sm
= sd
->sm
;
332 int ofs
= (char *)field
- (char *)section
;
335 for (i
= 0; i
< sm
->n_options
; i
++) {
336 if (sm
->options
[i
].offset
== ofs
) {
337 SET_BIT(sd
->cmap
, i
);
344 ucimap_store_section(struct uci_map
*map
, struct uci_package
*p
, void *section
)
346 char *sptr
= (char *)section
- sizeof(struct uci_sectmap_data
);
347 struct uci_sectmap_data
*sd
= (struct uci_sectmap_data
*) sptr
;
348 struct uci_sectmap
*sm
= sd
->sm
;
349 struct uci_section
*s
= NULL
;
350 struct uci_element
*e
;
354 uci_foreach_element(&p
->sections
, e
) {
355 if (!strcmp(e
->name
, sd
->section_name
)) {
356 s
= uci_to_section(e
);
361 return UCI_ERR_NOTFOUND
;
363 for (i
= 0; i
< sm
->n_options
; i
++) {
364 struct uci_optmap
*om
= &sm
->options
[i
];
366 const char *str
= NULL
;
367 void *p
= (char *)section
+ om
->offset
;
369 if (!TEST_BIT(sd
->cmap
, i
))
372 ucimap_fill_ptr(&ptr
, s
, om
->name
);
373 switch(om
->type
& UCIMAP_SUBTYPE
) {
375 str
= *((char **) p
);
378 sprintf(buf
, "%d", *((int *) p
));
382 sprintf(buf
, "%d", !!*((bool *)p
));
388 ret
= uci_set(s
->package
->ctx
, &ptr
);
392 CLR_BIT(sd
->cmap
, i
);
399 ucimap_find_section(struct uci_map
*map
, struct uci_fixup
*f
)
401 struct uci_sectmap_data
*sd
;
405 list_for_each(p
, &map
->sdata
) {
406 sd
= list_entry(p
, struct uci_sectmap_data
, list
);
409 if (strcmp(f
->name
, sd
->section_name
) != 0)
411 ret
= (char *)sd
+ sizeof(struct uci_sectmap_data
);
418 ucimap_parse(struct uci_map
*map
, struct uci_package
*pkg
)
420 struct uci_element
*e
;
421 struct list_head
*p
, *tmp
;
424 INIT_LIST_HEAD(&map
->fixup
);
425 uci_foreach_element(&pkg
->sections
, e
) {
426 struct uci_section
*s
= uci_to_section(e
);
428 for (i
= 0; i
< map
->n_sections
; i
++) {
429 if (strcmp(s
->type
, map
->sections
[i
]->type
) != 0)
431 ucimap_parse_section(map
, map
->sections
[i
], s
);
434 list_for_each_safe(p
, tmp
, &map
->fixup
) {
435 struct uci_fixup
*f
= list_entry(p
, struct uci_fixup
, list
);
436 void *ptr
= ucimap_find_section(map
, f
);
437 struct uci_listmap
*li
;
442 switch(f
->target
.type
& UCIMAP_TYPE
) {
444 *f
->target
.data
.ptr
= ptr
;
447 li
= malloc(sizeof(struct uci_listmap
));
448 memset(li
, 0, sizeof(struct uci_listmap
));
449 INIT_LIST_HEAD(&li
->list
);
450 li
->data
.section
= ptr
;
451 list_add(&li
->list
, f
->target
.data
.list
);
455 list_for_each_safe(p
, tmp
, &map
->sdata
) {
456 struct uci_sectmap_data
*sd
= list_entry(p
, struct uci_sectmap_data
, list
);
462 section
= (char *) sd
+ sizeof(struct uci_sectmap_data
);
463 if (sd
->sm
->add_section(map
, section
) != 0)
464 ucimap_free_section(map
, sd
);