ucimap: add support for saving lists to uci
[project/uci.git] / ucimap.c
index 0d16bb4..4621ebf 100644 (file)
--- a/ucimap.c
+++ b/ucimap.c
@@ -103,6 +103,12 @@ ucimap_section_ptr(struct ucimap_section_data *sd)
        return ((char *) sd - sd->sm->smap_offset);
 }
 
+static inline struct ucimap_section_data *
+ucimap_ptr_section(struct uci_sectionmap *sm, void *ptr) {
+       ptr = (char *) ptr + sm->smap_offset;
+       return ptr;
+}
+
 static inline union ucimap_data *
 ucimap_get_data(struct ucimap_section_data *sd, struct uci_optmap *om)
 {
@@ -730,6 +736,53 @@ ucimap_set_changed(struct ucimap_section_data *sd, void *field)
        }
 }
 
+static char *
+ucimap_data_to_string(struct ucimap_section_data *sd, struct uci_optmap *om, union ucimap_data *data)
+{
+       static char buf[32];
+       char *str = NULL;
+
+       switch(om->type & UCIMAP_SUBTYPE) {
+       case UCIMAP_STRING:
+               str = data->s;
+               break;
+       case UCIMAP_INT:
+               sprintf(buf, "%d", data->i);
+               str = buf;
+               break;
+       case UCIMAP_BOOL:
+               sprintf(buf, "%d", !!data->b);
+               str = buf;
+               break;
+       case UCIMAP_SECTION:
+               if (data->ptr)
+                       str = (char *) ucimap_ptr_section(om->data.sm, data->ptr)->section_name;
+               else
+                       str = "";
+               break;
+       case UCIMAP_CUSTOM:
+               break;
+       default:
+               return NULL;
+       }
+
+       if (om->format) {
+               union ucimap_data tdata;
+
+               if (ucimap_is_custom(om->type)) {
+                       tdata.s = (char *)data;
+                       data = &tdata;
+               }
+
+               if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
+                       return NULL;
+
+               if (!str)
+                       str = "";
+       }
+       return str;
+}
+
 int
 ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_section_data *sd)
 {
@@ -752,57 +805,41 @@ ucimap_store_section(struct uci_map *map, struct uci_package *p, struct ucimap_s
 
        ucimap_foreach_option(sm, om) {
                union ucimap_data *data;
-               static char buf[32];
-               char *str = NULL;
 
                i++;
-               if (ucimap_is_list(om->type))
-                       continue;
-
                data = ucimap_get_data(sd, om);
                if (!TEST_BIT(sd->cmap, i - 1))
                        continue;
 
                ucimap_fill_ptr(&ptr, s, om->name);
-               switch(om->type & UCIMAP_SUBTYPE) {
-               case UCIMAP_STRING:
-                       str = data->s;
-                       break;
-               case UCIMAP_INT:
-                       sprintf(buf, "%d", data->i);
-                       str = buf;
-                       break;
-               case UCIMAP_BOOL:
-                       sprintf(buf, "%d", !!data->b);
-                       str = buf;
-                       break;
-               case UCIMAP_CUSTOM:
-                       break;
-               default:
-                       continue;
-               }
-               if (om->format) {
-                       union ucimap_data tdata, *data;
+               if (ucimap_is_list(om->type)) {
+                       struct ucimap_list *list = data->list;
+                       bool first = true;
+                       int j;
 
-                       data = ucimap_get_data(sd, om);
-                       if (ucimap_is_custom(om->type)) {
-                               tdata.s = (char *)data;
-                               data = &tdata;
-                       }
+                       for (j = 0; j < list->n_items; j++) {
+                               ptr.value = ucimap_data_to_string(sd, om, &list->item[j]);
+                               if (!ptr.value)
+                                       continue;
 
-                       if (om->format(ucimap_section_ptr(sd), om, data, &str) < 0)
+                               if (first) {
+                                       ret = uci_set(s->package->ctx, &ptr);
+                                       first = false;
+                               } else {
+                                       ret = uci_add_list(s->package->ctx, &ptr);
+                               }
+                               if (ret)
+                                       return ret;
+                       }
+               } else {
+                       ptr.value = ucimap_data_to_string(sd, om, data);
+                       if (!ptr.value)
                                continue;
 
-                       if (!str)
-                               str = "";
+                       ret = uci_set(s->package->ctx, &ptr);
+                       if (ret)
+                               return ret;
                }
-               if (!str)
-                       continue;
-               ptr.value = str;
-
-               ret = uci_set(s->package->ctx, &ptr);
-               if (ret)
-                       return ret;
 
                CLR_BIT(sd->cmap, i - 1);
        }