more error handling
authorFelix Fietkau <nbd@openwrt.org>
Sat, 19 Jan 2008 22:05:45 +0000 (23:05 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Sat, 19 Jan 2008 22:05:45 +0000 (23:05 +0100)
err.h
libuci.h
list.c
parse.c
test.c

diff --git a/err.h b/err.h
index 469164c..cf42856 100644 (file)
--- a/err.h
+++ b/err.h
@@ -38,7 +38,7 @@
  * functions from other uci functions is only allowed at the end of the
  * calling function.
  */
-#define UCI_HANDLE_ERR(ctx) do {               \
+#define UCI_HANDLE_ERR(ctx) do {       \
        int __val;                      \
        if (!ctx)                       \
                return UCI_ERR_INVAL;   \
        }                               \
 } while (0)
 
+/*
+ * In a block enclosed by UCI_TRAP_SAVE and UCI_TRAP_RESTORE, all exceptions
+ * are intercepted and redirected to the label specified in 'handler'
+ * after UCI_TRAP_RESTORE, or when reaching the 'handler' label, the old
+ * exception handler is restored
+ */
+#define UCI_TRAP_SAVE(ctx, handler) do {   \
+       jmp_buf __old_trap;             \
+       int __val;                      \
+       memcpy(__old_trap, ctx->trap, sizeof(ctx->trap)); \
+       __val = setjmp(ctx->trap);      \
+       if (__val) {                    \
+               ctx->errno = __val;     \
+               memcpy(ctx->trap, __old_trap, sizeof(ctx->trap)); \
+               goto handler;           \
+       }
+#define UCI_TRAP_RESTORE(ctx)          \
+       memcpy(ctx->trap, __old_trap, sizeof(ctx->trap)); \
+} while(0)
+
 /*
  * check the specified condition.
  * throw an invalid argument exception if it's false
index aba4359..50c20f1 100644 (file)
--- a/libuci.h
+++ b/libuci.h
@@ -81,6 +81,8 @@ struct uci_context
        /* private: */
        int errno;
        jmp_buf trap;
+       jmp_buf trap_saved;
+       int saved;
 };
 
 struct uci_parse_context
diff --git a/list.c b/list.c
index 5888042..51fca61 100644 (file)
--- a/list.c
+++ b/list.c
@@ -46,24 +46,68 @@ static inline void uci_list_del(struct uci_list *ptr)
        next->prev = prev;
 }
 
-static struct uci_config *uci_alloc_file(struct uci_context *ctx, const char *name)
+static void uci_drop_section(struct uci_section *section)
 {
-       struct uci_config *cfg;
+       if (!section)
+               return;
+       if (section->name)
+               free(section->name);
+       if (section->type)
+               free(section->type);
+       free(section);
+}
 
-       cfg = (struct uci_config *) uci_malloc(ctx, sizeof(struct uci_config));
-       uci_list_init(&cfg->list);
-       uci_list_init(&cfg->sections);
-       cfg->name = uci_strdup(ctx, name);
-       cfg->ctx = ctx;
+static struct uci_section *uci_add_section(struct uci_config *cfg, const char *type, const char *name)
+{
+       struct uci_section *section = NULL;
+       struct uci_context *ctx = cfg->ctx;
 
-       return cfg;
+       UCI_TRAP_SAVE(ctx, error)
+       section = (struct uci_section *) uci_malloc(ctx, sizeof(struct uci_section));
+       section->config = cfg;
+       uci_list_init(&section->list);
+       uci_list_init(&section->options);
+       uci_list_add(&cfg->sections, &section->list);
+       section->type = uci_strdup(ctx, type);
+       if (name)
+               section->name = uci_strdup(ctx, name);
+       UCI_TRAP_RESTORE(ctx);
+
+       return section;
+
+error:
+       uci_drop_section(section);
+       UCI_THROW(ctx, ctx->errno);
+       return NULL;
 }
 
 static void uci_drop_file(struct uci_config *cfg)
 {
        /* TODO: free children */
-       uci_list_del(&cfg->list);
+       if(!cfg)
+               return;
        if (cfg->name)
                free(cfg->name);
        free(cfg);
 }
+
+
+static struct uci_config *uci_alloc_file(struct uci_context *ctx, const char *name)
+{
+       struct uci_config *cfg = NULL;
+
+       UCI_TRAP_SAVE(ctx, error)
+       cfg = (struct uci_config *) uci_malloc(ctx, sizeof(struct uci_config));
+       uci_list_init(&cfg->list);
+       uci_list_init(&cfg->sections);
+       cfg->name = uci_strdup(ctx, name);
+       cfg->ctx = ctx;
+       UCI_TRAP_RESTORE(ctx);
+       return cfg;
+
+error:
+       uci_drop_file(cfg);
+       UCI_THROW(ctx, ctx->errno);
+       return NULL;
+}
+
diff --git a/parse.c b/parse.c
index f5e6c29..a0a3ec8 100644 (file)
--- a/parse.c
+++ b/parse.c
@@ -72,8 +72,10 @@ static void uci_parse_cleanup(struct uci_context *ctx)
        if (!pctx)
                return;
 
-       if (pctx->cfg)
+       if (pctx->cfg) {
+               uci_list_del(&pctx->cfg->list);
                uci_drop_file(pctx->cfg);
+       }
        if (pctx->buf)
                free(pctx->buf);
        if (pctx->file)
diff --git a/test.c b/test.c
index 44e2dc8..53b2a6a 100644 (file)
--- a/test.c
+++ b/test.c
@@ -20,11 +20,11 @@ int main(int argc, char **argv)
                fprintf(stderr, "Failed to allocate uci context");
                return 1;
        }
-       
+
        if (uci_parse(ctx, argv[1])) {
                uci_perror(ctx, "uci_parse");
                return 1;
        }
-       
+
        return 0;
 }