uci: properly close input before exit
[project/uci.git] / file.c
diff --git a/file.c b/file.c
index 8d4408d..81047a4 100644 (file)
--- a/file.c
+++ b/file.c
@@ -48,8 +48,8 @@ __private void uci_getln(struct uci_context *ctx, int offset)
                pctx->buf = uci_malloc(ctx, LINEBUF);
                pctx->bufsz = LINEBUF;
        }
-       /* `offset' may off by one */
-       if (offset >= pctx->bufsz) {
+       /* It takes 2 slots for fgets to read 1 char. */
+       if (offset >= pctx->bufsz - 1) {
                pctx->bufsz *= 2;
                pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz);
        }
@@ -90,11 +90,11 @@ static bool parse_backslash(struct uci_context *ctx)
        pctx->pos += 1;
 
        /* undecoded backslash at the end of line, fetch the next line */
-       if (!pctx_cur_char(pctx)
-                   || pctx_cur_char(pctx) == '\n'
-                   || (pctx_cur_char(pctx) == '\r' &&
-                       pctx_char(pctx, pctx_pos(pctx) + 1) == '\n' &&
-                       !pctx_char(pctx, pctx_pos(pctx) + 2))) {
+       if (!pctx_cur_char(pctx) ||
+           pctx_cur_char(pctx) == '\n' ||
+           (pctx_cur_char(pctx) == '\r' &&
+            pctx_char(pctx, pctx_pos(pctx) + 1) == '\n' &&
+            !pctx_char(pctx, pctx_pos(pctx) + 2))) {
                uci_getln(ctx, pctx->pos);
                return false;
        }
@@ -157,7 +157,6 @@ static void parse_double_quote(struct uci_context *ctx, int *target)
                        break;
                }
        }
-       uci_parse_error(ctx, "unterminated \"");
 }
 
 /*
@@ -179,15 +178,14 @@ static void parse_single_quote(struct uci_context *ctx, int *target)
                case 0:
                        /* Multi-line str value */
                        uci_getln(ctx, pctx->pos);
-                       if (!pctx_cur_char(pctx)) {
-                               uci_parse_error(ctx, "EOF with unterminated \"");
-                       }
+                       if (!pctx_cur_char(pctx))
+                               uci_parse_error(ctx, "EOF with unterminated '");
+
                        break;
                default:
                        addc(ctx, target, &pctx->pos);
                }
        }
-       uci_parse_error(ctx, "unterminated '");
 }
 
 /*
@@ -239,14 +237,14 @@ done:
 /*
  * extract the next argument from the command line
  */
-static char *next_arg(struct uci_context *ctx, bool required, bool name)
+static int next_arg(struct uci_context *ctx, bool required, bool name, bool package)
 {
        struct uci_parse_context *pctx = ctx->pctx;
        int val, ptr;
 
        skip_whitespace(ctx);
        val = ptr = pctx_pos(pctx);
-       if(pctx_cur_char(pctx) == ';') {
+       if (pctx_cur_char(pctx) == ';') {
                pctx_cur_char(pctx) = 0;
                pctx->pos += 1;
        } else {
@@ -258,15 +256,17 @@ static char *next_arg(struct uci_context *ctx, bool required, bool name)
                goto done;
        }
 
-       if (name && !uci_validate_name(pctx_str(pctx, val)))
+       if (name && !uci_validate_str(pctx_str(pctx, val), name, package))
                uci_parse_error(ctx, "invalid character in name field");
 
 done:
-       return pctx_str(pctx, val);
+       return val;
 }
 
 int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result)
 {
+       int ofs_result;
+
        UCI_HANDLE_ERR(ctx);
        UCI_ASSERT(ctx, str != NULL);
        UCI_ASSERT(ctx, result != NULL);
@@ -278,15 +278,14 @@ int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char *
                uci_alloc_parse_context(ctx);
 
        ctx->pctx->file = stream;
-
        if (!*str) {
+               ctx->pctx->pos = 0;
                uci_getln(ctx, 0);
-               *str = ctx->pctx->buf;
-       } else {
-               UCI_ASSERT(ctx, ctx->pctx->pos == *str - ctx->pctx->buf);
        }
 
-       *result = next_arg(ctx, false, false);
+       ofs_result = next_arg(ctx, false, false, false);
+       *result = pctx_str(ctx->pctx, ofs_result);
+       *str = pctx_cur_str(ctx->pctx);
 
        return 0;
 }
@@ -335,9 +334,11 @@ fill_package:
 static void assert_eol(struct uci_context *ctx)
 {
        char *tmp;
+       int ofs_tmp;
 
        skip_whitespace(ctx);
-       tmp = next_arg(ctx, false, false);
+       ofs_tmp = next_arg(ctx, false, false, false);
+       tmp = pctx_str(ctx->pctx, ofs_tmp);
        if (*tmp && (ctx->flags & UCI_FLAG_STRICT))
                uci_parse_error(ctx, "too many arguments");
 }
@@ -383,12 +384,14 @@ static void uci_switch_config(struct uci_context *ctx)
 static void uci_parse_package(struct uci_context *ctx, bool single)
 {
        struct uci_parse_context *pctx = ctx->pctx;
-       char *name = NULL;
+       int ofs_name;
+       char *name;
 
        /* command string null-terminated by strtok */
        pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
 
-       name = next_arg(ctx, true, true);
+       ofs_name = next_arg(ctx, true, true, true);
+       name = pctx_str(pctx, ofs_name);
        assert_eol(ctx);
        if (single)
                return;
@@ -405,8 +408,9 @@ static void uci_parse_config(struct uci_context *ctx)
        struct uci_parse_context *pctx = ctx->pctx;
        struct uci_element *e;
        struct uci_ptr ptr;
-       char *name = NULL;
-       char *type = NULL;
+       int ofs_name, ofs_type;
+       char *name;
+       char *type;
 
        uci_fixup_section(ctx, ctx->pctx->section);
        if (!ctx->pctx->package) {
@@ -419,10 +423,14 @@ static void uci_parse_config(struct uci_context *ctx)
        /* command string null-terminated by strtok */
        pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
 
-       type = next_arg(ctx, true, false);
+       ofs_type = next_arg(ctx, true, false, false);
+       type = pctx_str(pctx, ofs_type);
        if (!uci_validate_type(type))
                uci_parse_error(ctx, "invalid character in type field");
-       name = next_arg(ctx, false, true);
+
+       ofs_name = next_arg(ctx, false, true, false);
+       type = pctx_str(pctx, ofs_type);
+       name = pctx_str(pctx, ofs_name);
        assert_eol(ctx);
 
        if (!name || !name[0]) {
@@ -450,6 +458,7 @@ static void uci_parse_option(struct uci_context *ctx, bool list)
        struct uci_parse_context *pctx = ctx->pctx;
        struct uci_element *e;
        struct uci_ptr ptr;
+       int ofs_name, ofs_value;
        char *name = NULL;
        char *value = NULL;
 
@@ -459,8 +468,10 @@ static void uci_parse_option(struct uci_context *ctx, bool list)
        /* command string null-terminated by strtok */
        pctx->pos += strlen(pctx_cur_str(pctx)) + 1;
 
-       name = next_arg(ctx, true, true);
-       value = next_arg(ctx, false, false);
+       ofs_name = next_arg(ctx, true, true, false);
+       ofs_value = next_arg(ctx, false, false, false);
+       name = pctx_str(pctx, ofs_name);
+       value = pctx_str(pctx, ofs_value);
        assert_eol(ctx);
 
        uci_fill_ptr(ctx, &ptr, &pctx->section->e);