make uci_errstr const
[project/uci.git] / parse.c
diff --git a/parse.c b/parse.c
index b6ee734..3a8a2ca 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -80,12 +80,19 @@ static void uci_parse_cleanup(struct uci_context *ctx)
        free(pctx);
 }
 
+/*
+ * move the string pointer forward until a non-whitespace character or
+ * EOL is reached
+ */
 static void skip_whitespace(char **str)
 {
        while (**str && isspace(**str))
                *str += 1;
 }
 
+/*
+ * parse a double quoted string argument from the command line
+ */
 static char *parse_double_quote(char **str)
 {
        char *val;
@@ -112,12 +119,18 @@ static char *parse_double_quote(char **str)
        return NULL;
 }
 
+/*
+ * parse a single quoted string argument from the command line
+ */
 static char *parse_single_quote(char **str)
 {
        /* TODO: implement */
        return NULL;
 }
 
+/*
+ * extract the next word from the command line (unquoted argument)
+ */
 static char *parse_unquoted(char **str)
 {
        char *val;
@@ -126,28 +139,60 @@ static char *parse_unquoted(char **str)
 
        while (**str && !isspace(**str))
                *str += 1;
-       **str = 0;
-       *str += 1;
+
+       if (**str) {
+               **str = 0;
+               *str += 1;
+       }
 
        return val;
 }
 
-static char *next_arg(char **str)
+/*
+ * extract the next argument from the command line
+ */
+static char *next_arg(struct uci_context *ctx, char **str, bool required)
 {
+       char *val;
        skip_whitespace(str);
 
        switch (**str) {
                case '"':
-                       return parse_double_quote(str);
+                       val = parse_double_quote(str);
                case '\'':
-                       return parse_single_quote(str);
+                       val = parse_single_quote(str);
                case 0:
-                       return NULL;
+                       val = NULL;
                default:
-                       return parse_unquoted(str);
+                       val = parse_unquoted(str);
+       }
+       
+       if (required && !val) {
+               ctx->pctx->byte = *str - ctx->pctx->buf;
+               UCI_THROW(ctx, UCI_ERR_PARSE);
+       }
+
+       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
+ */ 
+static void assert_eol(struct uci_context *ctx, char **str)
+{
+       char *tmp;
+
+       tmp = next_arg(ctx, str, false);
+       if (tmp) {
+               ctx->pctx->byte = tmp - ctx->pctx->buf;
+               UCI_THROW(ctx, UCI_ERR_PARSE);
        }
 }
 
+/*
+ * parse the 'config' uci command (open a section)
+ */
 static void uci_parse_config(struct uci_context *ctx, char **str)
 {
        char *type, *name;
@@ -159,37 +204,32 @@ static void uci_parse_config(struct uci_context *ctx, char **str)
                UCI_THROW(ctx, UCI_ERR_PARSE);
        }
 
-       type = next_arg(str);
-       if (!type) {
-               ctx->pctx->byte = *str - ctx->pctx->buf;
-               UCI_THROW(ctx, UCI_ERR_PARSE);
-       }
-               
-       name = next_arg(str);
+       type = next_arg(ctx, str, true);
+       name = next_arg(ctx, str, false);
+       assert_eol(ctx, str);   
+
        DPRINTF("Section<%s>: %s\n", type, name);
 }
 
+/*
+ * parse the 'option' uci command (open a value)
+ */
 static void uci_parse_option(struct uci_context *ctx, char **str)
 {
        char *name, *value;
        
        *str += strlen(*str) + 1;
        
-       name = next_arg(str);
-       if (!name) {
-               ctx->pctx->byte = *str - ctx->pctx->buf;
-               UCI_THROW(ctx, UCI_ERR_PARSE);
-       }
-
-       value = next_arg(str);
-       if (!value) {
-               ctx->pctx->byte = *str - ctx->pctx->buf;
-               UCI_THROW(ctx, UCI_ERR_PARSE);
-       }
+       name = next_arg(ctx, str, true);
+       value = next_arg(ctx, str, true);
+       assert_eol(ctx, str);   
 
        DPRINTF("\tOption: %s=\"%s\"\n", name, value);
 }
 
+/*
+ * parse a complete input line, split up combined commands by ';'
+ */
 static void uci_parse_line(struct uci_context *ctx)
 {
        struct uci_parse_context *pctx = ctx->pctx;