CMD_REVERT,
/* package cmds */
CMD_SHOW,
+ CMD_CHANGES,
CMD_EXPORT,
CMD_COMMIT,
/* other cmds */
}
}
+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;
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"))
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);
#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;
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)
[UCI_ERR_UNKNOWN] = "Unknown error",
};
+#include "uci_internal.h"
#include "util.c"
#include "list.c"
#include "history.c"
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)
{
p->ctx = ctx;
uci_list_init(&p->sections);
uci_list_init(&p->history);
+ uci_list_init(&p->saved_history);
return p;
}
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;
}
}
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:
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);
/* 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)
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 {
};
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
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;
/* private: */
int n_section;
struct uci_list history;
+ struct uci_list saved_history;
};
struct uci_section
--- /dev/null
+/*
+ * 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