dddbafc92d410cbca6f5fab0cec2051dd8258d47
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
);