remove ucimap type->name conversion unless DEBUG is enabled
[project/uci.git] / ucimap.c
1 /*
2  * ucimap - library for mapping uci sections into data structures
3  * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
4  *
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
8  *
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.
13  */
14 #include <strings.h>
15 #include <stdbool.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <unistd.h>
19 #include <limits.h>
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include "ucimap.h"
24 #include "uci_internal.h"
25
26 struct uci_alloc {
27         void *ptr;
28 };
29
30 struct uci_alloc_custom {
31         void *section;
32         struct uci_optmap *om;
33         void *ptr;
34 };
35
36 struct uci_fixup {
37         struct list_head list;
38         struct uci_sectionmap *sm;
39         const char *name;
40         enum ucimap_type type;
41         union ucimap_data *data;
42 };
43
44 #define ucimap_foreach_option(_sm, _o) \
45         if (!(_sm)->options_size) \
46                 (_sm)->options_size = sizeof(struct uci_optmap); \
47         for (_o = &(_sm)->options[0]; \
48                  ((char *)(_o)) < ((char *) &(_sm)->options[0] + \
49                         (_sm)->options_size * (_sm)->n_options); \
50                  _o = (struct uci_optmap *) ((char *)(_o) + \
51                         (_sm)->options_size))
52
53
54 static inline bool
55 ucimap_is_alloc(enum ucimap_type type)
56 {
57         switch(type & UCIMAP_SUBTYPE) {
58         case UCIMAP_STRING:
59                 return true;
60         default:
61                 return false;
62         }
63 }
64
65 static inline bool
66 ucimap_is_fixup(enum ucimap_type type)
67 {
68         switch(type & UCIMAP_SUBTYPE) {
69         case UCIMAP_SECTION:
70                 return true;
71         default:
72                 return false;
73         }
74 }
75
76 static inline bool
77 ucimap_is_simple(enum ucimap_type type)
78 {
79         return ((type & UCIMAP_TYPE) == UCIMAP_SIMPLE);
80 }
81
82 static inline bool
83 ucimap_is_list(enum ucimap_type type)
84 {
85         return ((type & UCIMAP_TYPE) == UCIMAP_LIST);
86 }
87
88 static inline bool
89 ucimap_is_list_auto(enum ucimap_type type)
90 {
91         return ucimap_is_list(type) && !!(type & UCIMAP_LIST_AUTO);
92 }
93
94 static inline bool
95 ucimap_is_custom(enum ucimap_type type)
96 {
97         return ((type & UCIMAP_SUBTYPE) == UCIMAP_CUSTOM);
98 }
99
100 static inline void *
101 ucimap_section_ptr(struct ucimap_section_data *sd)
102 {
103         return ((char *) sd - sd->sm->smap_offset);
104 }
105
106 static inline struct ucimap_section_data *
107 ucimap_ptr_section(struct uci_sectionmap *sm, void *ptr) {
108         ptr = (char *) ptr + sm->smap_offset;
109         return ptr;
110 }
111
112 static inline union ucimap_data *
113 ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om)
114 {
115         void *data;
116
117         data = (char *) ucimap_section_ptr(sd) + om->offset;
118         return data;
119 }
120
121 int
122 ucimap_init(struct uci_map *map)
123 {
124         INIT_LIST_HEAD(&map->pending);
125         INIT_LIST_HEAD(&map->sdata);
126         INIT_LIST_HEAD(&map->fixup);
127         return 0;
128 }
129
130 static void
131 ucimap_add_alloc(struct ucimap_section_data *sd, void *ptr)
132 {
133         struct uci_alloc *a = &sd->allocmap[sd->allocmap_len++];
134         a->ptr = ptr;
135 }
136
137 void
138 ucimap_free_section(struct uci_map *map, struct ucimap_section_data *sd)
139 {
140         void *section;
141         int i;
142
143         section = ucimap_section_ptr(sd);
144         if (!list_empty(&sd->list))
145                 list_del(&sd->list);
146
147         if (sd->sm->free)
148                 sd->sm->free(map, section);
149
150         for (i = 0; i < sd->allocmap_len; i++) {
151                 free(sd->allocmap[i].ptr);
152         }
153
154         if (sd->alloc_custom) {
155                 for (i = 0; i < sd->alloc_custom_len; i++) {
156                         struct uci_alloc_custom *a = &sd->alloc_custom[i];
157                         a->om->free(a->section, a->om, a->ptr);
158                 }
159                 free(sd->alloc_custom);
160         }
161
162         free(sd->allocmap);
163         free(sd);
164 }
165
166 void
167 ucimap_cleanup(struct uci_map *map)
168 {
169         struct list_head *ptr, *tmp;
170
171         list_for_each_safe(ptr, tmp, &map->sdata) {
172                 struct ucimap_section_data *sd = list_entry(ptr, struct ucimap_section_data, list);
173                 ucimap_free_section(map, sd);
174         }
175 }
176
177 static void *
178 ucimap_find_section(struct uci_map *map, struct uci_fixup *f)
179 {
180         struct ucimap_section_data *sd;
181         struct list_head *p;
182
183         list_for_each(p, &map->sdata) {
184                 sd = list_entry(p, struct ucimap_section_data, list);
185                 if (sd->sm != f->sm)
186                         continue;
187                 if (strcmp(f->name, sd->section_name) != 0)
188                         continue;
189                 return ucimap_section_ptr(sd);
190         }
191         list_for_each(p, &map->pending) {
192                 sd = list_entry(p, struct ucimap_section_data, list);
193                 if (sd->sm != f->sm)
194                         continue;
195                 if (strcmp(f->name, sd->section_name) != 0)
196                         continue;
197                 return ucimap_section_ptr(sd);
198         }
199         return NULL;
200 }
201
202 static bool
203 ucimap_handle_fixup(struct uci_map *map, struct uci_fixup *f)
204 {
205         void *ptr = ucimap_find_section(map, f);
206         struct ucimap_list *list;
207
208         if (!ptr)
209                 return false;
210
211         switch(f->type & UCIMAP_TYPE) {
212         case UCIMAP_SIMPLE:
213                 f->data->ptr = ptr;
214                 break;
215         case UCIMAP_LIST:
216                 list = f->data->list;
217                 list->item[list->n_items++].ptr = ptr;
218                 break;
219         }
220         return true;
221 }
222
223 void
224 ucimap_free_item(struct ucimap_section_data *sd, void *item)
225 {
226         struct uci_alloc_custom *ac;
227         struct uci_alloc *a;
228         void *ptr = *((void **) item);
229         int i;
230
231         if (!ptr)
232                 return;
233
234         *((void **)item) = NULL;
235         for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
236                 if (a->ptr != ptr)
237                         continue;
238
239                 if (i != sd->allocmap_len - 1)
240                         a->ptr = sd->allocmap[sd->allocmap_len - 1].ptr;
241
242                 sd->allocmap_len--;
243                 return;
244         }
245
246         for (i = 0, ac = sd->alloc_custom; i < sd->alloc_custom_len; i++, ac++) {
247                 if (ac->ptr != ptr)
248                         continue;
249
250                 if (i != sd->alloc_custom_len - 1)
251                         memcpy(ac, &sd->alloc_custom[sd->alloc_custom_len - 1],
252                                 sizeof(struct uci_alloc_custom));
253
254                 ac->om->free(ac->section, ac->om, ac->ptr);
255                 sd->alloc_custom_len--;
256                 return;
257         }
258 }
259
260 int
261 ucimap_resize_list(struct ucimap_section_data *sd, struct ucimap_list **list, int items)
262 {
263         struct ucimap_list *new;
264         struct uci_alloc *a;
265         int i, offset = 0;
266         int size = sizeof(struct ucimap_list) + items * sizeof(union ucimap_data);
267
268         if (!*list) {
269                 new = calloc(1, size);
270
271                 ucimap_add_alloc(sd, new);
272                 goto set;
273         }
274
275         for (i = 0, a = sd->allocmap; i < sd->allocmap_len; i++, a++) {
276                 if (a->ptr != *list)
277                         continue;
278
279                 goto realloc;
280         }
281         return -ENOENT;
282
283 realloc:
284         if (items > (*list)->size)
285                 offset = (items - (*list)->size) * sizeof(union ucimap_data);
286
287         a->ptr = realloc(a->ptr, size);
288         if (offset)
289                 memset((char *) a->ptr + offset, 0, size - offset);
290         new = a->ptr;
291
292 set:
293         new->size = items;
294         *list = new;
295         return 0;
296 }
297
298 static void
299 ucimap_add_fixup(struct ucimap_section_data *sd, union ucimap_data *data, struct uci_optmap *om, const char *str)
300 {
301         struct uci_fixup *f, tmp;
302         struct uci_map *map = sd->map;
303
304         INIT_LIST_HEAD(&tmp.list);
305         tmp.sm = om->data.sm;
306         tmp.name = str;
307         tmp.type = om->type;
308         tmp.data = data;
309         if (ucimap_handle_fixup(map, &tmp))
310                 return;
311
312         f = malloc(sizeof(struct uci_fixup));
313         if (!f)
314                 return;
315
316         memcpy(f, &tmp, sizeof(tmp));
317         list_add_tail(&f->list, &map->fixup);
318 }
319
320 static void
321 ucimap_add_custom_alloc(struct ucimap_section_data *sd, struct uci_optmap *om, void *ptr)
322 {
323         struct uci_alloc_custom *a = &sd->alloc_custom[sd->alloc_custom_len++];
324
325         a->section = ucimap_section_ptr(sd);
326         a->om = om;
327         a->ptr = ptr;
328 }
329
330 static void
331 ucimap_add_value(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
332 {
333         union ucimap_data tdata = *data;
334         char *eptr = NULL;
335         long lval;
336         char *s;
337         int val;
338
339         if (ucimap_is_list(om->type) && !ucimap_is_fixup(om->type)) {
340                 if (unlikely(data->list->size <= data->list->n_items)) {
341                         /* should not happen */
342                         DPRINTF("ERROR: overflow while filling a list\n");
343                         return;
344                 }
345
346                 data = &data->list->item[data->list->n_items++];
347         }
348
349         switch(om->type & UCIMAP_SUBTYPE) {
350         case UCIMAP_STRING:
351                 if ((om->data.s.maxlen > 0) &&
352                         (strlen(str) > om->data.s.maxlen))
353                         return;
354
355                 s = strdup(str);
356                 tdata.s = s;
357                 ucimap_add_alloc(sd, s);
358                 break;
359         case UCIMAP_BOOL:
360                 if (!strcmp(str, "on"))
361                         val = true;
362                 else if (!strcmp(str, "1"))
363                         val = true;
364                 else if (!strcmp(str, "enabled"))
365                         val = true;
366                 else if (!strcmp(str, "off"))
367                         val = false;
368                 else if (!strcmp(str, "0"))
369                         val = false;
370                 else if (!strcmp(str, "disabled"))
371                         val = false;
372                 else
373                         return;
374
375                 tdata.b = val;
376                 break;
377         case UCIMAP_INT:
378                 lval = strtol(str, &eptr, om->data.i.base);
379                 if (lval < INT_MIN || lval > INT_MAX)
380                         return;
381
382                 if (!eptr || *eptr == '\0')
383                         tdata.i = (int) lval;
384                 else
385                         return;
386                 break;
387         case UCIMAP_SECTION:
388                 ucimap_add_fixup(sd, data, om, str);
389                 return;
390         case UCIMAP_CUSTOM:
391                 tdata.s = (char *) data;
392                 break;
393         }
394         if (om->parse) {
395                 if (om->parse(ucimap_section_ptr(sd), om, &tdata, str) < 0)
396                         return;
397                 if (ucimap_is_custom(om->type) && om->free) {
398                         if (tdata.ptr != data->ptr)
399                                 ucimap_add_custom_alloc(sd, om, data->ptr);
400                 }
401         }
402         if (ucimap_is_custom(om->type))
403                 return;
404         memcpy(data, &tdata, sizeof(union ucimap_data));
405 }
406
407
408 static void
409 ucimap_convert_list(union ucimap_data *data, struct uci_optmap *om, struct ucimap_section_data *sd, const char *str)
410 {
411         char *s, *p;
412
413         s = strdup(str);
414         if (!s)
415                 return;
416
417         ucimap_add_alloc(sd, s);
418
419         do {
420                 while (isspace(*s))
421                         s++;
422
423                 if (!*s)
424                         break;
425
426                 p = s;
427                 while (*s && !isspace(*s))
428                         s++;
429
430                 if (isspace(*s)) {
431                         *s = 0;
432                         s++;
433                 }
434
435                 ucimap_add_value(data, om, sd, p);
436         } while (*s);
437 }
438
439 static int
440 ucimap_parse_options(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
441 {
442         struct uci_element *e, *l;
443         struct uci_option *o;
444         union ucimap_data *data;
445
446         uci_foreach_element(&s->options, e) {
447                 struct uci_optmap *om = NULL, *tmp;
448
449                 ucimap_foreach_option(sm, tmp) {
450                         if (strcmp(e->name, tmp->name) == 0) {
451                                 om = tmp;
452                                 break;
453                         }
454                 }
455                 if (!om)
456                         continue;
457
458                 data = ucimap_get_data(sd, om);
459                 o = uci_to_option(e);
460                 if ((o->type == UCI_TYPE_STRING) && ucimap_is_simple(om->type)) {
461                         ucimap_add_value(data, om, sd, o->v.string);
462                 } else if ((o->type == UCI_TYPE_LIST) && ucimap_is_list(om->type)) {
463                         uci_foreach_element(&o->v.list, l) {
464                                 ucimap_add_value(data, om, sd, l->name);
465                         }
466                 } else if ((o->type == UCI_TYPE_STRING) && ucimap_is_list_auto(om->type)) {
467                         ucimap_convert_list(data, om, sd, o->v.string);
468                 }
469         }
470
471         return 0;
472 }
473
474 static void
475 ucimap_add_section(struct ucimap_section_data *sd)
476 {
477         struct uci_map *map = sd->map;
478
479         if (sd->sm->add(map, ucimap_section_ptr(sd)) < 0)
480                 ucimap_free_section(map, sd);
481         else
482                 list_add_tail(&sd->list, &map->sdata);
483 }
484
485 #ifdef UCI_DEBUG
486 static const char *ucimap_type_names[] = {
487         [UCIMAP_STRING] = "string",
488         [UCIMAP_INT] = "integer",
489         [UCIMAP_BOOL] = "boolean",
490         [UCIMAP_SECTION] = "section",
491         [UCIMAP_LIST] = "list",
492 };
493
494 static const char *
495 ucimap_get_type_name(int type)
496 {
497         static char buf[32];
498         const char *name;
499
500         if (ucimap_is_list(type))
501                 return ucimap_type_names[UCIMAP_LIST];
502
503         name = ucimap_type_names[type & UCIMAP_SUBTYPE];
504         if (!name) {
505                 sprintf(buf, "Unknown (%d)", type & UCIMAP_SUBTYPE);
506                 name = buf;
507         }
508
509         return name;
510 }
511 #endif
512
513 static bool
514 ucimap_check_optmap_type(struct uci_sectionmap *sm, struct uci_optmap *om)
515 {
516         unsigned int type;
517
518         if (unlikely(sm->type_name != om->type_name) &&
519             unlikely(strcmp(sm->type_name, om->type_name) != 0)) {
520                 DPRINTF("Option '%s' of section type '%s' refereces unknown "
521                         "section type '%s', should be '%s'.\n",
522                         om->name, sm->type, om->type_name, sm->type_name);
523                 return false;
524         }
525
526         if (om->detected_type < 0)
527                 return true;
528
529         if (ucimap_is_custom(om->type))
530                 return true;
531
532         if (ucimap_is_list(om->type) !=
533             ucimap_is_list(om->detected_type))
534                 goto failed;
535
536         if (ucimap_is_list(om->type))
537                 return true;
538
539         type = om->type & UCIMAP_SUBTYPE;
540         switch(type) {
541         case UCIMAP_STRING:
542         case UCIMAP_INT:
543         case UCIMAP_BOOL:
544                 if (type != om->detected_type)
545                         goto failed;
546                 break;
547         case UCIMAP_SECTION:
548                 goto failed;
549         default:
550                 break;
551         }
552         return true;
553
554 failed:
555         DPRINTF("Invalid type in option '%s' of section type '%s', "
556                 "declared type is %s, detected type is %s\n",
557                 om->name, sm->type,
558                 ucimap_get_type_name(om->type),
559                 ucimap_get_type_name(om->detected_type));
560         return false;
561 }
562
563 static void
564 ucimap_count_alloc(struct uci_optmap *om, int *n_alloc, int *n_custom)
565 {
566         if (ucimap_is_alloc(om->type))
567                 (*n_alloc)++;
568         else if (ucimap_is_custom(om->type) && om->free)
569                 (*n_custom)++;
570 }
571
572 int
573 ucimap_parse_section(struct uci_map *map, struct uci_sectionmap *sm, struct ucimap_section_data *sd, struct uci_section *s)
574 {
575         struct uci_optmap *om;
576         char *section_name;
577         void *section;
578         int n_alloc = 2;
579         int n_alloc_custom = 0;
580         int err;
581
582         INIT_LIST_HEAD(&sd->list);
583         sd->map = map;
584         sd->sm = sm;
585
586         ucimap_foreach_option(sm, om) {
587                 if (!ucimap_check_optmap_type(sm, om))
588                         continue;
589
590                 if (ucimap_is_list(om->type)) {
591                         union ucimap_data *data;
592                         struct uci_element *e;
593                         int n_elements = 0;
594                         int n_elements_custom = 0;
595                         int size;
596
597                         data = ucimap_get_data(sd, om);
598                         uci_foreach_element(&s->options, e) {
599                                 struct uci_option *o = uci_to_option(e);
600                                 struct uci_element *tmp;
601
602                                 if (strcmp(e->name, om->name) != 0)
603                                         continue;
604
605                                 if (o->type == UCI_TYPE_LIST) {
606                                         uci_foreach_element(&o->v.list, tmp) {
607                                                 ucimap_count_alloc(om, &n_elements, &n_elements_custom);
608                                         }
609                                 } else if ((o->type == UCI_TYPE_STRING) &&
610                                            ucimap_is_list_auto(om->type)) {
611                                         const char *data = o->v.string;
612                                         do {
613                                                 while (isspace(*data))
614                                                         data++;
615
616                                                 if (!*data)
617                                                         break;
618
619                                                 n_elements++;
620                                                 ucimap_count_alloc(om, &n_elements, &n_elements_custom);
621
622                                                 while (*data && !isspace(*data))
623                                                         data++;
624                                         } while (*data);
625
626                                         /* for the duplicated data string */
627                                         if (n_elements)
628                                                 n_alloc++;
629                                 }
630                                 break;
631                         }
632                         /* add one more for the ucimap_list */
633                         n_alloc += n_elements + 1;
634                         n_alloc_custom += n_elements_custom;
635                         size = sizeof(struct ucimap_list) +
636                                 n_elements * sizeof(union ucimap_data);
637
638                         data->list = malloc(size);
639                         if (!data->list)
640                                 goto error_mem;
641
642                         data->list->size = n_elements;
643                         memset(data->list, 0, size);
644                 } else {
645                         ucimap_count_alloc(om, &n_alloc, &n_alloc_custom);
646                 }
647         }
648
649         sd->allocmap = calloc(n_alloc, sizeof(struct uci_alloc));
650         if (!sd->allocmap)
651                 goto error_mem;
652
653         if (n_alloc_custom > 0) {
654                 sd->alloc_custom = calloc(n_alloc_custom, sizeof(struct uci_alloc_custom));
655                 if (!sd->alloc_custom)
656                         goto error_mem;
657         }
658
659         section_name = strdup(s->e.name);
660         if (!section_name)
661                 goto error_mem;
662
663         sd->section_name = section_name;
664
665         sd->cmap = calloc(1, BITFIELD_SIZE(sm->n_options));
666         if (!sd->cmap)
667                 goto error_mem;
668
669         ucimap_add_alloc(sd, (void *)section_name);
670         ucimap_add_alloc(sd, (void *)sd->cmap);
671         ucimap_foreach_option(sm, om) {
672                 if (!ucimap_is_list(om->type))
673                         continue;
674
675                 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list);
676         }
677
678         section = ucimap_section_ptr(sd);
679         err = sm->init(map, section, s);
680         if (err)
681                 goto error;
682
683         if (map->parsed) {
684                 ucimap_add_section(sd);
685         } else {
686                 list_add_tail(&sd->list, &map->pending);
687         }
688
689         err = ucimap_parse_options(map, sm, sd, s);
690         if (err)
691                 goto error;
692
693         return 0;
694
695 error_mem:
696         if (sd->allocmap)
697                 free(sd->allocmap);
698         free(sd);
699         return UCI_ERR_MEM;
700
701 error:
702         ucimap_free_section(map, sd);
703         return err;
704 }
705
706 static int
707 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option)
708 {
709         struct uci_package *p = s->package;
710
711         memset(ptr, 0, sizeof(struct uci_ptr));
712
713         ptr->package = p->e.name;
714         ptr->p = p;
715
716         ptr->section = s->e.name;
717         ptr->s = s;
718
719         ptr->option = option;
720         return uci_lookup_ptr(p->ctx, ptr, NULL, false);
721 }
722
723 void
724 ucimap_set_changed(struct ucimap_section_data *sd, void *field)
725 {
726         void *section = ucimap_section_ptr(sd);
727         struct uci_sectionmap *sm = sd->sm;
728         struct uci_optmap *om;
729         int ofs = (char *)field - (char *)section;
730         int i = 0;
731
732         ucimap_foreach_option(sm, om) {
733                 if (om->offset == ofs) {
734                         SET_BIT(sd->cmap, i);
735                         break;
736                 }
737                 i++;
738         }
739 }
740
741 static char *
742 ucimap_data_to_string(struct ucimap_section_data *sd, struct uci_optmap *om, union ucimap_data *data)
743 {
744         static char buf[32];
745         char *str = NULL;
746
747         switch(om->type & UCIMAP_SUBTYPE) {
748         case UCIMAP_STRING:
749                 str = data->s;
750                 break;
751         case UCIMAP_INT:
752                 sprintf(buf, "%d", data->i);
753                 str = buf;
754                 break;
755         case UCIMAP_BOOL:
756                 sprintf(buf, "%d", !!data->b);
757                 str = buf;
758                 break;
759         case UCIMAP_SECTION:
760                 if (data->ptr)
761                         str = (char *) ucimap_ptr_section(om->data.sm, data->ptr)->section_name;
762                 else
763                         str = "";
764                 break;
765         case UCIMAP_CUSTOM:
766                 break;
767         default:
768                 return NULL;
769         }
770
771         if (om->format) {
772                 union ucimap_data tdata;
773
774                 if (ucimap_is_custom(om->type)) {
775                         tdata.s = (char *)data;
776                         data = &tdata;
777                 }
778
779                 if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
780                         return NULL;
781
782                 if (!str)
783                         str = "";
784         }
785         return str;
786 }
787
788 int
789 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
790 {
791         struct uci_sectionmap *sm = sd->sm;
792         struct uci_section *s = NULL;
793         struct uci_optmap *om;
794         struct uci_element *e;
795         struct uci_ptr ptr;
796         int i = 0;
797         int ret;
798
799         uci_foreach_element(&p->sections, e) {
800                 if (!strcmp(e->name, sd->section_name)) {
801                         s = uci_to_section(e);
802                         break;
803                 }
804         }
805         if (!s)
806                 return UCI_ERR_NOTFOUND;
807
808         ucimap_foreach_option(sm, om) {
809                 union ucimap_data *data;
810
811                 i++;
812                 data = ucimap_get_data(sd, om);
813                 if (!TEST_BIT(sd->cmap, i - 1))
814                         continue;
815
816                 ucimap_fill_ptr(&ptr, s, om->name);
817                 if (ucimap_is_list(om->type)) {
818                         struct ucimap_list *list = data->list;
819                         bool first = true;
820                         int j;
821
822                         for (j = 0; j < list->n_items; j++) {
823                                 ptr.value = ucimap_data_to_string(sd, om, &list->item[j]);
824                                 if (!ptr.value)
825                                         continue;
826
827                                 if (first) {
828                                         ret = uci_set(s->package->ctx, &ptr);
829                                         first = false;
830                                 } else {
831                                         ret = uci_add_list(s->package->ctx, &ptr);
832                                 }
833                                 if (ret)
834                                         return ret;
835                         }
836                 } else {
837                         ptr.value = ucimap_data_to_string(sd, om, data);
838                         if (!ptr.value)
839                                 continue;
840
841                         ret = uci_set(s->package->ctx, &ptr);
842                         if (ret)
843                                 return ret;
844                 }
845
846                 CLR_BIT(sd->cmap, i - 1);
847         }
848
849         return 0;
850 }
851
852 void
853 ucimap_parse(struct uci_map *map, struct uci_package *pkg)
854 {
855         struct uci_element *e;
856         struct list_head *p, *tmp;
857         int i;
858
859         INIT_LIST_HEAD(&map->fixup);
860         uci_foreach_element(&pkg->sections, e) {
861                 struct uci_section *s = uci_to_section(e);
862
863                 for (i = 0; i < map->n_sections; i++) {
864                         struct uci_sectionmap *sm = map->sections[i];
865                         struct ucimap_section_data *sd;
866
867                         if (strcmp(s->type, map->sections[i]->type) != 0)
868                                 continue;
869
870                         if (sm->alloc) {
871                                 sd = sm->alloc(map, sm, s);
872                                 memset(sd, 0, sizeof(struct ucimap_section_data));
873                         } else {
874                                 sd = malloc(sm->alloc_len);
875                                 memset(sd, 0, sm->alloc_len);
876                         }
877                         if (!sd)
878                                 continue;
879
880                         ucimap_parse_section(map, sm, sd, s);
881                 }
882         }
883         map->parsed = true;
884
885         list_for_each_safe(p, tmp, &map->fixup) {
886                 struct uci_fixup *f = list_entry(p, struct uci_fixup, list);
887                 ucimap_handle_fixup(map, f);
888                 list_del(&f->list);
889                 free(f);
890         }
891
892         list_for_each_safe(p, tmp, &map->pending) {
893                 struct ucimap_section_data *sd;
894                 sd = list_entry(p, struct ucimap_section_data, list);
895
896                 list_del_init(&sd->list);
897                 ucimap_add_section(sd);
898         }
899 }