X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fuci.git;a=blobdiff_plain;f=file.c;h=553e5196355c165edb17adcf34df00d92efc6644;hp=d81bbe85995ce3cebc9c2e924698362537b009de;hb=9f540f2106dcf724e4b8c41489d4bda6ccfe65d8;hpb=818f7b8433ae369c20fc56cccbb55b22043b9024 diff --git a/file.c b/file.c index d81bbe8..553e519 100644 --- a/file.c +++ b/file.c @@ -53,165 +53,6 @@ static void uci_file_cleanup(struct uci_context *ctx) } -/* - * parse a character escaped by '\' - * returns true if the escaped character is to be parsed - * returns false if the escaped character is to be ignored - */ -static inline bool parse_backslash(struct uci_context *ctx, char **str) -{ - /* skip backslash */ - *str += 1; - - /* undecoded backslash at the end of line, fetch the next line */ - if (!**str) { - *str += 1; - uci_getln(ctx, *str - ctx->pctx->buf); - return false; - } - - /* FIXME: decode escaped char, necessary? */ - return true; -} - -/* - * move the string pointer forward until a non-whitespace character or - * EOL is reached - */ -static void skip_whitespace(struct uci_context *ctx, char **str) -{ -restart: - while (**str && isspace(**str)) - *str += 1; - - if (**str == '\\') { - if (!parse_backslash(ctx, str)) - goto restart; - } -} - -static inline void addc(char **dest, char **src) -{ - **dest = **src; - *dest += 1; - *src += 1; -} - -/* - * parse a double quoted string argument from the command line - */ -static void parse_double_quote(struct uci_context *ctx, char **str, char **target) -{ - char c; - - /* skip quote character */ - *str += 1; - - while ((c = **str)) { - switch(c) { - case '"': - **target = 0; - *str += 1; - return; - case '\\': - if (!parse_backslash(ctx, str)) - continue; - /* fall through */ - default: - addc(target, str); - break; - } - } - uci_parse_error(ctx, *str, "unterminated \""); -} - -/* - * parse a single quoted string argument from the command line - */ -static void parse_single_quote(struct uci_context *ctx, char **str, char **target) -{ - char c; - /* skip quote character */ - *str += 1; - - while ((c = **str)) { - switch(c) { - case '\'': - **target = 0; - *str += 1; - return; - default: - addc(target, str); - } - } - uci_parse_error(ctx, *str, "unterminated '"); -} - -/* - * parse a string from the command line and detect the quoting style - */ -static void parse_str(struct uci_context *ctx, char **str, char **target) -{ - do { - switch(**str) { - case '\'': - parse_single_quote(ctx, str, target); - break; - case '"': - parse_double_quote(ctx, str, target); - break; - case '#': - **str = 0; - /* fall through */ - case 0: - goto done; - case '\\': - if (!parse_backslash(ctx, str)) - continue; - /* fall through */ - default: - addc(target, str); - break; - } - } while (**str && !isspace(**str)); -done: - - /* - * if the string was unquoted and we've stopped at a whitespace - * character, skip to the next one, because the whitespace will - * be overwritten by a null byte here - */ - if (**str) - *str += 1; - - /* terminate the parsed string */ - **target = 0; -} - -/* - * extract the next argument from the command line - */ -static char *next_arg(struct uci_context *ctx, char **str, bool required, bool name) -{ - char *val; - char *ptr; - - val = ptr = *str; - skip_whitespace(ctx, str); - parse_str(ctx, str, &ptr); - if (!*val) { - if (required) - uci_parse_error(ctx, *str, "insufficient arguments"); - goto done; - } - - if (name && !uci_validate_name(val)) - uci_parse_error(ctx, val, "invalid character in field"); - -done: - return val; -} - /* * verify that the end of the line or command is reached. * throw an error if extra arguments are given on the command line @@ -221,7 +62,7 @@ static void assert_eol(struct uci_context *ctx, char **str) char *tmp; tmp = next_arg(ctx, str, false, false); - if (tmp && *tmp && (ctx->flags & UCI_FLAG_STRICT)) + if (*tmp && (ctx->flags & UCI_FLAG_STRICT)) uci_parse_error(ctx, *str, "too many arguments"); } @@ -278,50 +119,6 @@ static void uci_parse_package(struct uci_context *ctx, char **str, bool single) uci_switch_config(ctx); } -/* Based on an efficient hash function published by D. J. Bernstein */ -static unsigned int djbhash(unsigned int hash, char *str) -{ - int len = strlen(str); - int i; - - /* initial value */ - if (hash == ~0) - hash = 5381; - - for(i = 0; i < len; i++) { - hash = ((hash << 5) + hash) + str[i]; - } - return (hash & 0x7FFFFFFF); -} - -/* fix up an unnamed section */ -static void uci_fixup_section(struct uci_context *ctx, struct uci_section *s) -{ - unsigned int hash = ~0; - struct uci_element *e; - char buf[16]; - - if (!s || s->e.name) - return; - - /* - * Generate a name for unnamed sections. This is used as reference - * when locating or updating the section from apps/scripts. - * To make multiple concurrent versions somewhat safe for updating, - * the name is generated from a hash of its type and name/value - * pairs of its option, and it is prefixed by a counter value. - * If the order of the unnamed sections changes for some reason, - * updates to them will be rejected. - */ - hash = djbhash(hash, s->type); - uci_foreach_element(&s->options, e) { - hash = djbhash(hash, e->name); - hash = djbhash(hash, uci_to_option(e)->value); - } - sprintf(buf, "cfg%02x%04x", ++s->package->n_section, hash % (1 << 16)); - s->e.name = uci_strdup(ctx, buf); -} - /* * parse the 'config' uci command (open a section) */ @@ -342,13 +139,15 @@ static void uci_parse_config(struct uci_context *ctx, char **str) /* command string null-terminated by strtok */ *str += strlen(*str) + 1; - type = next_arg(ctx, str, true, true); + type = next_arg(ctx, str, true, false); + if (!uci_validate_str(type, false)) + uci_parse_error(ctx, type, "invalid character in field"); name = next_arg(ctx, str, false, true); assert_eol(ctx, str); if (pctx->merge) { UCI_TRAP_SAVE(ctx, error); - uci_set(ctx, pctx->package, name, NULL, type); + uci_set(ctx, pctx->package, name, NULL, type, NULL); UCI_TRAP_RESTORE(ctx); return; error: @@ -373,12 +172,12 @@ static void uci_parse_option(struct uci_context *ctx, char **str) *str += strlen(*str) + 1; name = next_arg(ctx, str, true, true); - value = next_arg(ctx, str, true, false); + value = next_arg(ctx, str, false, false); assert_eol(ctx, str); if (pctx->merge) { UCI_TRAP_SAVE(ctx, error); - uci_set(ctx, pctx->package, pctx->section->e.name, name, value); + uci_set(ctx, pctx->package, pctx->section->e.name, name, value, NULL); UCI_TRAP_RESTORE(ctx); return; error: @@ -521,8 +320,8 @@ int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct u /* make sure no memory from previous parse attempts is leaked */ uci_file_cleanup(ctx); - pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); - ctx->pctx = pctx; + uci_alloc_parse_context(ctx); + pctx = ctx->pctx; pctx->file = stream; if (*package && single) { pctx->package = *package; @@ -673,11 +472,13 @@ int uci_commit(struct uci_context *ctx, struct uci_package **package, bool overw /* freed together with the uci_package */ path = NULL; - /* check for updated history, just in case */ - uci_load_history(ctx, p, true); + /* check for updated history, flush */ + if (!uci_load_history(ctx, p, true)) + goto done; } else { /* flush history */ - uci_load_history(ctx, NULL, true); + if (!uci_load_history(ctx, NULL, true)) + goto done; } }