• source navigation  • diff markup  • identifier search  • freetext search  • 

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

This page was automatically generated by LXR 0.3.1.  •  OpenWrt