From a453ffddff2ce0c0c7fd21826bb4ae1544829553 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Tue, 22 Jan 2008 23:34:04 +0100 Subject: [PATCH] refactor, add uci_import --- Makefile | 2 +- parse.c => file.c | 119 +++++++++++++++++++++++++++++++++------------- libuci.c | 2 +- uci.h | 14 +++++- 4 files changed, 102 insertions(+), 35 deletions(-) rename parse.c => file.c (85%) diff --git a/Makefile b/Makefile index 1e0fce3..01063a8 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ cli.o: cli.c uci.h uci: cli.o libuci.a $(CC) $(CFLAGS) -o $@ $^ -libuci.o: libuci.c parse.c uci.h list.c err.h +libuci.o: libuci.c file.c uci.h list.c err.h libuci.a: libuci.o rm -f $@ $(AR) rc $@ $^ diff --git a/parse.c b/file.c similarity index 85% rename from parse.c rename to file.c index 1297b80..580ca18 100644 --- a/parse.c +++ b/file.c @@ -241,6 +241,42 @@ static void assert_eol(struct uci_context *ctx, char **str) } } +/* + * switch to a different config, either triggered by uci_load, or by a + * 'package <...>' statement in the import file + */ +static void uci_switch_config(struct uci_context *ctx) +{ + struct uci_parse_context *pctx; + const char *name; + + pctx = ctx->pctx; + name = pctx->name; + + /* add the last config to main config file list */ + if (pctx->cfg) { + uci_list_add(&ctx->root, &pctx->cfg->list); + + pctx->cfg = NULL; + pctx->section = NULL; + } + + if (!name) + return; + + /* + * if an older config under the same name exists, unload it + * ignore errors here, e.g. if the config was not found + */ + UCI_TRAP_SAVE(ctx, ignore); + uci_unload(ctx, name); + UCI_TRAP_RESTORE(ctx); +ignore: + ctx->errno = 0; + + pctx->cfg = uci_alloc_config(ctx, name); +} + /* * parse the 'config' uci command (open a section) */ @@ -249,6 +285,15 @@ static void uci_parse_config(struct uci_context *ctx, char **str) char *name = NULL; char *type = NULL; + if (!ctx->pctx->cfg) { + if (!ctx->pctx->name) { + ctx->pctx->byte = *str - ctx->pctx->buf; + ctx->pctx->reason = "attempting to import a file without a package name"; + UCI_THROW(ctx, UCI_ERR_PARSE); + } + uci_switch_config(ctx); + } + /* command string null-terminated by strtok */ *str += strlen(*str) + 1; @@ -300,6 +345,7 @@ error: UCI_THROW(ctx, ctx->errno); } + /* * parse a complete input line, split up combined commands by ';' */ @@ -333,29 +379,56 @@ static void uci_parse_line(struct uci_context *ctx) } } -int uci_load(struct uci_context *ctx, const char *name, struct uci_config **cfg) +int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_config **cfg) { struct uci_parse_context *pctx; + + /* make sure no memory from previous parse attempts is leaked */ + uci_parse_cleanup(ctx); + + pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); + ctx->pctx = pctx; + pctx->file = stream; + + /* + * If 'name' was supplied, assume that the supplied stream does not contain + * the appropriate 'package ' string to specify the config name + * NB: the config file can still override the package name + */ + if (name) + pctx->name = name; + + while (!feof(pctx->file)) { + uci_getln(ctx); + if (pctx->buf[0]) + uci_parse_line(ctx); + } + + if (cfg) + *cfg = pctx->cfg; + + pctx->name = NULL; + uci_switch_config(ctx); + + /* no error happened, we can get rid of the parser context now */ + uci_parse_cleanup(ctx); + + return 0; +} + +int uci_load(struct uci_context *ctx, const char *name, struct uci_config **cfg) +{ struct stat statbuf; char *filename; bool confpath; + FILE *file; UCI_HANDLE_ERR(ctx); UCI_ASSERT(ctx, name != NULL); - UCI_TRAP_SAVE(ctx, ignore); - uci_unload(ctx, name); - UCI_TRAP_RESTORE(ctx); - ignore: ctx->errno = 0; - /* make sure no memory from previous parse attempts is leaked */ - uci_parse_cleanup(ctx); - - pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); - ctx->pctx = pctx; - switch (name[0]) { case '.': case '/': @@ -375,31 +448,13 @@ ignore: UCI_THROW(ctx, UCI_ERR_NOTFOUND); } - pctx->file = fopen(filename, "r"); + file = fopen(filename, "r"); if (filename != name) free(filename); - if (!pctx->file) + if (!file) UCI_THROW(ctx, UCI_ERR_IO); - pctx->cfg = uci_alloc_config(ctx, name); - - while (!feof(pctx->file)) { - uci_getln(ctx); - if (pctx->buf[0]) - uci_parse_line(ctx); - } - - /* add to main config file list */ - uci_list_add(&ctx->root, &pctx->cfg->list); - if (cfg) - *cfg = pctx->cfg; - - pctx->cfg = NULL; - - /* no error happened, we can get rid of the parser context now */ - uci_parse_cleanup(ctx); - - return 0; + return uci_import(ctx, file, name, cfg); } diff --git a/libuci.c b/libuci.c index ada75c0..4a06d71 100644 --- a/libuci.c +++ b/libuci.c @@ -79,7 +79,7 @@ static char *uci_strdup(struct uci_context *ctx, const char *str) } #include "list.c" -#include "parse.c" +#include "file.c" /* externally visible functions */ diff --git a/uci.h b/uci.h index c5594d8..7cd7eb9 100644 --- a/uci.h +++ b/uci.h @@ -61,6 +61,17 @@ extern void uci_free(struct uci_context *ctx); */ extern void uci_perror(struct uci_context *ctx, const char *str); +/** + * uci_import: Import uci config data from a stream + * @ctx: uci context + * @stream: file stream to import from + * @name: (optional) assume the config has the given name + * @cfg: (optional) store the last parsed config package in this variable + * + * the name parameter is for config files that don't explicitly use the 'package <...>' keyword + */ +extern int uci_import(struct uci_context *ctx, FILE *stream, const char *name, struct uci_config **cfg); + /** * uci_load: Parse an uci config file and store it in the uci context * @@ -107,6 +118,7 @@ struct uci_context struct uci_parse_context { + const char *reason; int line; int byte; @@ -114,8 +126,8 @@ struct uci_parse_context struct uci_config *cfg; struct uci_section *section; FILE *file; + const char *name; char *buf; - char *reason; int bufsz; }; -- 2.30.2