From 6ce771b1095c220f849e70cdcbf23bd09f7fe7d5 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 20 Aug 2010 14:51:18 +0200 Subject: [PATCH] split off and compile file.c separately --- Makefile | 6 +- file.c | 284 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- history.c | 2 +- libuci.c | 4 +- list.c | 82 +---------------- uci_internal.h | 69 ++++++++++++++ util.c | 256 +-------------------------------------------------- 7 files changed, 362 insertions(+), 341 deletions(-) diff --git a/Makefile b/Makefile index 506893f..c3d79e4 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,7 @@ endef all: uci libuci.$(SHLIB_EXT) uci-static ucimap-example -$(eval $(call add_dep,libuci,file.c history.c list.c util.c uci.h uci_config.h uci_internal.h)) +$(eval $(call add_dep,libuci,history.c list.c util.c uci.h uci_config.h uci_internal.h)) $(eval $(call add_dep,ucimap,uci.h uci_config.h ucimap.h)) cli.o: cli.c uci.h uci_config.h @@ -56,12 +56,12 @@ uci-static: cli.o libuci.a ucimap.c: ucimap.h uci.h -libuci.a: libuci.static.o ucimap.static.o +libuci.a: libuci.static.o ucimap.static.o file.static.o rm -f $@ $(AR) rc $@ $^ $(RANLIB) $@ -libuci.$(SHLIB_EXT): libuci.shared.o ucimap.shared.o +libuci.$(SHLIB_EXT): libuci.shared.o file.shared.o ucimap.shared.o $(LINK) $(SHLIB_FLAGS) -o $(SHLIB_FILE) $^ $(LIBS) ln -sf $(SHLIB_FILE) $@ diff --git a/file.c b/file.c index c6a3095..33ba93c 100644 --- a/file.c +++ b/file.c @@ -25,8 +25,284 @@ #include #include #include +#include +#include + +#include "uci.h" +#include "uci_internal.h" + +#define LINEBUF 32 +#define LINEBUF_MAX 4096 + +/* + * Fetch a new line from the input stream and resize buffer if necessary + */ +__private void uci_getln(struct uci_context *ctx, int offset) +{ + struct uci_parse_context *pctx = ctx->pctx; + char *p; + int ofs; + + if (pctx->buf == NULL) { + pctx->buf = uci_malloc(ctx, LINEBUF); + pctx->bufsz = LINEBUF; + } + + ofs = offset; + do { + p = &pctx->buf[ofs]; + p[ofs] = 0; + + p = fgets(p, pctx->bufsz - ofs, pctx->file); + if (!p || !*p) + return; + + ofs += strlen(p); + if (pctx->buf[ofs - 1] == '\n') { + pctx->line++; + pctx->buf[ofs - 1] = 0; + return; + } + + if (pctx->bufsz > LINEBUF_MAX/2) + uci_parse_error(ctx, p, "line too long"); + + pctx->bufsz *= 2; + pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz); + } while (1); +} + + +/* + * parse a character escaped by '\' + * returns true if the escaped character is to be parsed + * returns false if the escaped character is to be ignored + */ +static inline bool parse_backslash(struct uci_context *ctx, char **str) +{ + /* skip backslash */ + *str += 1; + + /* undecoded backslash at the end of line, fetch the next line */ + if (!**str) { + *str += 1; + uci_getln(ctx, *str - ctx->pctx->buf); + return false; + } + + /* FIXME: decode escaped char, necessary? */ + return true; +} + +/* + * move the string pointer forward until a non-whitespace character or + * EOL is reached + */ +static void skip_whitespace(struct uci_context *ctx, char **str) +{ +restart: + while (**str && isspace(**str)) + *str += 1; + + if (**str == '\\') { + if (!parse_backslash(ctx, str)) + goto restart; + } +} + +static inline void addc(char **dest, char **src) +{ + **dest = **src; + *dest += 1; + *src += 1; +} + +/* + * parse a double quoted string argument from the command line + */ +static void parse_double_quote(struct uci_context *ctx, char **str, char **target) +{ + char c; + + /* skip quote character */ + *str += 1; + + while ((c = **str)) { + switch(c) { + case '"': + **target = 0; + *str += 1; + return; + case '\\': + if (!parse_backslash(ctx, str)) + continue; + /* fall through */ + default: + addc(target, str); + break; + } + } + uci_parse_error(ctx, *str, "unterminated \""); +} + +/* + * parse a single quoted string argument from the command line + */ +static void parse_single_quote(struct uci_context *ctx, char **str, char **target) +{ + char c; + /* skip quote character */ + *str += 1; + + while ((c = **str)) { + switch(c) { + case '\'': + **target = 0; + *str += 1; + return; + default: + addc(target, str); + } + } + uci_parse_error(ctx, *str, "unterminated '"); +} + +/* + * parse a string from the command line and detect the quoting style + */ +static void parse_str(struct uci_context *ctx, char **str, char **target) +{ + bool next = true; + do { + switch(**str) { + case '\'': + parse_single_quote(ctx, str, target); + break; + case '"': + parse_double_quote(ctx, str, target); + break; + case '#': + **str = 0; + /* fall through */ + case 0: + goto done; + case ';': + next = false; + goto done; + case '\\': + if (!parse_backslash(ctx, str)) + continue; + /* fall through */ + default: + addc(target, str); + break; + } + } while (**str && !isspace(**str)); +done: + + /* + * if the string was unquoted and we've stopped at a whitespace + * character, skip to the next one, because the whitespace will + * be overwritten by a null byte here + */ + if (**str && next) + *str += 1; + + /* terminate the parsed string */ + **target = 0; +} + +/* + * extract the next argument from the command line + */ +static char *next_arg(struct uci_context *ctx, char **str, bool required, bool name) +{ + char *val; + char *ptr; + + val = ptr = *str; + skip_whitespace(ctx, str); + if(*str[0] == ';') { + *str[0] = 0; + *str += 1; + } else { + parse_str(ctx, str, &ptr); + } + if (!*val) { + if (required) + uci_parse_error(ctx, *str, "insufficient arguments"); + goto done; + } + + if (name && !uci_validate_name(val)) + uci_parse_error(ctx, val, "invalid character in field"); + +done: + return val; +} + +int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result) +{ + UCI_HANDLE_ERR(ctx); + UCI_ASSERT(ctx, str != NULL); + UCI_ASSERT(ctx, result != NULL); + + if (ctx->pctx && (ctx->pctx->file != stream)) + uci_cleanup(ctx); + + if (!ctx->pctx) + uci_alloc_parse_context(ctx); + + ctx->pctx->file = stream; + + if (!*str) { + uci_getln(ctx, 0); + *str = ctx->pctx->buf; + } + + *result = next_arg(ctx, str, false, false); + + return 0; +} + +static int +uci_fill_ptr(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_element *e, bool complete) +{ + UCI_ASSERT(ctx, ptr != NULL); + UCI_ASSERT(ctx, e != NULL); + + memset(ptr, 0, sizeof(struct uci_ptr)); + switch(e->type) { + case UCI_TYPE_OPTION: + ptr->o = uci_to_option(e); + goto fill_option; + case UCI_TYPE_SECTION: + ptr->s = uci_to_section(e); + goto fill_section; + case UCI_TYPE_PACKAGE: + ptr->p = uci_to_package(e); + goto fill_package; + default: + UCI_THROW(ctx, UCI_ERR_INVAL); + } + +fill_option: + ptr->option = ptr->o->e.name; + ptr->s = ptr->o->section; +fill_section: + ptr->section = ptr->s->e.name; + ptr->p = ptr->s->package; +fill_package: + ptr->package = ptr->p->e.name; + + ptr->flags |= UCI_LOOKUP_DONE; + if (complete) + ptr->flags |= UCI_LOOKUP_COMPLETE; + + return 0; +} + -static struct uci_backend uci_file_backend; /* * verify that the end of the line or command is reached. @@ -128,7 +404,7 @@ static void uci_parse_config(struct uci_context *ctx, char **str) ctx->internal = !pctx->merge; UCI_NESTED(uci_add_section, ctx, pctx->package, type, &pctx->section); } else { - UCI_NESTED(uci_fill_ptr, ctx, &ptr, &pctx->package->e, false); + uci_fill_ptr(ctx, &ptr, &pctx->package->e, false); e = uci_lookup_list(&pctx->package->sections, name); if (e) ptr.s = uci_to_section(e); @@ -162,7 +438,7 @@ static void uci_parse_option(struct uci_context *ctx, char **str, bool list) value = next_arg(ctx, str, false, false); assert_eol(ctx, str); - UCI_NESTED(uci_fill_ptr, ctx, &ptr, &pctx->section->e, false); + uci_fill_ptr(ctx, &ptr, &pctx->section->e, false); e = uci_lookup_list(&pctx->section->options, name); if (e) ptr.o = uci_to_option(e); @@ -576,7 +852,7 @@ done: return package; } -static UCI_BACKEND(uci_file_backend, "file", +__private UCI_BACKEND(uci_file_backend, "file", .load = uci_file_load, .commit = uci_file_commit, .list_configs = uci_list_config_files, diff --git a/history.c b/history.c index c698192..649ead1 100644 --- a/history.c +++ b/history.c @@ -239,7 +239,7 @@ done: } /* returns the number of changes that were successfully parsed */ -static int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush) +__private int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush) { struct uci_element *e; char *filename = NULL; diff --git a/libuci.c b/libuci.c index a1fd92a..6e9587b 100644 --- a/libuci.c +++ b/libuci.c @@ -40,14 +40,12 @@ static const char *uci_errstr[] = { [UCI_ERR_UNKNOWN] = "Unknown error", }; -static void uci_cleanup(struct uci_context *ctx); static void uci_unload_plugin(struct uci_context *ctx, struct uci_plugin *p); #include "uci_internal.h" #include "util.c" #include "list.c" #include "history.c" -#include "file.c" /* exported functions */ struct uci_context *uci_alloc_context(void) @@ -117,7 +115,7 @@ int uci_set_confdir(struct uci_context *ctx, const char *dir) return 0; } -static void uci_cleanup(struct uci_context *ctx) +__private void uci_cleanup(struct uci_context *ctx) { struct uci_parse_context *pctx; diff --git a/list.c b/list.c index cd995fe..fb9d38a 100644 --- a/list.c +++ b/list.c @@ -12,43 +12,7 @@ * GNU General Public License for more details. */ -/* initialize a list head/item */ -static inline void uci_list_init(struct uci_list *ptr) -{ - ptr->prev = ptr; - ptr->next = ptr; -} - -/* inserts a new list entry after a given entry */ -static inline void uci_list_insert(struct uci_list *list, struct uci_list *ptr) -{ - list->next->prev = ptr; - ptr->prev = list; - ptr->next = list->next; - list->next = ptr; -} - -/* inserts a new list entry at the tail of the list */ -static inline void uci_list_add(struct uci_list *head, struct uci_list *ptr) -{ - /* NB: head->prev points at the tail */ - uci_list_insert(head->prev, ptr); -} - -static inline void uci_list_del(struct uci_list *ptr) -{ - struct uci_list *next, *prev; - - next = ptr->next; - prev = ptr->prev; - - prev->next = next; - next->prev = prev; - - uci_list_init(ptr); -} - -static inline void uci_list_set_pos(struct uci_list *head, struct uci_list *ptr, int pos) +static void uci_list_set_pos(struct uci_list *head, struct uci_list *ptr, int pos) { struct uci_list *new_head = head; struct uci_element *p = NULL; @@ -164,7 +128,7 @@ uci_alloc_list(struct uci_section *s, const char *name) } /* fix up an unnamed section, e.g. after adding options to it */ -static void uci_fixup_section(struct uci_context *ctx, struct uci_section *s) +__private void uci_fixup_section(struct uci_context *ctx, struct uci_section *s) { unsigned int hash = ~0; struct uci_element *e; @@ -249,7 +213,7 @@ uci_alloc_package(struct uci_context *ctx, const char *name) return p; } -static void +__private void uci_free_package(struct uci_package **package) { struct uci_element *e, *tmp; @@ -289,7 +253,7 @@ uci_free_any(struct uci_element **e) *e = NULL; } -static inline struct uci_element * +__private struct uci_element * uci_lookup_list(struct uci_list *list, const char *name) { struct uci_element *e; @@ -437,44 +401,6 @@ notfound: return 0; } -int -uci_fill_ptr(struct uci_context *ctx, struct uci_ptr *ptr, struct uci_element *e, bool complete) -{ - UCI_HANDLE_ERR(ctx); - UCI_ASSERT(ctx, ptr != NULL); - UCI_ASSERT(ctx, e != NULL); - - memset(ptr, 0, sizeof(struct uci_ptr)); - switch(e->type) { - case UCI_TYPE_OPTION: - ptr->o = uci_to_option(e); - goto fill_option; - case UCI_TYPE_SECTION: - ptr->s = uci_to_section(e); - goto fill_section; - case UCI_TYPE_PACKAGE: - ptr->p = uci_to_package(e); - goto fill_package; - default: - UCI_THROW(ctx, UCI_ERR_INVAL); - } - -fill_option: - ptr->option = ptr->o->e.name; - ptr->s = ptr->o->section; -fill_section: - ptr->section = ptr->s->e.name; - ptr->p = ptr->s->package; -fill_package: - ptr->package = ptr->p->e.name; - - ptr->flags |= UCI_LOOKUP_DONE; - if (complete) - ptr->flags |= UCI_LOOKUP_COMPLETE; - - return 0; -} - static struct uci_element * expand_ptr(struct uci_context *ctx, struct uci_ptr *ptr, bool complete) { diff --git a/uci_internal.h b/uci_internal.h index 111982e..7ce00d0 100644 --- a/uci_internal.h +++ b/uci_internal.h @@ -15,6 +15,7 @@ #ifndef __UCI_INTERNAL_H #define __UCI_INTERNAL_H +#define __private __attribute__((visibility("hidden"))) #define __public #ifdef UCI_PLUGIN_SUPPORT #define __plugin extern @@ -47,6 +48,74 @@ __plugin void uci_add_history(struct uci_context *ctx, struct uci_list *list, in __plugin void uci_free_history(struct uci_history *h); __plugin struct uci_package *uci_alloc_package(struct uci_context *ctx, const char *name); +__private FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create); +__private void uci_close_stream(FILE *stream); +__private void uci_getln(struct uci_context *ctx, int offset); + +__private void uci_parse_error(struct uci_context *ctx, char *pos, char *reason); +__private void uci_alloc_parse_context(struct uci_context *ctx); + +__private void uci_cleanup(struct uci_context *ctx); +__private struct uci_element *uci_lookup_list(struct uci_list *list, const char *name); +__private void uci_fixup_section(struct uci_context *ctx, struct uci_section *s); +__private void uci_free_package(struct uci_package **package); + +__private int uci_load_history(struct uci_context *ctx, struct uci_package *p, bool flush); + +static inline bool uci_validate_package(const char *str) +{ + return uci_validate_str(str, false); +} + +static inline bool uci_validate_type(const char *str) +{ + return uci_validate_str(str, false); +} + +static inline bool uci_validate_name(const char *str) +{ + return uci_validate_str(str, true); +} + +/* initialize a list head/item */ +static inline void uci_list_init(struct uci_list *ptr) +{ + ptr->prev = ptr; + ptr->next = ptr; +} + +/* inserts a new list entry after a given entry */ +static inline void uci_list_insert(struct uci_list *list, struct uci_list *ptr) +{ + list->next->prev = ptr; + ptr->prev = list; + ptr->next = list->next; + list->next = ptr; +} + +/* inserts a new list entry at the tail of the list */ +static inline void uci_list_add(struct uci_list *head, struct uci_list *ptr) +{ + /* NB: head->prev points at the tail */ + uci_list_insert(head->prev, ptr); +} + +static inline void uci_list_del(struct uci_list *ptr) +{ + struct uci_list *next, *prev; + + next = ptr->next; + prev = ptr->prev; + + prev->next = next; + next->prev = prev; + + uci_list_init(ptr); +} + + +extern struct uci_backend uci_file_backend; + #ifdef UCI_PLUGIN_SUPPORT /** * uci_add_backend: add an extra backend diff --git a/util.c b/util.c index f0b2094..d44114d 100644 --- a/util.c +++ b/util.c @@ -25,9 +25,6 @@ #include #include -#define LINEBUF 32 -#define LINEBUF_MAX 4096 - __plugin void *uci_malloc(struct uci_context *ctx, size_t size) { void *ptr; @@ -97,21 +94,6 @@ __plugin bool uci_validate_str(const char *str, bool name) return true; } -static inline bool uci_validate_package(const char *str) -{ - return uci_validate_str(str, false); -} - -static inline bool uci_validate_type(const char *str) -{ - return uci_validate_str(str, false); -} - -static inline bool uci_validate_name(const char *str) -{ - return uci_validate_str(str, true); -} - bool uci_validate_text(const char *str) { while (*str) { @@ -124,7 +106,7 @@ bool uci_validate_text(const char *str) return true; } -static void uci_alloc_parse_context(struct uci_context *ctx) +__private void uci_alloc_parse_context(struct uci_context *ctx) { ctx->pctx = (struct uci_parse_context *) uci_malloc(ctx, sizeof(struct uci_parse_context)); } @@ -188,7 +170,7 @@ error: } -static void uci_parse_error(struct uci_context *ctx, char *pos, char *reason) +__private void uci_parse_error(struct uci_context *ctx, char *pos, char *reason) { struct uci_parse_context *pctx = ctx->pctx; @@ -198,236 +180,6 @@ static void uci_parse_error(struct uci_context *ctx, char *pos, char *reason) } -/* - * Fetch a new line from the input stream and resize buffer if necessary - */ -static void uci_getln(struct uci_context *ctx, int offset) -{ - struct uci_parse_context *pctx = ctx->pctx; - char *p; - int ofs; - - if (pctx->buf == NULL) { - pctx->buf = uci_malloc(ctx, LINEBUF); - pctx->bufsz = LINEBUF; - } - - ofs = offset; - do { - p = &pctx->buf[ofs]; - p[ofs] = 0; - - p = fgets(p, pctx->bufsz - ofs, pctx->file); - if (!p || !*p) - return; - - ofs += strlen(p); - if (pctx->buf[ofs - 1] == '\n') { - pctx->line++; - pctx->buf[ofs - 1] = 0; - return; - } - - if (pctx->bufsz > LINEBUF_MAX/2) - uci_parse_error(ctx, p, "line too long"); - - pctx->bufsz *= 2; - pctx->buf = uci_realloc(ctx, pctx->buf, pctx->bufsz); - } while (1); -} - -/* - * parse a character escaped by '\' - * returns true if the escaped character is to be parsed - * returns false if the escaped character is to be ignored - */ -static inline bool parse_backslash(struct uci_context *ctx, char **str) -{ - /* skip backslash */ - *str += 1; - - /* undecoded backslash at the end of line, fetch the next line */ - if (!**str) { - *str += 1; - uci_getln(ctx, *str - ctx->pctx->buf); - return false; - } - - /* FIXME: decode escaped char, necessary? */ - return true; -} - -/* - * move the string pointer forward until a non-whitespace character or - * EOL is reached - */ -static void skip_whitespace(struct uci_context *ctx, char **str) -{ -restart: - while (**str && isspace(**str)) - *str += 1; - - if (**str == '\\') { - if (!parse_backslash(ctx, str)) - goto restart; - } -} - -static inline void addc(char **dest, char **src) -{ - **dest = **src; - *dest += 1; - *src += 1; -} - -/* - * parse a double quoted string argument from the command line - */ -static void parse_double_quote(struct uci_context *ctx, char **str, char **target) -{ - char c; - - /* skip quote character */ - *str += 1; - - while ((c = **str)) { - switch(c) { - case '"': - **target = 0; - *str += 1; - return; - case '\\': - if (!parse_backslash(ctx, str)) - continue; - /* fall through */ - default: - addc(target, str); - break; - } - } - uci_parse_error(ctx, *str, "unterminated \""); -} - -/* - * parse a single quoted string argument from the command line - */ -static void parse_single_quote(struct uci_context *ctx, char **str, char **target) -{ - char c; - /* skip quote character */ - *str += 1; - - while ((c = **str)) { - switch(c) { - case '\'': - **target = 0; - *str += 1; - return; - default: - addc(target, str); - } - } - uci_parse_error(ctx, *str, "unterminated '"); -} - -/* - * parse a string from the command line and detect the quoting style - */ -static void parse_str(struct uci_context *ctx, char **str, char **target) -{ - bool next = true; - do { - switch(**str) { - case '\'': - parse_single_quote(ctx, str, target); - break; - case '"': - parse_double_quote(ctx, str, target); - break; - case '#': - **str = 0; - /* fall through */ - case 0: - goto done; - case ';': - next = false; - goto done; - case '\\': - if (!parse_backslash(ctx, str)) - continue; - /* fall through */ - default: - addc(target, str); - break; - } - } while (**str && !isspace(**str)); -done: - - /* - * if the string was unquoted and we've stopped at a whitespace - * character, skip to the next one, because the whitespace will - * be overwritten by a null byte here - */ - if (**str && next) - *str += 1; - - /* terminate the parsed string */ - **target = 0; -} - -/* - * extract the next argument from the command line - */ -static char *next_arg(struct uci_context *ctx, char **str, bool required, bool name) -{ - char *val; - char *ptr; - - val = ptr = *str; - skip_whitespace(ctx, str); - if(*str[0] == ';') { - *str[0] = 0; - *str += 1; - } else { - parse_str(ctx, str, &ptr); - } - if (!*val) { - if (required) - uci_parse_error(ctx, *str, "insufficient arguments"); - goto done; - } - - if (name && !uci_validate_name(val)) - uci_parse_error(ctx, val, "invalid character in field"); - -done: - return val; -} - -int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char **result) -{ - UCI_HANDLE_ERR(ctx); - UCI_ASSERT(ctx, str != NULL); - UCI_ASSERT(ctx, result != NULL); - - if (ctx->pctx && (ctx->pctx->file != stream)) - uci_cleanup(ctx); - - if (!ctx->pctx) - uci_alloc_parse_context(ctx); - - ctx->pctx->file = stream; - - if (!*str) { - uci_getln(ctx, 0); - *str = ctx->pctx->buf; - } - - *result = next_arg(ctx, str, false, false); - - return 0; -} - /* * open a stream and go to the right position @@ -435,7 +187,7 @@ int uci_parse_argument(struct uci_context *ctx, FILE *stream, char **str, char * * note: when opening for write and seeking to the beginning of * the stream, truncate the file */ -static FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create) +__private FILE *uci_open_stream(struct uci_context *ctx, const char *filename, int pos, bool write, bool create) { struct stat statbuf; FILE *file = NULL; @@ -473,7 +225,7 @@ done: return file; } -static void uci_close_stream(FILE *stream) +__private void uci_close_stream(FILE *stream) { int fd; -- 2.11.0