]> source.dussan.org Git - rspamd.git/commitdiff
Sync from libucl.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 19 Dec 2013 13:44:02 +0000 (13:44 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 19 Dec 2013 13:44:02 +0000 (13:44 +0000)
src/ucl/include/ucl.h
src/ucl/src/ucl_parser.c
src/ucl/src/ucl_util.c

index 3b4008e8712424f3294dbe4dfeed77b26b5b7e85..632c6e1702f1f8960227b7d7281a4354ffd98b93 100644 (file)
@@ -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;
 
 /**
index a22389ae9065b9dfb787e0292af5559efc67c6ba..0441a121c355c3b3ece477d8548a46759e69edc9 100644 (file)
@@ -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
index cf9cf99b0b755f6b3c3f6cc714383267ef807648..470d291637aeca6877c12632e9280fdafb25fe6e 100644 (file)
@@ -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);
        }
@@ -692,17 +709,56 @@ ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
        return ucl_include_url (data, len, parser, true);
 }
 
+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) {