clean up uci_set
authorFelix Fietkau <nbd@pi.lan>
Fri, 22 Aug 2008 20:02:20 +0000 (22:02 +0200)
committerFelix Fietkau <nbd@pi.lan>
Fri, 22 Aug 2008 20:02:20 +0000 (22:02 +0200)
cli.c
file.c
history.c
list.c
uci.h

diff --git a/cli.c b/cli.c
index a1f4ce35f97a10bba7f00561d8b1cb4eed915efb..b7071a11c3874dff8fbbcf19ce7629e35704593f 100644 (file)
--- a/cli.c
+++ b/cli.c
@@ -357,7 +357,7 @@ static int uci_do_section_cmd(int cmd, int argc, char **argv)
                ret = uci_revert(ctx, &ptr);
                break;
        case CMD_SET:
-               ret = uci_set(ctx, ptr.p, ptr.section, ptr.option, ptr.value, NULL);
+               ret = uci_set(ctx, &ptr);
                break;
        case CMD_ADD_LIST:
                ret = uci_add_list(ctx, &ptr);
diff --git a/file.c b/file.c
index 04ef91e5e2193e5cda74536053ec12ba0575de84..a58ac559e55aedda25730ea2a0d4a86f978d5e53 100644 (file)
--- a/file.c
+++ b/file.c
@@ -102,6 +102,8 @@ static void uci_parse_package(struct uci_context *ctx, char **str, bool single)
 static void uci_parse_config(struct uci_context *ctx, char **str)
 {
        struct uci_parse_context *pctx = ctx->pctx;
+       struct uci_element *e;
+       struct uci_ptr ptr;
        char *name = NULL;
        char *type = NULL;
 
@@ -122,46 +124,36 @@ static void uci_parse_config(struct uci_context *ctx, char **str)
        name = next_arg(ctx, str, false, true);
        assert_eol(ctx, str);
 
-       if (pctx->merge) {
-               UCI_NESTED(uci_set, ctx, pctx->package, name, NULL, type, NULL);
-       } else
-               pctx->section = uci_alloc_section(pctx->package, type, name);
+       if (!name) {
+               ctx->internal = !pctx->merge;
+               UCI_NESTED(uci_add_section, ctx, pctx->package, type, &pctx->section);
+       } else {
+               UCI_NESTED(uci_fill_ptr, ctx, &ptr, &pctx->package->e, false);
+               e = uci_lookup_list(&pctx->package->sections, name);
+               if (e)
+                       ptr.s = uci_to_section(e);
+               ptr.section = name;
+               ptr.value = type;
+
+               ctx->internal = !pctx->merge;
+               UCI_NESTED(uci_set, ctx, &ptr);
+               pctx->section = uci_to_section(ptr.last);
+       }
 }
 
 /*
  * parse the 'option' uci command (open a value)
  */
-static void uci_parse_option(struct uci_context *ctx, char **str)
-{
-       struct uci_parse_context *pctx = ctx->pctx;
-       char *name = NULL;
-       char *value = NULL;
-
-       if (!pctx->section)
-               uci_parse_error(ctx, *str, "option command found before the first section");
-
-       /* command string null-terminated by strtok */
-       *str += strlen(*str) + 1;
-
-       name = next_arg(ctx, str, true, true);
-       value = next_arg(ctx, str, false, false);
-       assert_eol(ctx, str);
-
-       if (pctx->merge) {
-               UCI_NESTED(uci_set, ctx, pctx->package, pctx->section->e.name, name, value, NULL);
-       } else
-               uci_alloc_option(pctx->section, name, value);
-}
-
-static void uci_parse_list(struct uci_context *ctx, char **str)
+static void uci_parse_option(struct uci_context *ctx, char **str, bool list)
 {
        struct uci_parse_context *pctx = ctx->pctx;
+       struct uci_element *e;
        struct uci_ptr ptr;
        char *name = NULL;
        char *value = NULL;
 
        if (!pctx->section)
-               uci_parse_error(ctx, *str, "list command found before the first section");
+               uci_parse_error(ctx, *str, "option/list command found before the first section");
 
        /* command string null-terminated by strtok */
        *str += strlen(*str) + 1;
@@ -171,16 +163,19 @@ static void uci_parse_list(struct uci_context *ctx, char **str)
        assert_eol(ctx, str);
 
        UCI_NESTED(uci_fill_ptr, ctx, &ptr, &pctx->section->e, false);
+       e = uci_lookup_list(&pctx->section->options, name);
+       if (e)
+               ptr.o = uci_to_option(e);
        ptr.option = name;
        ptr.value = value;
 
-       UCI_INTERNAL(uci_lookup_ptr, ctx, &ptr, NULL, false);
-
        ctx->internal = !pctx->merge;
-       UCI_NESTED(uci_add_list, ctx, &ptr);
+       if (list)
+               UCI_NESTED(uci_add_list, ctx, &ptr);
+       else
+               UCI_NESTED(uci_set, ctx, &ptr);
 }
 
