more error handling
[project/uci.git] / parse.c
diff --git a/parse.c b/parse.c
index 9c9dc59461592b637e744509108eb5ca3c430011..a0a3ec83d36a8ac553903e819b0ba33dfac93d61 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -11,7 +11,7 @@
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  */
+
 /*
  * This file contains the code for parsing uci config files
  */
@@ -34,7 +34,7 @@ static void uci_getln(struct uci_context *ctx)
                pctx->buf = uci_malloc(ctx, LINEBUF);
                pctx->bufsz = LINEBUF;
        }
-       
+
        ofs = 0;
        do {
                p = &pctx->buf[ofs];
@@ -43,7 +43,7 @@ static void uci_getln(struct uci_context *ctx)
                p = fgets(p, pctx->bufsz - ofs, pctx->file);
                if (!p || !p[ofs])
                        return;
-               
+
                ofs += strlen(p);
                if (pctx->buf[ofs - 1] == '\n') {
                        pctx->line++;
@@ -67,11 +67,15 @@ static void uci_getln(struct uci_context *ctx)
 static void uci_parse_cleanup(struct uci_context *ctx)
 {
        struct uci_parse_context *pctx;
-       
+
        pctx = ctx->pctx;
        if (!pctx)
                return;
 
+       if (pctx->cfg) {
+               uci_list_del(&pctx->cfg->list);
+               uci_drop_file(pctx->cfg);
+       }
        if (pctx->buf)
                free(pctx->buf);
        if (pctx->file)
@@ -80,26 +84,33 @@ 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;
-       
+
        *str += 1;
        val = *str;
        while (**str) {
-                       
+
                /* skip escaped characters */
                if (**str == '\\') {
                        *str += 2;
                        continue;
                }
-               
+
                /* check for the end of the quoted string */
                if (**str == '"') {
                        **str = 0;
@@ -112,16 +123,22 @@ 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;
-       
+
        val = *str;
 
        while (**str && !isspace(**str))
@@ -135,11 +152,14 @@ static char *parse_unquoted(char **str)
        return val;
 }
 
+/*
+ * 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);
 
+       skip_whitespace(str);
        switch (**str) {
                case '"':
                        val = parse_double_quote(str);
@@ -150,7 +170,7 @@ static char *next_arg(struct uci_context *ctx, char **str, bool required)
                default:
                        val = parse_unquoted(str);
        }
-       
+
        if (required && !val) {
                ctx->pctx->byte = *str - ctx->pctx->buf;
                UCI_THROW(ctx, UCI_ERR_PARSE);
@@ -159,23 +179,30 @@ static char *next_arg(struct uci_context *ctx, char **str, bool required)
        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) {
+       if (tmp && *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;
-       
+
        *str += strlen(*str) + 1;
-       
+
        if (!*str) {
                ctx->pctx->byte = *str - ctx->pctx->buf;
                UCI_THROW(ctx, UCI_ERR_PARSE);
@@ -183,36 +210,42 @@ static void uci_parse_config(struct uci_context *ctx, char **str)
 
        type = next_arg(ctx, str, true);
        name = next_arg(ctx, str, false);
-       assert_eol(ctx, str);   
+       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(ctx, str, true);
        value = next_arg(ctx, str, true);
-       assert_eol(ctx, str);   
+       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;
        char *word, *brk;
-       
+
        for (word = strtok_r(pctx->buf, ";", &brk);
                 word;
                 word = strtok_r(NULL, ";", &brk)) {
-                       
+
                char *pbrk;
                word = strtok_r(word, " \t", &pbrk);
-               
+
                switch(word[0]) {
                        case 'c':
                                if ((word[1] == 0) || !strcmp(word + 1, "onfig"))
@@ -233,7 +266,7 @@ static void uci_parse_line(struct uci_context *ctx)
 int uci_parse(struct uci_context *ctx, const char *name)
 {
        struct uci_parse_context *pctx;
-       
+
        UCI_HANDLE_ERR(ctx);
        UCI_ASSERT(ctx, name != NULL);
 
@@ -242,18 +275,24 @@ int uci_parse(struct uci_context *ctx, const char *name)
 
        pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context));
        ctx->pctx = pctx;
-       
+
        /* TODO: use /etc/config/ */
        pctx->file = fopen(name, "r");
        if (!pctx->file)
                UCI_THROW(ctx, UCI_ERR_NOTFOUND);
 
+       pctx->cfg = uci_alloc_file(ctx, name);
+
        while (!feof(pctx->file)) {
                uci_getln(ctx);
                if (*(pctx->buf))
                        uci_parse_line(ctx);
        }
 
+       /* add to main config file list */
+       uci_list_add(&ctx->root, &pctx->cfg->list);
+       pctx->cfg = NULL;
+
        /* if no error happened, we can get rid of the parser context now */
        uci_parse_cleanup(ctx);