From 8e57ddf6b61e9e95e1f319b1def18789f19f9ee1 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Wed, 30 Jan 2008 01:38:03 +0100 Subject: [PATCH] add proper history tracking for delete --- cli.c | 99 ++++++++++++++++++++++++++++++++++++------------------------------ err.h | 2 +- file.c | 19 +++++++++---- list.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++------------ uci.h | 18 +++++++++++- 5 files changed, 166 insertions(+), 69 deletions(-) diff --git a/cli.c b/cli.c index e17acb5..043ba1a 100644 --- a/cli.c +++ b/cli.c @@ -14,7 +14,14 @@ #include #include "uci.h" +static const char *appname = "uci"; + static struct uci_context *ctx; +enum { + CMD_GET, + CMD_SET, + CMD_DEL +}; static void uci_usage(int argc, char **argv) { @@ -112,88 +119,90 @@ static int uci_do_export(int argc, char **argv) return 0; } -static int uci_do_get(int argc, char **argv) +static int uci_do_cmd(int cmd, int argc, char **argv) { char *package = NULL; char *section = NULL; char *option = NULL; + char *value = NULL; struct uci_package *p = NULL; struct uci_element *e = NULL; - char *value = NULL; if (argc != 2) return 255; - if (uci_parse_tuple(ctx, argv[1], &package, §ion, &option, NULL) != UCI_OK) + if (uci_parse_tuple(ctx, argv[1], &package, §ion, &option, (cmd == CMD_SET ? &value : NULL)) != UCI_OK) return 1; if (uci_load(ctx, package, &p) != UCI_OK) { - uci_perror(ctx, "uci"); + uci_perror(ctx, appname); return 1; } if (uci_lookup(ctx, &e, p, section, option) != UCI_OK) return 1; - switch(e->type) { - case UCI_TYPE_SECTION: - value = uci_to_section(e)->type; + switch(cmd) { + case CMD_GET: + switch(e->type) { + case UCI_TYPE_SECTION: + value = uci_to_section(e)->type; + break; + case UCI_TYPE_OPTION: + value = uci_to_option(e)->value; + break; + default: + /* should not happen */ + return 1; + } + /* throw the value to stdout */ + printf("%s\n", value); break; - case UCI_TYPE_OPTION: - value = uci_to_option(e)->value; + case CMD_SET: + if (uci_set(ctx, p, section, option, value) != UCI_OK) { + uci_perror(ctx, appname); + return 1; + } + break; + case CMD_DEL: + if (uci_del(ctx, p, section, option) != UCI_OK) { + uci_perror(ctx, appname); + return 1; + } break; - default: - /* should not happen */ - return 1; } - /* throw the value to stdout */ - printf("%s\n", value); - - return 0; -} - -static int uci_do_set(int argc, char **argv) -{ - struct uci_package *p; - char *package = NULL; - char *section = NULL; - char *option = NULL; - char *value = NULL; - - if (argc != 2) - return 255; - - if (uci_parse_tuple(ctx, argv[1], &package, §ion, &option, &value) != UCI_OK) - return 1; - - if (uci_load(ctx, package, &p) != UCI_OK) { - uci_perror(ctx, "uci"); - return 1; - } + /* no save necessary for get */ + if (cmd == CMD_GET) + return 0; - if (uci_set(ctx, package, section, option, value) != UCI_OK) { - uci_perror(ctx, "uci"); - return 1; - } + /* save changes, but don't commit them yet */ if (uci_save(ctx, p) != UCI_OK) { - uci_perror(ctx, "uci"); + uci_perror(ctx, appname); return 1; } + return 0; } static int uci_cmd(int argc, char **argv) { + int cmd; + if (!strcasecmp(argv[0], "show")) return uci_show(argc, argv); if (!strcasecmp(argv[0], "export")) return uci_do_export(argc, argv); + if (!strcasecmp(argv[0], "get")) - return uci_do_get(argc, argv); - if (!strcasecmp(argv[0], "set")) - return uci_do_set(argc, argv); - return 255; + cmd = CMD_GET; + else if (!strcasecmp(argv[0], "set")) + cmd = CMD_SET; + else if (!strcasecmp(argv[0], "del")) + cmd = CMD_DEL; + else + return 255; + return uci_do_cmd(cmd, argc, argv); } int main(int argc, char **argv) diff --git a/err.h b/err.h index 078fdbe..82eba81 100644 --- a/err.h +++ b/err.h @@ -76,7 +76,7 @@ #define UCI_INTERNAL(func, ctx, ...) do { \ ctx->internal = true; \ func(ctx, __VA_ARGS__); \ -} while (0); +} while (0) /* * check the specified condition. diff --git a/file.c b/file.c index a0fe58b..7a57612 100644 --- a/file.c +++ b/file.c @@ -580,7 +580,7 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package * } UCI_INTERNAL(uci_parse_tuple, ctx, buf, &package, §ion, &option, &value); - if (!package || !section || !value) + if (!package || !section || (!delete && !value)) goto error; if (strcmp(package, p->e.name) != 0) goto error; @@ -588,10 +588,13 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package * goto error; if (option && !uci_validate_name(option)) goto error; - if (!delete) - UCI_INTERNAL(uci_set, ctx, package, section, option, value); - return; + if (delete) + UCI_INTERNAL(uci_del, ctx, p, section, option); + else + UCI_INTERNAL(uci_set, ctx, p, section, option, value); + + return; error: UCI_THROW(ctx, UCI_ERR_PARSE); } @@ -724,12 +727,18 @@ int uci_save(struct uci_context *ctx, struct uci_package *p) uci_foreach_element_safe(&p->history, tmp, e) { struct uci_history *h = uci_to_history(e); + if (h->cmd == UCI_CMD_REMOVE) fprintf(f, "-"); + fprintf(f, "%s.%s", p->e.name, h->section); if (e->name) fprintf(f, ".%s", e->name); - fprintf(f, "=%s\n", h->value); + + if (h->cmd == UCI_CMD_REMOVE) + fprintf(f, "\n"); + else + fprintf(f, "=%s\n", h->value); uci_list_del(&e->list); } diff --git a/list.c b/list.c index 19fe8c5..fb5e686 100644 --- a/list.c +++ b/list.c @@ -171,15 +171,20 @@ static inline void uci_add_history(struct uci_context *ctx, struct uci_package *p, int cmd, char *section, char *option, char *value) { struct uci_history *h; - int size = 0; + int size = strlen(section) + 1; char *ptr; - h = uci_alloc_element(ctx, history, option, strlen(section) + strlen(value) + 2); + if (value) + size += strlen(section) + 1; + + h = uci_alloc_element(ctx, history, option, size); ptr = uci_dataptr(h); h->cmd = cmd; h->section = strcpy(ptr, section); - ptr += strlen(ptr) + 1; - h->value = strcpy(ptr, value); + if (value) { + ptr += strlen(ptr) + 1; + h->value = strcpy(ptr, value); + } uci_list_add(&p->history, &h->e.list); } @@ -222,6 +227,53 @@ notfound: return 0; } +int uci_del_element(struct uci_context *ctx, struct uci_element *e) +{ + bool internal = ctx->internal; + struct uci_package *p = NULL; + struct uci_section *s = NULL; + struct uci_option *o = NULL; + struct uci_element *i, *tmp; + char *option = NULL; + + UCI_HANDLE_ERR(ctx); + UCI_ASSERT(ctx, e != NULL); + + switch(e->type) { + case UCI_TYPE_SECTION: + s = uci_to_section(e); + uci_foreach_element_safe(&s->options, tmp, i) { + uci_del_element(ctx, i); + } + break; + case UCI_TYPE_OPTION: + o = uci_to_option(e); + s = o->section; + p = s->package; + option = e->name; + break; + default: + UCI_THROW(ctx, UCI_ERR_INVAL); + break; + } + + p = s->package; + if (!internal) + uci_add_history(ctx, p, UCI_CMD_REMOVE, s->e.name, option, NULL); + + switch(e->type) { + case UCI_TYPE_SECTION: + uci_free_section(s); + break; + case UCI_TYPE_OPTION: + uci_free_option(o); + break; + default: + break; + } + return 0; +} + int uci_set_element_value(struct uci_context *ctx, struct uci_element **element, char *value) { bool internal = ctx->internal; @@ -291,17 +343,36 @@ int uci_set_element_value(struct uci_context *ctx, struct uci_element **element, return 0; } -int uci_set(struct uci_context *ctx, char *package, char *section, char *option, char *value) +int uci_del(struct uci_context *ctx, struct uci_package *p, char *section, char *option) { + bool internal = ctx->internal; struct uci_element *e; - struct uci_package *p = NULL; struct uci_section *s = NULL; struct uci_option *o = NULL; - struct uci_history *h; + + UCI_HANDLE_ERR(ctx); + UCI_ASSERT(ctx, p != NULL); + UCI_ASSERT(ctx, section != NULL); + + UCI_INTERNAL(uci_lookup, ctx, &e, p, section, option); + + if (!internal) + return uci_del_element(ctx, e); + UCI_INTERNAL(uci_del_element, ctx, e); + + return 0; +} + +int uci_set(struct uci_context *ctx, struct uci_package *p, char *section, char *option, char *value) +{ bool internal = ctx->internal; + struct uci_element *e = NULL; + struct uci_section *s = NULL; + struct uci_option *o = NULL; + struct uci_history *h; UCI_HANDLE_ERR(ctx); - UCI_ASSERT(ctx, package != NULL); + UCI_ASSERT(ctx, p != NULL); UCI_ASSERT(ctx, section != NULL); UCI_ASSERT(ctx, value != NULL); @@ -310,15 +381,7 @@ int uci_set(struct uci_context *ctx, char *package, char *section, char *option, * 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(ctx, &ctx->root, package); - if (!e) - goto notfound; - - p = uci_to_package(e); - e = uci_lookup_list(ctx, &p->sections, section); - if (!e) - goto notfound; - + UCI_INTERNAL(uci_lookup, ctx, &e, p, section, NULL); s = uci_to_section(e); if (option) { e = uci_lookup_list(ctx, &s->options, option); diff --git a/uci.h b/uci.h index 891fb3b..78a0249 100644 --- a/uci.h +++ b/uci.h @@ -173,7 +173,23 @@ extern int uci_set_element_value(struct uci_context *ctx, struct uci_element **e * @option: option name * @value: value (option) or type (section) */ -extern int uci_set(struct uci_context *ctx, char *package, char *section, char *option, char *value); +extern int uci_set(struct uci_context *ctx, struct uci_package *p, char *section, char *option, char *value); + +/** + * uci_del_element: Delete a section or option + * @ctx: uci context + * @e: element (section or option) + */ +extern int uci_del_element(struct uci_context *ctx, struct uci_element *e); + +/** + * uci_del: Delete a section or option + * @ctx: uci context + * @p: uci package + * @section: section name + * @option: option name (optional) + */ +extern int uci_del(struct uci_context *ctx, struct uci_package *p, char *section, char *option); /** * uci_save: save change history for a package -- 2.11.0