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