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 = calloc(1, size); 665 if (!data->list) 666 goto error_mem; 667 668 data->list->size = n_elements; 669 } else { 670 ucimap_count_alloc(om, &n_alloc, &n_alloc_custom); 671 } 672 } 673 674 sd->allocmap = calloc(n_alloc, sizeof(struct ucimap_alloc)); 675 if (!sd->allocmap) 676 goto error_mem; 677 678 if (n_alloc_custom > 0) { 679 sd->alloc_custom = calloc(n_alloc_custom, sizeof(struct ucimap_alloc_custom)); 680 if (!sd->alloc_custom) 681 goto error_mem; 682 } 683 684 section_name = strdup(s->e.name); 685 if (!section_name) 686 goto error_mem; 687 688 sd->section_name = section_name; 689 690 sd->cmap = calloc(1, BITFIELD_SIZE(sm->n_options)); 691 if (!sd->cmap) 692 goto error_mem; 693 694 ucimap_add_alloc(sd, (void *)section_name); 695 ucimap_add_alloc(sd, (void *)sd->cmap); 696 ucimap_foreach_option(sm, om) { 697 if (!ucimap_is_list(om->type)) 698 continue; 699 700 ucimap_add_alloc(sd, ucimap_get_data(sd, om)->list); 701 } 702 703 section = ucimap_section_ptr(sd); 704 err = sm->init(map, section, s); 705 if (err) 706 goto error; 707 708 if (map->parsed) { 709 err = ucimap_add_section(sd); 710 if (err) 711 return err; 712 } else { 713 ucimap_add_section_list(map, sd); 714 } 715 716 err = ucimap_parse_options(map, sm, sd, s); 717 if (err) 718 goto error; 719 720 return 0; 721 722 error_mem: 723 free(sd->alloc_custom); 724 free(sd->allocmap); 725 free(sd); 726 return UCI_ERR_MEM; 727 728 error: 729 ucimap_free_section(map, sd); 730 return err; 731 } 732 733 static int 734 ucimap_fill_ptr(struct uci_ptr *ptr, struct uci_section *s, const char *option) 735 { 736 struct uci_package *p = s->package; 737 738 memset(ptr, 0, sizeof(struct uci_ptr)); 739 740 ptr->package = p->e.name; 741 ptr->p = p; 742 743 ptr->section = s->e.name; 744 ptr->s = s; 745 746 ptr->option = option; 747 return uci_lookup_ptr(p->ctx, ptr, NULL, false); 748 } 749 750 void 751 ucimap_set_changed(struct ucimap_section_data *sd, void *field) 752 { 753 void *section = ucimap_section_ptr(sd); 754 struct uci_sectionmap *sm = sd->sm; 755 struct uci_optmap *om; 756 unsigned int ofs = (char *)field - (char *)section; 757 int i = 0; 758 759 ucimap_foreach_option(sm, om) { 760 if (om->offset == ofs) { 761 SET_BIT(sd->cmap, i); 762 break; 763 } 764 i++; 765 } 766 } 767 768 static char * 769 ucimap_data_to_string(struct ucimap_section_data *sd, struct uci_optmap *om, union ucimap_data *data) 770 { 771 static char buf[32]; 772 char *str = NULL; 773 774 switch(om->type & UCIMAP_SUBTYPE) { 775 case UCIMAP_STRING: 776 str = data->s; 777 break; 778 case UCIMAP_INT: 779 sprintf(buf, "%d", data->i); 780 str = buf; 781 break; 782 case UCIMAP_BOOL: 783 sprintf(buf, "%d", !!data->b); 784 str = buf; 785 break; 786 case UCIMAP_SECTION: 787 if (data->ptr) 788 str = (char *) ucimap_ptr_section(om->data.sm, data->ptr)->section_name; 789 else 790 str = ""; 791 break; 792 case UCIMAP_CUSTOM: 793 break; 794 default: 795 return NULL; 796 } 797 798 if (om->format) { 799 if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0) 800 return NULL; 801 802 if (!str) 803 str = ""; 804 } 805 return str; 806 } 807 808 int 809 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd) 810 { 811 struct uci_sectionmap *sm = sd->sm; 812 struct uci_section *s = NULL; 813 struct uci_optmap *om; 814 struct uci_element *e; 815 struct uci_ptr ptr; 816 int i = 0; 817 int ret; 818 819 uci_foreach_element(&p->sections, e) { 820 if (!strcmp(e->name, sd->section_name)) { 821 s = uci_to_section(e); 822 break; 823 } 824 } 825 if (!s) 826 return UCI_ERR_NOTFOUND; 827 828 ucimap_foreach_option(sm, om) { 829 union ucimap_data *data; 830 831 i++; 832 data = ucimap_get_data(sd, om); 833 if (!TEST_BIT(sd->cmap, i - 1)) 834 continue; 835 836 ucimap_fill_ptr(&ptr, s, om->name); 837 if (ucimap_is_list(om->type)) { 838 struct ucimap_list *list = data->list; 839 bool first = true; 840 int j; 841 842 for (j = 0; j < list->n_items; j++) { 843 ptr.value = ucimap_data_to_string(sd, om, &list->item[j]); 844 if (!ptr.value) 845 continue; 846 847 if (first) { 848 ret = uci_set(s->package->ctx, &ptr); 849 first = false; 850 } else { 851 ret = uci_add_list(s->package->ctx, &ptr); 852 } 853 if (ret) 854 return ret; 855 } 856 } else { 857 ptr.value = ucimap_data_to_string(sd, om, data); 858 if (!ptr.value) 859 continue; 860 861 ret = uci_set(s->package->ctx, &ptr); 862 if (ret) 863 return ret; 864 } 865 866 CLR_BIT(sd->cmap, i - 1); 867 } 868 869 return 0; 870 } 871 872 void 873 ucimap_parse(struct uci_map *map, struct uci_package *pkg) 874 { 875 struct uci_element *e; 876 struct ucimap_section_data *sd, **sd_tail; 877 struct ucimap_fixup *f; 878 unsigned int i; 879 880 sd_tail = map->sdata_tail; 881 map->parsed = false; 882 map->sdata_tail = &map->pending; 883 uci_foreach_element(&pkg->sections, e) { 884 struct uci_section *s = uci_to_section(e); 885 886 for (i = 0; i < map->n_sections; i++) { 887 struct uci_sectionmap *sm = map->sections[i]; 888 struct ucimap_section_data *sd; 889 890 if (strcmp(s->type, map->sections[i]->type) != 0) 891 continue; 892 893 if (sm->alloc) { 894 sd = sm->alloc(map, sm, s); 895 if (!sd) 896 continue; 897 memset(sd, 0, sizeof(struct ucimap_section_data)); 898 } else { 899 sd = calloc(1, sm->alloc_len); 900 if (!sd) 901 continue; 902 sd = ucimap_ptr_section(sm, sd); 903 } 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