-
 /*
  * parse a complete input line, split up combined commands by ';'
  */
@@ -214,13 +209,13 @@ static void uci_parse_line(struct uci_context *ctx, bool single)
                                break;
                        case 'o':
                                if ((word[1] == 0) || !strcmp(word + 1, "ption"))
-                                       uci_parse_option(ctx, &word);
+                                       uci_parse_option(ctx, &word, false);
                                else
                                        goto invalid;
                                break;
                        case 'l':
                                if ((word[1] == 0) || !strcmp(word + 1, "ist"))
-                                       uci_parse_list(ctx, &word);
+                                       uci_parse_option(ctx, &word, true);
                                else
                                        goto invalid;
                                break;
index ae66f66c0f60ff8bcc4e54a283e83b48793ce252..1fe2900821a8d8a10715ff73eced4357a6d066ce 100644 (file)
--- a/history.c
+++ b/history.c
@@ -160,7 +160,8 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *
                break;
        case UCI_CMD_ADD:
        case UCI_CMD_CHANGE:
-               UCI_INTERNAL(uci_set, ctx, p, ptr.section, ptr.option, ptr.value, &e);
+               UCI_INTERNAL(uci_set, ctx, &ptr);
+               e = ptr.last;
                if (!ptr.option && e && (cmd == UCI_CMD_ADD))
                        uci_to_section(e)->anonymous = true;
                break;
diff --git a/list.c b/list.c
index 83f016e858b418d48cb550b81faa48e42f95ac5b..0cb6daded734eb2a85c04ebc535308616c02ec99 100644 (file)
--- a/list.c
+++ b/list.c
@@ -48,6 +48,12 @@ static inline void uci_list_del(struct uci_list *ptr)
        uci_list_init(ptr);
 }
 
