diff options
-rw-r--r-- | src/ucl/include/ucl.h | 10 | ||||
-rw-r--r-- | src/ucl/src/ucl_parser.c | 86 | ||||
-rw-r--r-- | src/ucl/src/ucl_util.c | 60 |
3 files changed, 137 insertions, 19 deletions
diff --git a/src/ucl/include/ucl.h b/src/ucl/include/ucl.h index 3b4008e87..632c6e170 100644 --- a/src/ucl/include/ucl.h +++ b/src/ucl/include/ucl.h @@ -775,6 +775,16 @@ unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type); */ bool ucl_pubkey_add (struct ucl_parser *parser, const unsigned char *key, size_t len); +/** + * Set FILENAME and CURDIR variables in parser + * @param parser parser object + * @param filename filename to set or NULL to set FILENAME to "undef" and CURDIR to getcwd() + * @param need_expand perform realpath() if this variable is true and filename is not NULL + * @return true if variables has been set + */ +bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, + bool need_expand); + typedef void* ucl_object_iter_t; /** diff --git a/src/ucl/src/ucl_parser.c b/src/ucl/src/ucl_parser.c index a22389ae9..0441a121c 100644 --- a/src/ucl/src/ucl_parser.c +++ b/src/ucl/src/ucl_parser.c @@ -86,8 +86,14 @@ ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state static inline void ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err) { - ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'", - chunk->line, chunk->column, str, *chunk->pos); + if (isgraph (*chunk->pos)) { + ucl_create_err (err, "error on line %d at column %d: '%s', character: '%c'", + chunk->line, chunk->column, str, *chunk->pos); + } + else { + ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'", + chunk->line, chunk->column, str, (int)*chunk->pos); + } } /** @@ -926,6 +932,12 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke *end_of_object = true; return true; } + else if (*p == '.') { + ucl_chunk_skipc (chunk, p); + parser->prev_state = parser->state; + parser->state = UCL_STATE_MACRO_NAME; + return true; + } else { /* Invalid identifier */ ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err); @@ -1534,8 +1546,14 @@ ucl_state_machine (struct ucl_parser *parser) bool next_key = false, end_of_object = false; if (parser->top_obj == NULL) { - obj = ucl_add_parser_stack (NULL, parser, false, 0); + if (*chunk->pos == '[') { + obj = ucl_add_parser_stack (NULL, parser, true, 0); + } + else { + obj = ucl_add_parser_stack (NULL, parser, false, 0); + } parser->top_obj = obj; + parser->cur_obj = obj; parser->state = UCL_STATE_INIT; } @@ -1548,7 +1566,7 @@ ucl_state_machine (struct ucl_parser *parser) * if we got [ or { correspondingly or can just treat new data as * a key of newly created object */ - obj = parser->top_obj; + obj = parser->cur_obj; if (!ucl_skip_comments (parser)) { parser->prev_state = parser->state; parser->state = UCL_STATE_ERROR; @@ -1558,14 +1576,10 @@ ucl_state_machine (struct ucl_parser *parser) p = chunk->pos; if (*p == '[') { parser->state = UCL_STATE_VALUE; - obj->type = UCL_ARRAY; - ucl_hash_destroy (obj->value.ov, NULL); - obj->value.av = NULL; ucl_chunk_skipc (chunk, p); } else { parser->state = UCL_STATE_KEY; - obj->type = UCL_OBJECT; if (*p == '{') { ucl_chunk_skipc (chunk, p); } @@ -1675,7 +1689,7 @@ ucl_state_machine (struct ucl_parser *parser) return false; } macro_len = ucl_expand_variable (parser, ¯o_escaped, macro_start, macro_len); - parser->state = UCL_STATE_KEY; + parser->state = parser->prev_state; if (macro_escaped == NULL) { if (!macro->handler (macro_start, macro_len, macro->ud)) { return false; @@ -1714,6 +1728,9 @@ ucl_parser_new (int flags) new->flags = flags; + /* Initial assumption about filevars */ + ucl_parser_set_filevars (new, NULL, false); + return new; } @@ -1736,16 +1753,51 @@ void ucl_parser_register_variable (struct ucl_parser *parser, const char *var, const char *value) { - struct ucl_variable *new; + struct ucl_variable *new = NULL, *cur; + + if (var == NULL) { + return; + } - new = UCL_ALLOC (sizeof (struct ucl_variable)); - memset (new, 0, sizeof (struct ucl_variable)); - new->var = strdup (var); - new->var_len = strlen (var); - new->value = strdup (value); - new->value_len = strlen (value); + /* Find whether a variable already exists */ + LL_FOREACH (parser->variables, cur) { + if (strcmp (cur->var, var) == 0) { + new = cur; + break; + } + } + + if (value == NULL) { + + if (new != NULL) { + /* Remove variable */ + LL_DELETE (parser->variables, new); + free (new->var); + free (new->value); + UCL_FREE (sizeof (struct ucl_variable), new); + } + else { + /* Do nothing */ + return; + } + } + else { + if (new == NULL) { + new = UCL_ALLOC (sizeof (struct ucl_variable)); + memset (new, 0, sizeof (struct ucl_variable)); + new->var = strdup (var); + new->var_len = strlen (var); + new->value = strdup (value); + new->value_len = strlen (value); - LL_PREPEND (parser->variables, new); + LL_PREPEND (parser->variables, new); + } + else { + free (new->value); + new->value = strdup (value); + new->value_len = strlen (value); + } + } } bool diff --git a/src/ucl/src/ucl_util.c b/src/ucl/src/ucl_util.c index cf9cf99b0..470d29163 100644 --- a/src/ucl/src/ucl_util.c +++ b/src/ucl/src/ucl_util.c @@ -25,6 +25,8 @@ #include "ucl_internal.h" #include "ucl_chartable.h" +#include <libgen.h> /* For dirname */ + #ifdef HAVE_OPENSSL #include <openssl/err.h> #include <openssl/sha.h> @@ -439,7 +441,7 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl int fd; struct stat st; - if (stat (filename, &st) == -1) { + if (stat (filename, &st) == -1 || !S_ISREG (st.st_mode)) { ucl_create_err (err, "cannot stat file %s: %s", filename, strerror (errno)); return false; @@ -535,6 +537,7 @@ ucl_include_url (const unsigned char *data, size_t len, size_t buflen = 0; struct ucl_chunk *chunk; char urlbuf[PATH_MAX]; + int prev_state; snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data); @@ -566,6 +569,9 @@ ucl_include_url (const unsigned char *data, size_t len, #endif } + prev_state = parser->state; + parser->state = UCL_STATE_INIT; + res = ucl_parser_add_chunk (parser, buf, buflen); if (res == true) { /* Remove chunk from the stack */ @@ -575,6 +581,8 @@ ucl_include_url (const unsigned char *data, size_t len, UCL_FREE (sizeof (struct ucl_chunk), chunk); } } + + parser->state = prev_state; free (buf); return res; @@ -597,6 +605,7 @@ ucl_include_file (const unsigned char *data, size_t len, unsigned char *buf = NULL; size_t buflen; char filebuf[PATH_MAX], realbuf[PATH_MAX]; + int prev_state; snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data); if (realpath (filebuf, realbuf) == NULL) { @@ -634,6 +643,11 @@ ucl_include_file (const unsigned char *data, size_t len, #endif } + ucl_parser_set_filevars (parser, realbuf, false); + + prev_state = parser->state; + parser->state = UCL_STATE_INIT; + res = ucl_parser_add_chunk (parser, buf, buflen); if (res == true) { /* Remove chunk from the stack */ @@ -643,6 +657,9 @@ ucl_include_file (const unsigned char *data, size_t len, UCL_FREE (sizeof (struct ucl_chunk), chunk); } } + + parser->state = prev_state; + if (buflen > 0) { munmap (buf, buflen); } @@ -693,16 +710,55 @@ ucl_includes_handler (const unsigned char *data, size_t len, void* ud) } bool +ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename, bool need_expand) +{ + char realbuf[PATH_MAX], *curdir; + + if (filename != NULL) { + if (need_expand) { + if (realpath (filename, realbuf) == NULL) { + return false; + } + } + else { + ucl_strlcpy (realbuf, filename, sizeof (realbuf)); + } + + /* Define variables */ + ucl_parser_register_variable (parser, "FILENAME", realbuf); + curdir = dirname (realbuf); + ucl_parser_register_variable (parser, "CURDIR", curdir); + } + else { + /* Set everything from the current dir */ + curdir = getcwd (realbuf, sizeof (realbuf)); + ucl_parser_register_variable (parser, "FILENAME", "undef"); + ucl_parser_register_variable (parser, "CURDIR", curdir); + } + + return true; +} + +bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename) { unsigned char *buf; size_t len; bool ret; + char realbuf[PATH_MAX]; + + if (realpath (filename, realbuf) == NULL) { + ucl_create_err (&parser->err, "cannot open file %s: %s", + filename, + strerror (errno)); + return false; + } - if (!ucl_fetch_file (filename, &buf, &len, &parser->err)) { + if (!ucl_fetch_file (realbuf, &buf, &len, &parser->err)) { return false; } + ucl_parser_set_filevars (parser, realbuf, false); ret = ucl_parser_add_chunk (parser, buf, len); if (len > 0) { |