implement the uci changes command to display uncommitted changes
authorFelix Fietkau <nbd@openwrt.org>
Tue, 5 Feb 2008 00:23:55 +0000 (01:23 +0100)
committerFelix Fietkau <nbd@openwrt.org>
Tue, 5 Feb 2008 00:23:55 +0000 (01:23 +0100)
cli.c
history.c
libuci.c
list.c
uci.h
uci_internal.h [new file with mode: 0644]

diff --git a/cli.c b/cli.c
index e05f5d4db06e7c615757a1f321fa326f13e25a97..dadadaa9226eb8d9867fcfdfaf5ed804273a4d61 100644 (file)
--- a/cli.c
+++ b/cli.c
@@ -38,6 +38,7 @@ enum {
        CMD_REVERT,
        /* package cmds */
        CMD_SHOW,
+       CMD_CHANGES,
        CMD_EXPORT,
        CMD_COMMIT,
        /* other cmds */
@@ -106,18 +107,45 @@ static void uci_show_package(struct uci_package *p)
        }
 }
 
+static void uci_show_changes(struct uci_package *p)
+{
+       struct uci_element *e;
+
+       uci_foreach_element(&p->saved_history, e) {
+               struct uci_history *h = uci_to_history(e);
+
+               if (h->cmd == UCI_CMD_REMOVE)
+                       printf("-");
+               printf("%s.%s", p->e.name, h->section);
+               if (e->name)
+                       printf(".%s", e->name);
+               if (h->cmd != UCI_CMD_REMOVE)
+                       printf("=%s", h->value);
+               printf("\n");
+       }
+}
 
 static int package_cmd(int cmd, char *package)
 {
        struct uci_package *p = NULL;
+       int ret;
 
-       if (uci_load(ctx, package, &p) != UCI_OK) {
+       if (cmd == CMD_CHANGES)
+               ctx->flags |= UCI_FLAG_SAVED_HISTORY;
+       ret = uci_load(ctx, package, &p);
+       if (cmd == CMD_CHANGES)
+               ctx->flags &= ~UCI_FLAG_SAVED_HISTORY;
+
+       if (ret != UCI_OK) {
                cli_perror();
                return 1;
        }
        if (!p)
                return 0;
        switch(cmd) {
+       case CMD_CHANGES:
+               uci_show_changes(p);
+               break;
        case CMD_COMMIT:
                if (flags & CLI_FLAG_NOCOMMIT)
                        return 0;
@@ -355,6 +383,8 @@ static int uci_cmd(int argc, char **argv)
                return uci_batch();
        else if (!strcasecmp(argv[0], "show"))
                cmd = CMD_SHOW;
+       else if (!strcasecmp(argv[0], "changes"))
+               cmd = CMD_CHANGES;
        else if (!strcasecmp(argv[0], "export"))
                cmd = CMD_EXPORT;
        else if (!strcasecmp(argv[0], "commit"))
@@ -387,6 +417,7 @@ static int uci_cmd(int argc, char **argv)
                case CMD_SHOW:
                case CMD_EXPORT:
                case CMD_COMMIT:
+               case CMD_CHANGES:
                        return uci_do_package_cmd(cmd, argc, argv);
                case CMD_IMPORT:
                        return uci_do_import(argc, argv);
index 3a8b73e6e44db82092c3b2a424360b3029c1a336..070930b9093a610ea8a8aa3d547d37d2f97ffd6e 100644 (file)
--- a/history.c
+++ b/history.c
 #include <stdio.h>
 #include <ctype.h>
 
+/* record a change that was done to a package */
+static void
+uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, char *section, char *option, char *value)
+{
+       struct uci_history *h;
+       int size = strlen(section) + 1;
+       char *ptr;
+
+       if (value)
+               size += strlen(value) + 1;
+
+       h = uci_alloc_element(ctx, history, option, size);
+       ptr = uci_dataptr(h);
+       h->cmd = cmd;
+       h->section = strcpy(ptr, section);
+       if (value) {
+               ptr += strlen(ptr) + 1;
+               h->value = strcpy(ptr, value);
+       }
+       uci_list_add(list, &h->e.list);
+}
+
+static void
+uci_free_history(struct uci_history *h)
+{
+       if (!h)
+               return;
+       if ((h->section != NULL) &&
+               (h->section != uci_dataptr(h))) {
+               free(h->section);
+               free(h->value);
+       }
+       uci_free_element(&h->e);
+}
+
+
 int uci_set_savedir(struct uci_context *ctx, const char *dir)
 {
        char *sdir;
@@ -85,6 +121,20 @@ static void uci_parse_history_line(struct uci_context *ctx, struct uci_package *
        if (rename && !uci_validate_str(value, (option || delete)))
                goto error;
 
+       if (ctx->flags & UCI_FLAG_SAVED_HISTORY) {
+               int cmd;
+
+               /* NB: no distinction between CMD_CHANGE and CMD_ADD possible at this point */
+               if(delete)
+                       cmd = UCI_CMD_REMOVE;
+               else if (rename)
+                       cmd = UCI_CMD_RENAME;
+               else
+                       cmd = UCI_CMD_CHANGE;
+
+               uci_add_history(ctx, &p->saved_history, cmd, section, option, value);
+       }
+
        if (rename)
                UCI_INTERNAL(uci_rename, ctx, p, section, option, value);
        else if (delete)
index 66e6d23860fd57559d1f3606803fa512c36ba6ce..7805d746f01197582e2d7c453471616212a83394 100644 (file)
--- a/libuci.c
+++ b/libuci.c
@@ -39,6 +39,7 @@ static const char *uci_errstr[] = {
        [UCI_ERR_UNKNOWN] =   "Unknown error",
 };
 
+#include "uci_internal.h"
 #include "util.c"
 #include "list.c"
 #include "history.c"
diff --git a/list.c b/list.c
index 24382c8464d090746d416fa45e5caef5b213b8b8..e817118472f06db1ef3476b88d93ba3ab8f18881 100644 (file)
--- a/list.c
+++ b/list.c
@@ -151,44 +151,6 @@ uci_free_section(struct uci_section *s)
        uci_free_element(&s->e);
 }
 
-/* record a change that was done to a package */
-static void
-uci_add_history(struct uci_context *ctx, struct uci_package *p, int cmd, char *section, char *option, char *value)
-{
-       struct uci_history *h;
-       int size = strlen(section) + 1;
-       char *ptr;
-
-       if (!p->confdir)
-               return;
-
-       if (value)
-               size += strlen(value) + 1;
-
-       h = uci_alloc_element(ctx, history, option, size);
-       ptr = uci_dataptr(h);
-       h->cmd = cmd;
-       h->section = strcpy(ptr, section);
-       if (value) {
-               ptr += strlen(ptr) + 1;
-               h->value = strcpy(ptr, value);
-       }
-       uci_list_add(&p->history, &h->e.list);
-}
-
-static void
-uci_free_history(struct uci_history *h)
-{
-       if (!h)
-               return;
-       if ((h->section != NULL) &&
-               (h->section != uci_dataptr(h))) {
-               free(h->section);
-               free(h->value);
-       }
-       uci_free_element(&h->e);
-}
-
 static struct uci_package *
 uci_alloc_package(struct uci_context *ctx, const char *name)
 {
@@ -198,6 +160,7 @@ uci_alloc_package(struct uci_context *ctx, const char *name)
        p->ctx = ctx;
        uci_list_init(&p->sections);
        uci_list_init(&p->history);
+       uci_list_init(&p->saved_history);
        return p;
 }
 
@@ -218,6 +181,9 @@ uci_free_package(struct uci_package **package)
        uci_foreach_element_safe(&p->history, tmp, e) {
                uci_free_history(uci_to_history(e));
        }
+       uci_foreach_element_safe(&p->saved_history, tmp, e) {
+               uci_free_history(uci_to_history(e));
+       }
        uci_free_element(&p->e);
        *package = NULL;
 }
@@ -294,8 +260,8 @@ int uci_del_element(struct uci_context *ctx, struct uci_element *e)
        }
 
        p = s->package;
-       if (!internal)
-               uci_add_history(ctx, p, UCI_CMD_REMOVE, s->e.name, option, NULL);
+       if (!internal && p->confdir)
+               uci_add_history(ctx, &p->history, UCI_CMD_REMOVE, s->e.name, option, NULL);
 
        switch(e->type) {
        case UCI_TYPE_SECTION:
@@ -357,8 +323,8 @@ int uci_set_element_value(struct uci_context *ctx, struct uci_element **element,
                return 0;
        }
        p = s->package;
-       if (!internal)
-               uci_add_history(ctx, p, UCI_CMD_CHANGE, section, option, value);
+       if (!internal && p->confdir)
+               uci_add_history(ctx, &p->history, UCI_CMD_CHANGE, section, option, value);
 
        uci_list_del(&e->list);
        e = uci_realloc(ctx, e, size);
@@ -391,8 +357,8 @@ int uci_rename(struct uci_context *ctx, struct uci_package *p, char *section, ch
        /* NB: p, section, option validated by uci_lookup */
        UCI_INTERNAL(uci_lookup, ctx, &e, p, section, option);
 
-       if (!internal)
-               uci_add_history(ctx, p, UCI_CMD_RENAME, section, option, name);
+       if (!internal && p->confdir)
+               uci_add_history(ctx, &p->history, UCI_CMD_RENAME, section, option, name);
 
        name = uci_strdup(ctx, name);
        if (e->name)
@@ -479,8 +445,8 @@ notfound:
                UCI_THROW(ctx, UCI_ERR_NOTFOUND);
 
        /* now add the missing entry */
-       if (!internal)
-               uci_add_history(ctx, p, UCI_CMD_ADD, section, option, value);
+       if (!internal && p->confdir)
+               uci_add_history(ctx, &p->history, UCI_CMD_ADD, section, option, value);
        if (s)
                uci_alloc_option(s, option, value);
        else {
diff --git a/uci.h b/uci.h
index 9f03a6f811de2299b445fe84b5572e5d9d468fa8..cfcdf3ea8abf6f1bee81584f3088225bd8503117 100644 (file)
--- a/uci.h
+++ b/uci.h
@@ -279,9 +279,10 @@ enum uci_type {
 };
 
 enum uci_flags {
-       UCI_FLAG_STRICT =      (1 << 0), /* strict mode for the parser */
-       UCI_FLAG_PERROR =      (1 << 1), /* print parser error messages */
-       UCI_FLAG_EXPORT_NAME = (1 << 2), /* when exporting, name unnamed sections */
+       UCI_FLAG_STRICT =        (1 << 0), /* strict mode for the parser */
+       UCI_FLAG_PERROR =        (1 << 1), /* print parser error messages */
+       UCI_FLAG_EXPORT_NAME =   (1 << 2), /* when exporting, name unnamed sections */
+       UCI_FLAG_SAVED_HISTORY = (1 << 3), /* store the saved history in memory as well */
 };
 
 struct uci_element
@@ -317,23 +318,6 @@ struct uci_context
        int bufsz;
 };
 
-struct uci_parse_context
-{
-       /* error context */
-       const char *reason;
-       int line;
-       int byte;
-
-       /* private: */
-       struct uci_package *package;
-       struct uci_section *section;
-       bool merge;
-       FILE *file;
-       const char *name;
-       char *buf;
-       int bufsz;
-};
-
 struct uci_package
 {
        struct uci_element e;
@@ -345,6 +329,7 @@ struct uci_package
        /* private: */
        int n_section;
        struct uci_list history;
+       struct uci_list saved_history;
 };
 
 struct uci_section
diff --git a/uci_internal.h b/uci_internal.h
new file mode 100644 (file)
index 0000000..5b496ea
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * libuci - Library for the Unified Configuration Interface
+ * Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __UCI_INTERNAL_H
+#define __UCI_INTERNAL_H
+
+struct uci_parse_context
+{
+       /* error context */
+       const char *reason;
+       int line;
+       int byte;
+
+       /* private: */
+       struct uci_package *package;
+       struct uci_section *section;
+       bool merge;
+       FILE *file;
+       const char *name;
+       char *buf;
+       int bufsz;
+};
+
+static void uci_add_history(struct uci_context *ctx, struct uci_list *list, int cmd, char *section, char *option, char *value);
+static void uci_free_history(struct uci_history *h);
+
+#endif