+static inline void uci_list_fixup(struct uci_list *ptr)
+{
+       ptr->prev->next = ptr;
+       ptr->next->prev = ptr;
+}
+
 /* 
  * uci_alloc_generic allocates a new uci_element with payload
  * payload is appended to the struct to save memory and reduce fragmentation
@@ -496,103 +502,6 @@ static void uci_add_element_list(struct uci_context *ctx, struct uci_ptr *ptr, b
        uci_list_add(&ptr->o->v.list, &e->list);
 }
 
-int uci_set_element_value(struct uci_context *ctx, struct uci_element **element, const char *value)
-{
-       /* NB: UCI_INTERNAL use means without history tracking */
-       bool internal = ctx->internal;
-       struct uci_list *list;
-       struct uci_element *e;
-       struct uci_package *p;
-       struct uci_section *s;
-       struct uci_option *o;
-       char *section;
-       char *option;
-       char *str;
-       int size = 0;
-
-       UCI_HANDLE_ERR(ctx);
-       UCI_ASSERT(ctx, (element != NULL) && (*element != NULL));
-
-       /* what the 'value' of an element means depends on the type
-        * for a section, the 'value' means its type
-        * for an option, the 'value' means its value string
-        * when changing the value, shrink the element to its actual size
-        * (it may have been allocated with a bigger size, to include
-        *  its buffer)
-        * then duplicate the string passed on the command line and
-        * insert it into the structure.
-        */
-       e = *element;
-       list = e->list.prev;
-
-       switch(e->type) {
-       case UCI_TYPE_SECTION:
-               UCI_ASSERT(ctx, uci_validate_str(value, false));
-               size = sizeof(struct uci_section);
-               s = uci_to_section(e);
-               section = e->name;
-               option = NULL;
-               /* matches the currently set value */
-               if (!strcmp(value, s->type))
-                       return 0;
-               break;
-
-       case UCI_TYPE_OPTION:
-               UCI_ASSERT(ctx, value != NULL);
-               o = uci_to_option(e);
-               s = o->section;
-               section = s->e.name;
-               option = o->e.name;
-               switch(o->type) {
-               case UCI_TYPE_STRING:
-                       size = sizeof(struct uci_option);
-                       /* matches the currently set value */
-                       if (!strcmp(value, o->v.string))
-                               return 0;
-                       break;
-               default:
-                       /* default action for non-string datatypes is to delete
-                        * the existing entry, then re-create it as a string */
-                       break;
-               }
-               break;
-
-       default:
-               UCI_THROW(ctx, UCI_ERR_INVAL);
-               return 0;
-       }
-       p = s->package;
-       if (!internal && p->has_history)
-               uci_add_history(ctx, &p->history, UCI_CMD_CHANGE, section, option, value);
-
-       if ((e->type == UCI_TYPE_OPTION) && (size == 0)) {
-               o = uci_alloc_option(s, option, value);
-               uci_free_any(&e);
-               *element = &o->e;
-               goto done;
-       }
-
-       uci_list_del(&e->list);
-       e = uci_realloc(ctx, e, size);
-       str = uci_strdup(ctx, value);
-       uci_list_insert(list, &e->list);
-       *element = e;
-
-       switch(e->type) {
-       case UCI_TYPE_SECTION:
-               uci_to_section(e)->type = str;
-               break;
-       case UCI_TYPE_OPTION:
-               uci_to_option(e)->v.string = str;
-               break;
-       default:
-               break;
-       }
-
-done:
-       return 0;
-}
-
 int uci_rename(struct uci_context *ctx, struct uci_ptr *ptr)
 {
        /* NB: UCI_INTERNAL use means without history tracking */
@@ -698,85 +607,48 @@ int uci_add_list(struct uci_context *ctx, struct uci_ptr *ptr)
        return 0;
 }
 
