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