aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/ucl/include/ucl.h10
-rw-r--r--src/ucl/src/ucl_parser.c86
-rw-r--r--src/ucl/src/ucl_util.c60
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, &macro_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) {