-int uci_set(struct uci_context *ctx, struct uci_package *p, const char *section, const char *option, const char *value, struct uci_element **result)
+int uci_set(struct uci_context *ctx, struct uci_ptr *ptr)
 {
        /* NB: UCI_INTERNAL use means without history tracking */
        bool internal = ctx->internal;
-       struct uci_element *e = NULL;
-       struct uci_section *s = NULL;
-       struct uci_option *o = NULL;
 
        UCI_HANDLE_ERR(ctx);
-       UCI_ASSERT(ctx, p != NULL);
-       UCI_ASSERT(ctx, uci_validate_name(section));
-       if (option) {
-               UCI_ASSERT(ctx, uci_validate_name(option));
-               UCI_ASSERT(ctx, value != NULL);
-       } else {
-               UCI_ASSERT(ctx, uci_validate_str(value, false));
-       }
-
-       /*
-        * look up the package, section and option (if set)
-        * if the section/option is to be modified and it is not found
-        * create a new element in the appropriate list
-        */
-       e = uci_lookup_list(&p->sections, section);
-       if (!e)
-               goto notfound;
-
-       s = uci_to_section(e);
-       if (ctx->pctx && ctx->pctx->merge)
-               ctx->pctx->section = s;
-
-       if (option) {
-               e = uci_lookup_list(&s->options, option);
-               if (!e)
-                       goto notfound;
-               o = uci_to_option(e);
+       expand_ptr(ctx, ptr, false);
+       UCI_ASSERT(ctx, ptr->value);
+       UCI_ASSERT(ctx, ptr->s || (!ptr->option && ptr->section));
+       if (!ptr->option) {
+               UCI_ASSERT(ctx, uci_validate_str(ptr->value, false));
        }
 
-       /* 
-        * no unknown element was supplied, assume that we can just update 
-        * an existing entry
-        */
-       if (o)
-               e = &o->e;
-       else
-               e = &s->e;
-       if (result)
-               *result = e;
-       else
-               result = &e;
-
-       ctx->internal = internal;
-       return uci_set_element_value(ctx, result, value);
-
-notfound:
-       /* 
-        * the entry that we need to update was not found,
-        * check if the search failed prematurely.
-        * this can happen if the package was not found, or if
-        * an option was supplied, but the section wasn't found
-        */
-       if (!p || (!s && option))
-               UCI_THROW(ctx, UCI_ERR_NOTFOUND);
-
-       /* now add the missing entry */
-       if (!internal && p->has_history)
-               uci_add_history(ctx, &p->history, UCI_CMD_CHANGE, section, option, value);
-       if (s) {
-               o = uci_alloc_option(s, option, value);
-               if (result)
-                       *result = &o->e;
+       if (!ptr->o && ptr->option) { /* new option */
+               ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
+               ptr->last = &ptr->o->e;
+       } else if (!ptr->s && ptr->section) { /* new section */
+               ptr->s = uci_alloc_section(ptr->p, ptr->value, ptr->section);
+               ptr->last = &ptr->s->e;
+       } else if (ptr->o && ptr->option) { /* update option */
+               uci_free_option(ptr->o);
+               ptr->o = uci_alloc_option(ptr->s, ptr->option, ptr->value);
+               ptr->last = &ptr->o->e;
+       } else if (ptr->s && ptr->section) { /* update section */
+               char *s = uci_strdup(ctx, ptr->value);
+
+               if (ptr->s->type == uci_dataptr(ptr->s)) {
+                       ptr->last = NULL;
+                       ptr->last = uci_realloc(ctx, ptr->s, sizeof(struct uci_section));
+                       ptr->s = uci_to_section(ptr->last);
+                       uci_list_fixup(&ptr->s->e.list);
+               } else {
+                       free(ptr->s->type);
+               }
+               ptr->s->type = s;
        } else {
-               s = uci_alloc_section(p, value, section);
-               if (result)
-                       *result = &s->e;
-               if (ctx->pctx && ctx->pctx->merge)
-                       ctx->pctx->section = s;
+               UCI_THROW(ctx, UCI_ERR_INVAL);
        }
 
+       if (!internal && ptr->p->has_history)
+               uci_add_history(ctx, &ptr->p->history, UCI_CMD_CHANGE, ptr->section, ptr->option, ptr->value);
+
        return 0;
 }
 
diff --git a/uci.h b/uci.h
index 7866a75053daecf1e66a117e937f5c1ccb22af9b..66ad752c395725ad94d9a859bcb3c654763f3743 100644 (file)
--- a/uci.h
+++ b/uci.h
@@ -148,27 +148,14 @@ extern int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *st
  */
 extern int uci_add_section(struct uci_context *ctx, struct uci_package *p, const char *type, struct uci_section **res);
 
-/**
- * uci_set_element_value: Replace an element's value with a new one
- * @ctx: uci context
- * @element: pointer to an uci_element struct pointer
- * @value: new value
- * 
- * Only valid for uci_option and uci_section. Will replace the type string
- * when used with an uci_section
- */
-extern int uci_set_element_value(struct uci_context *ctx, struct uci_element **element, const char *value);
-
 /**
  * uci_set: Set an element's value; create the element if necessary
  * @ctx: uci context
- * @package: package name
- * @section: section name
- * @option: option name
- * @value: value (option) or type (section)
- * @result: store the updated element in this variable (optional)
+ * @ptr: uci pointer 
+ *
+ * The updated/created element is stored in ptr->last
  */
-extern int uci_set(struct uci_context *ctx, struct uci_package *p, const char *section, const char *option, const char *value, struct uci_element **result);
+extern int uci_set(struct uci_context *ctx, struct uci_ptr *ptr);
 
 /**
  * uci_add_list: Append a string to an element list