X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=history.c;h=2b6dbef64718ea319b318c577c266cdf1425952e;hp=14c650ab30383fa5fee6d9ef1d4a33122a882342;hb=e1738122f616e3dce498598d55f84fa8a7e2263b;hpb=5620bfaa14ce556b94de26128bc7fe9edc5a3f27 diff --git a/history.c b/history.c index 14c650a..2b6dbef 100644 --- a/history.c +++ b/history.c @@ -27,8 +27,8 @@ #include /* record a change that was done to a package */ -static void -uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, char *section, char *option, char *value) +void +uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, const char *section, const char *option, const char *value) { struct uci_history *h; int size = strlen(section) + 1; @@ -48,7 +48,7 @@ uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, char *s uci_list_add(list, &h->e.list); } -static void +void uci_free_history(struct uci_history *h) { if (!h) @@ -88,30 +88,50 @@ int uci_add_history_path(struct uci_context *ctx, const char *dir) return 0; } -static inline void uci_parse_history_tuple(struct uci_context *ctx, char **buf, char **package, char **section, char **option, char **value, bool *delete, bool *rename) +static inline void uci_parse_history_tuple(struct uci_context *ctx, char **buf, char **package, char **section, char **option, char **value, int *cmd) { - if (**buf == '-') { - if (delete) - *delete = true; - *buf += 1; - } else if (**buf == '@') { - if (rename) - *rename = true; - *buf += 1; + int c = UCI_CMD_CHANGE; + + switch(**buf) { + case '-': + c = UCI_CMD_REMOVE; + break; + case '@': + c = UCI_CMD_RENAME; + break; + case '+': + /* UCI_CMD_ADD is used for anonymous sections or list values */ + c = UCI_CMD_ADD; + break; + case '|': + c = UCI_CMD_LIST_ADD; + break; } + if (c != UCI_CMD_CHANGE) + *buf += 1; + + if (cmd) + *cmd = c; + UCI_INTERNAL(uci_parse_tuple, ctx, *buf, package, section, option, value); + if (!*section[0]) + UCI_THROW(ctx, UCI_ERR_PARSE); + } + static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *p, char *buf) { + struct uci_element *e = NULL; bool delete = false; bool rename = false; char *package = NULL; char *section = NULL; char *option = NULL; char *value = NULL; + int cmd; - uci_parse_history_tuple(ctx, &buf, &package, §ion, &option, &value, &delete, &rename); + uci_parse_history_tuple(ctx, &buf, &package, §ion, &option, &value, &cmd); if (!package || (strcmp(package, p->e.name) != 0)) goto error; if (!uci_validate_name(section)) @@ -121,27 +141,26 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package * if (rename && !uci_validate_str(value, (option || delete))) goto error; - if (ctx->flags & UCI_FLAG_SAVED_HISTORY) { - int cmd; - - /* NB: no distinction between CMD_CHANGE and CMD_ADD possible at this point */ - if(delete) - cmd = UCI_CMD_REMOVE; - else if (rename) - cmd = UCI_CMD_RENAME; - else - cmd = UCI_CMD_CHANGE; - + if (ctx->flags & UCI_FLAG_SAVED_HISTORY) uci_add_history(ctx, &p->saved_history, cmd, section, option, value); - } - if (rename) + switch(cmd) { + case UCI_CMD_RENAME: UCI_INTERNAL(uci_rename, ctx, p, section, option, value); - else if (delete) + break; + case UCI_CMD_REMOVE: UCI_INTERNAL(uci_delete, ctx, p, section, option); - else - UCI_INTERNAL(uci_set, ctx, p, section, option, value, NULL); - + break; + case UCI_CMD_LIST_ADD: + UCI_INTERNAL(uci_add_list, ctx, p, section, option, value, NULL); + break; + case UCI_CMD_ADD: + case UCI_CMD_CHANGE: + UCI_INTERNAL(uci_set, ctx, p, section, option, value, &e); + if (!option && e && (cmd == UCI_CMD_ADD)) + uci_to_section(e)->anonymous = true; + break; + } return; error: UCI_THROW(ctx, UCI_ERR_PARSE); @@ -154,7 +173,6 @@ static int uci_parse_history(struct uci_context *ctx, FILE *stream, struct uci_p int changes = 0; /* make sure no memory from previous parse attempts is leaked */ - ctx->internal = true; uci_cleanup(ctx); pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); @@ -179,7 +197,6 @@ error: } /* no error happened, we can get rid of the parser context now */ - ctx->internal = true; uci_cleanup(ctx); return changes; } @@ -211,7 +228,7 @@ static int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool FILE *f = NULL; int changes = 0; - if (!p->confdir) + if (!p->has_history) return 0; uci_foreach_element(&ctx->history_path, e) { @@ -233,11 +250,11 @@ static int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool if (filename) free(filename); uci_close_stream(f); - ctx->errno = 0; + ctx->err = 0; return changes; } -static void uci_filter_history(struct uci_context *ctx, const char *name, char *section, char *option) +static void uci_filter_history(struct uci_context *ctx, const char *name, const char *section, const char *option) { struct uci_parse_context *pctx; struct uci_element *e, *tmp; @@ -274,7 +291,7 @@ static void uci_filter_history(struct uci_context *ctx, const char *name, char * e = uci_alloc_generic(ctx, UCI_TYPE_HISTORY, pctx->buf, sizeof(struct uci_element)); uci_list_add(&list, &e->list); - uci_parse_history_tuple(ctx, &buf, &p, &s, &o, &v, NULL, NULL); + uci_parse_history_tuple(ctx, &buf, &p, &s, &o, &v, NULL); if (section) { if (!s || (strcmp(section, s) != 0)) continue; @@ -303,11 +320,10 @@ done: uci_foreach_element_safe(&list, tmp, e) { uci_free_element(e); } - ctx->internal = true; uci_cleanup(ctx); } -int uci_revert(struct uci_context *ctx, struct uci_package **pkg, char *section, char *option) +int uci_revert(struct uci_context *ctx, struct uci_package **pkg, const char *section, const char *option) { struct uci_package *p; char *name = NULL; @@ -316,7 +332,7 @@ int uci_revert(struct uci_context *ctx, struct uci_package **pkg, char *section, UCI_ASSERT(ctx, pkg != NULL); p = *pkg; UCI_ASSERT(ctx, p != NULL); - UCI_ASSERT(ctx, p->confdir); + UCI_ASSERT(ctx, p->has_history); /* * - flush unwritten changes @@ -335,13 +351,13 @@ int uci_revert(struct uci_context *ctx, struct uci_package **pkg, char *section, UCI_INTERNAL(uci_load, ctx, name, &p); UCI_TRAP_RESTORE(ctx); - ctx->errno = 0; + ctx->err = 0; error: if (name) free(name); - if (ctx->errno) - UCI_THROW(ctx, ctx->errno); + if (ctx->err) + UCI_THROW(ctx, ctx->err); return 0; } @@ -350,6 +366,7 @@ int uci_save(struct uci_context *ctx, struct uci_package *p) FILE *f = NULL; char *filename = NULL; struct uci_element *e, *tmp; + struct stat statbuf; UCI_HANDLE_ERR(ctx); UCI_ASSERT(ctx, p != NULL); @@ -360,29 +377,47 @@ int uci_save(struct uci_context *ctx, struct uci_package *p) * directly. * does not modify the uci_package pointer */ - if (!p->confdir) + if (!p->has_history) return uci_commit(ctx, &p, false); if (uci_list_empty(&p->history)) return 0; + if (stat(ctx->savedir, &statbuf) < 0) + mkdir(ctx->savedir, UCI_DIRMODE); + else if ((statbuf.st_mode & S_IFMT) != S_IFDIR) + UCI_THROW(ctx, UCI_ERR_IO); + if ((asprintf(&filename, "%s/%s", ctx->savedir, p->e.name) < 0) || !filename) UCI_THROW(ctx, UCI_ERR_MEM); - ctx->errno = 0; + ctx->err = 0; UCI_TRAP_SAVE(ctx, done); f = uci_open_stream(ctx, filename, SEEK_END, true, true); UCI_TRAP_RESTORE(ctx); uci_foreach_element_safe(&p->history, tmp, e) { struct uci_history *h = uci_to_history(e); + char *prefix = ""; + + switch(h->cmd) { + case UCI_CMD_REMOVE: + prefix = "-"; + break; + case UCI_CMD_RENAME: + prefix = "@"; + break; + case UCI_CMD_ADD: + prefix = "+"; + break; + case UCI_CMD_LIST_ADD: + prefix = "|"; + break; + default: + break; + } - if (h->cmd == UCI_CMD_REMOVE) - fprintf(f, "-"); - else if (h->cmd == UCI_CMD_RENAME) - fprintf(f, "@"); - - fprintf(f, "%s.%s", p->e.name, h->section); + fprintf(f, "%s%s.%s", prefix, p->e.name, h->section); if (e->name) fprintf(f, ".%s", e->name); @@ -397,8 +432,8 @@ done: uci_close_stream(f); if (filename) free(filename); - if (ctx->errno) - UCI_THROW(ctx, ctx->errno); + if (ctx->err) + UCI_THROW(ctx, ctx->err); return 0; }