summaryrefslogtreecommitdiffstats
path: root/contrib/libucl/src
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2014-11-29 00:45:09 +0000
committerbapt <bapt@FreeBSD.org>2014-11-29 00:45:09 +0000
commit7d08b91413fa16522ce2fe9052df826886fe42e4 (patch)
treeda7419ce979eaeb23133fbdfa13129abcde1cfc9 /contrib/libucl/src
parent2aa5fef0aaa6b189fbabb79e67c84c76a4a40d3b (diff)
parent040f7be2fc3d89695611d460fd55d9b018fd7aa2 (diff)
downloadFreeBSD-src-7d08b91413fa16522ce2fe9052df826886fe42e4.zip
FreeBSD-src-7d08b91413fa16522ce2fe9052df826886fe42e4.tar.gz
Update libucl to latest version
While here correctly link libucl to libm and register the dependency on libm for static building
Diffstat (limited to 'contrib/libucl/src')
-rw-r--r--contrib/libucl/src/ucl_emitter.c64
-rw-r--r--contrib/libucl/src/ucl_emitter_streamline.c3
-rw-r--r--contrib/libucl/src/ucl_emitter_utils.c58
-rw-r--r--contrib/libucl/src/ucl_hash.c15
-rw-r--r--contrib/libucl/src/ucl_hash.h6
-rw-r--r--contrib/libucl/src/ucl_internal.h40
-rw-r--r--contrib/libucl/src/ucl_parser.c422
-rw-r--r--contrib/libucl/src/ucl_util.c581
8 files changed, 989 insertions, 200 deletions
diff --git a/contrib/libucl/src/ucl_emitter.c b/contrib/libucl/src/ucl_emitter.c
index 11fe50c..8134d09 100644
--- a/contrib/libucl/src/ucl_emitter.c
+++ b/contrib/libucl/src/ucl_emitter.c
@@ -130,6 +130,19 @@ ucl_emitter_print_key (bool print_key, struct ucl_emitter_context *ctx,
func->ucl_emitter_append_character (' ', 1, func->ud);
}
}
+ else if (ctx->id == UCL_EMIT_YAML) {
+ if (obj->keylen > 0 && (obj->flags & UCL_OBJECT_NEED_KEY_ESCAPE)) {
+ ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
+ }
+ else if (obj->keylen > 0) {
+ func->ucl_emitter_append_len (obj->key, obj->keylen, func->ud);
+ }
+ else {
+ func->ucl_emitter_append_len ("null", 4, func->ud);
+ }
+
+ func->ucl_emitter_append_len (": ", 2, func->ud);
+ }
else {
if (obj->keylen > 0) {
ucl_elt_string_write_json (obj->key, obj->keylen, ctx);
@@ -182,7 +195,7 @@ ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
const struct ucl_emitter_functions *func = ctx->func;
if (UCL_EMIT_IDENT_TOP_OBJ(ctx, obj)) {
- ctx->ident --;
+ ctx->indent --;
if (compact) {
func->ucl_emitter_append_character ('}', 1, func->ud);
}
@@ -191,7 +204,7 @@ ucl_emitter_common_end_object (struct ucl_emitter_context *ctx,
/* newline is already added for this format */
func->ucl_emitter_append_character ('\n', 1, func->ud);
}
- ucl_add_tabs (func, ctx->ident, compact);
+ ucl_add_tabs (func, ctx->indent, compact);
func->ucl_emitter_append_character ('}', 1, func->ud);
}
}
@@ -210,7 +223,7 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
{
const struct ucl_emitter_functions *func = ctx->func;
- ctx->ident --;
+ ctx->indent --;
if (compact) {
func->ucl_emitter_append_character (']', 1, func->ud);
}
@@ -219,7 +232,7 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,
/* newline is already added for this format */
func->ucl_emitter_append_character ('\n', 1, func->ud);
}
- ucl_add_tabs (func, ctx->ident, compact);
+ ucl_add_tabs (func, ctx->indent, compact);
func->ucl_emitter_append_character (']', 1, func->ud);
}
@@ -249,7 +262,7 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,
func->ucl_emitter_append_len ("[\n", 2, func->ud);
}
- ctx->ident ++;
+ ctx->indent ++;
if (obj->type == UCL_ARRAY) {
/* explicit array */
@@ -294,7 +307,7 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
else {
func->ucl_emitter_append_len ("{\n", 2, func->ud);
}
- ctx->ident ++;
+ ctx->indent ++;
}
while ((cur = ucl_hash_iterate (obj->value.ov, &it))) {
@@ -315,7 +328,7 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,
func->ucl_emitter_append_len (",\n", 2, func->ud);
}
}
- ucl_add_tabs (func, ctx->ident, compact);
+ ucl_add_tabs (func, ctx->indent, compact);
ucl_emitter_common_start_array (ctx, cur, true, compact);
ucl_emitter_common_end_array (ctx, cur, compact);
}
@@ -342,17 +355,23 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
{
const struct ucl_emitter_functions *func = ctx->func;
bool flag;
+ struct ucl_object_userdata *ud;
+ const char *ud_out = "";
if (ctx->id != UCL_EMIT_CONFIG && !first) {
if (compact) {
func->ucl_emitter_append_character (',', 1, func->ud);
}
else {
- func->ucl_emitter_append_len (",\n", 2, func->ud);
+ if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) {
+ func->ucl_emitter_append_len ("\n", 1, func->ud);
+ } else {
+ func->ucl_emitter_append_len (",\n", 2, func->ud);
+ }
}
}
- ucl_add_tabs (func, ctx->ident, compact);
+ ucl_add_tabs (func, ctx->indent, compact);
switch (obj->type) {
case UCL_INT:
@@ -379,7 +398,12 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
break;
case UCL_STRING:
ucl_emitter_print_key (print_key, ctx, obj, compact);
- ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
+ if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
+ ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
+ }
+ else {
+ ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
+ }
ucl_emitter_finish_object (ctx, obj, compact, !print_key);
break;
case UCL_NULL:
@@ -396,6 +420,16 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_emitter_common_end_array (ctx, obj, compact);
break;
case UCL_USERDATA:
+ ud = (struct ucl_object_userdata *)obj;
+ ucl_emitter_print_key (print_key, ctx, obj, compact);
+ if (ud->emitter) {
+ ud_out = ud->emitter (obj->value.ud);
+ if (ud_out == NULL) {
+ ud_out = "null";
+ }
+ }
+ ucl_elt_string_write_json (ud_out, strlen (ud_out), ctx);
+ ucl_emitter_finish_object (ctx, obj, compact, !print_key);
break;
}
}
@@ -425,10 +459,10 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
ucl_emitter_common_end_array (ctx, obj, (compact)); \
}
-UCL_EMIT_TYPE_IMPL(json, false);
-UCL_EMIT_TYPE_IMPL(json_compact, true);
-UCL_EMIT_TYPE_IMPL(config, false);
-UCL_EMIT_TYPE_IMPL(yaml, false);
+UCL_EMIT_TYPE_IMPL(json, false)
+UCL_EMIT_TYPE_IMPL(json_compact, true)
+UCL_EMIT_TYPE_IMPL(config, false)
+UCL_EMIT_TYPE_IMPL(yaml, false)
unsigned char *
ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
@@ -461,7 +495,7 @@ ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
if (ctx != NULL) {
memcpy (&my_ctx, ctx, sizeof (my_ctx));
my_ctx.func = emitter;
- my_ctx.ident = 0;
+ my_ctx.indent = 0;
my_ctx.top = obj;
my_ctx.ops->ucl_emitter_write_elt (&my_ctx, obj, true, false);
diff --git a/contrib/libucl/src/ucl_emitter_streamline.c b/contrib/libucl/src/ucl_emitter_streamline.c
index acf4a30..ff27c88 100644
--- a/contrib/libucl/src/ucl_emitter_streamline.c
+++ b/contrib/libucl/src/ucl_emitter_streamline.c
@@ -108,9 +108,8 @@ ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx,
st->is_array = false;
sctx->ops->ucl_emitter_start_object (ctx, obj, print_key);
}
+ LL_PREPEND (sctx->containers, st);
}
-
- LL_PREPEND (sctx->containers, st);
}
void
diff --git a/contrib/libucl/src/ucl_emitter_utils.c b/contrib/libucl/src/ucl_emitter_utils.c
index c619ab9..da41209 100644
--- a/contrib/libucl/src/ucl_emitter_utils.c
+++ b/contrib/libucl/src/ucl_emitter_utils.c
@@ -93,9 +93,7 @@ ucl_elt_string_write_json (const char *str, size_t size,
size_t len = 0;
const struct ucl_emitter_functions *func = ctx->func;
- if (ctx->id != UCL_EMIT_YAML) {
- func->ucl_emitter_append_character ('"', 1, func->ud);
- }
+ func->ucl_emitter_append_character ('"', 1, func->ud);
while (size) {
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
@@ -137,9 +135,18 @@ ucl_elt_string_write_json (const char *str, size_t size,
if (len > 0) {
func->ucl_emitter_append_len (c, len, func->ud);
}
- if (ctx->id != UCL_EMIT_YAML) {
- func->ucl_emitter_append_character ('"', 1, func->ud);
- }
+ func->ucl_emitter_append_character ('"', 1, func->ud);
+}
+
+void
+ucl_elt_string_write_multiline (const char *str, size_t size,
+ struct ucl_emitter_context *ctx)
+{
+ const struct ucl_emitter_functions *func = ctx->func;
+
+ func->ucl_emitter_append_len ("<<EOD\n", sizeof ("<<EOD\n") - 1, func->ud);
+ func->ucl_emitter_append_len (str, size, func->ud);
+ func->ucl_emitter_append_len ("\nEOD", sizeof ("\nEOD") - 1, func->ud);
}
/*
@@ -154,7 +161,7 @@ ucl_utstring_append_character (unsigned char c, size_t len, void *ud)
utstring_append_c (buf, c);
}
else {
- utstring_reserve (buf, len);
+ utstring_reserve (buf, len + 1);
memset (&buf->d[buf->i], c, len);
buf->i += len;
buf->d[buf->i] = '\0';
@@ -267,19 +274,23 @@ ucl_fd_append_character (unsigned char c, size_t len, void *ud)
unsigned char *buf;
if (len == 1) {
- write (fd, &c, 1);
+ return write (fd, &c, 1);
}
else {
buf = malloc (len);
if (buf == NULL) {
/* Fallback */
while (len --) {
- write (fd, &c, 1);
+ if (write (fd, &c, 1) == -1) {
+ return -1;
+ }
}
}
else {
memset (buf, c, len);
- write (fd, buf, len);
+ if (write (fd, buf, len) == -1) {
+ return -1;
+ }
free (buf);
}
}
@@ -292,9 +303,7 @@ ucl_fd_append_len (const unsigned char *str, size_t len, void *ud)
{
int fd = *(int *)ud;
- write (fd, str, len);
-
- return 0;
+ return write (fd, str, len);
}
static int
@@ -304,9 +313,7 @@ ucl_fd_append_int (int64_t val, void *ud)
char intbuf[64];
snprintf (intbuf, sizeof (intbuf), "%jd", (intmax_t)val);
- write (fd, intbuf, strlen (intbuf));
-
- return 0;
+ return write (fd, intbuf, strlen (intbuf));
}
static int
@@ -327,9 +334,7 @@ ucl_fd_append_double (double val, void *ud)
snprintf (nbuf, sizeof (nbuf), "%lf", val);
}
- write (fd, nbuf, strlen (nbuf));
-
- return 0;
+ return write (fd, nbuf, strlen (nbuf));
}
struct ucl_emitter_functions*
@@ -464,3 +469,18 @@ ucl_object_emit_single_json (const ucl_object_t *obj)
return res;
}
+
+#define LONG_STRING_LIMIT 80
+
+bool
+ucl_maybe_long_string (const ucl_object_t *obj)
+{
+ if (obj->len > LONG_STRING_LIMIT || (obj->flags & UCL_OBJECT_MULTILINE)) {
+ /* String is long enough, so search for newline characters in it */
+ if (memchr (obj->value.sv, '\n', obj->len) != NULL) {
+ return true;
+ }
+ }
+
+ return false;
+}
diff --git a/contrib/libucl/src/ucl_hash.c b/contrib/libucl/src/ucl_hash.c
index c2e80cb..ea55491 100644
--- a/contrib/libucl/src/ucl_hash.c
+++ b/contrib/libucl/src/ucl_hash.c
@@ -66,6 +66,20 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
}
+void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
+ const ucl_object_t *new)
+{
+ ucl_hash_node_t *node;
+
+ HASH_FIND (hh, hashlin->buckets, old->key, old->keylen, node);
+ if (node != NULL) {
+ /* Direct replacement */
+ node->data = new;
+ node->hh.key = new->key;
+ node->hh.keylen = new->keylen;
+ }
+}
+
const void*
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
{
@@ -122,5 +136,6 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
if (found) {
HASH_DELETE (hh, hashlin->buckets, found);
+ UCL_FREE (sizeof (ucl_hash_node_t), found);
}
}
diff --git a/contrib/libucl/src/ucl_hash.h b/contrib/libucl/src/ucl_hash.h
index cbbf005..ddbfdba 100644
--- a/contrib/libucl/src/ucl_hash.h
+++ b/contrib/libucl/src/ucl_hash.h
@@ -66,6 +66,12 @@ void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *
unsigned keylen);
/**
+ * Replace element in the hash
+ */
+void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
+ const ucl_object_t *new);
+
+/**
* Delete an element from the the hashtable.
*/
void ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj);
diff --git a/contrib/libucl/src/ucl_internal.h b/contrib/libucl/src/ucl_internal.h
index 0ac8de8..2f75872 100644
--- a/contrib/libucl/src/ucl_internal.h
+++ b/contrib/libucl/src/ucl_internal.h
@@ -163,6 +163,7 @@ struct ucl_chunk {
size_t remain;
unsigned int line;
unsigned int column;
+ unsigned priority;
struct ucl_chunk *next;
};
@@ -182,7 +183,7 @@ struct ucl_variable {
char *value;
size_t var_len;
size_t value_len;
- struct ucl_variable *next;
+ struct ucl_variable *prev, *next;
};
struct ucl_parser {
@@ -192,6 +193,7 @@ struct ucl_parser {
int flags;
ucl_object_t *top_obj;
ucl_object_t *cur_obj;
+ char *cur_file;
struct ucl_macro *macroes;
struct ucl_stack *stack;
struct ucl_chunk *chunks;
@@ -202,6 +204,12 @@ struct ucl_parser {
UT_string *err;
};
+struct ucl_object_userdata {
+ ucl_object_t obj;
+ ucl_userdata_dtor dtor;
+ ucl_userdata_emitter emitter;
+};
+
/**
* Unescape json string inplace
* @param str
@@ -216,9 +224,11 @@ size_t ucl_unescape_json_string (char *str, size_t len);
* @param err error ptr
* @return
*/
-bool ucl_include_handler (const unsigned char *data, size_t len, void* ud);
+bool ucl_include_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud);
-bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
+bool ucl_try_include_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud);
/**
* Handle includes macro
@@ -228,7 +238,8 @@ bool ucl_try_include_handler (const unsigned char *data, size_t len, void* ud);
* @param err error ptr
* @return
*/
-bool ucl_includes_handler (const unsigned char *data, size_t len, void* ud);
+bool ucl_includes_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud);
size_t ucl_strlcpy (char *dst, const char *src, size_t siz);
size_t ucl_strlcpy_unsafe (char *dst, const char *src, size_t siz);
@@ -264,7 +275,7 @@ ucl_create_err (UT_string **err, const char *fmt, ...)
static inline bool
ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t len)
{
- const unsigned char *p = start;
+ const char *p = (const char *)start;
bool ret = false, val = false;
if (len == 5) {
@@ -351,7 +362,7 @@ const struct ucl_emitter_context *
ucl_emit_get_standard_context (enum ucl_emitter emit_type);
/**
- * Serialise string
+ * Serialize string as JSON string
* @param str string to emit
* @param buf target buffer
*/
@@ -359,10 +370,27 @@ void ucl_elt_string_write_json (const char *str, size_t size,
struct ucl_emitter_context *ctx);
/**
+ * Write multiline string using `EOD` as string terminator
+ * @param str
+ * @param size
+ * @param ctx
+ */
+void ucl_elt_string_write_multiline (const char *str, size_t size,
+ struct ucl_emitter_context *ctx);
+
+/**
* Emit a single object to string
* @param obj
* @return
*/
unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj);
+/**
+ * Check whether a specified string is long and should be likely printed in
+ * multiline mode
+ * @param obj
+ * @return
+ */
+bool ucl_maybe_long_string (const ucl_object_t *obj);
+
#endif /* UCL_INTERNAL_H_ */
diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c
index e51a54b..0d118d8 100644
--- a/contrib/libucl/src/ucl_parser.c
+++ b/contrib/libucl/src/ucl_parser.c
@@ -26,8 +26,8 @@
#include "ucl_chartable.h"
/**
- * @file rcl_parser.c
- * The implementation of rcl parser
+ * @file ucl_parser.c
+ * The implementation of ucl parser
*/
struct ucl_parser_saved_state {
@@ -56,20 +56,33 @@ struct ucl_parser_saved_state {
} while (0)
static inline void
-ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
+ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
{
+ const char *fmt_string, *filename;
+ struct ucl_chunk *chunk = parser->chunks;
+
+ if (parser->cur_file) {
+ filename = parser->cur_file;
+ }
+ else {
+ filename = "<unknown>";
+ }
if (chunk->pos < chunk->end) {
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);
+ fmt_string = "error while parsing %s: "
+ "line: %d, column: %d - '%s', character: '%c'";
}
else {
- ucl_create_err (err, "error on line %d at column %d: '%s', character: '0x%02x'",
- chunk->line, chunk->column, str, (int)*chunk->pos);
+ fmt_string = "error while parsing %s: "
+ "line: %d, column: %d - '%s', character: '0x%02x'";
}
+ ucl_create_err (err, fmt_string,
+ filename, chunk->line, chunk->column,
+ str, *chunk->pos);
}
else {
- ucl_create_err (err, "error at the end of chunk: %s", str);
+ ucl_create_err (err, "error while parsing %s: at the end of chunk: %s",
+ filename, str);
}
}
@@ -84,11 +97,12 @@ ucl_skip_comments (struct ucl_parser *parser)
struct ucl_chunk *chunk = parser->chunks;
const unsigned char *p;
int comments_nested = 0;
+ bool quoted = false;
p = chunk->pos;
start:
- if (*p == '#') {
+ if (chunk->remain > 0 && *p == '#') {
if (parser->state != UCL_STATE_SCOMMENT &&
parser->state != UCL_STATE_MCOMMENT) {
while (p < chunk->end) {
@@ -100,34 +114,41 @@ start:
}
}
}
- else if (*p == '/' && chunk->remain >= 2) {
+ else if (chunk->remain >= 2 && *p == '/') {
if (p[1] == '*') {
ucl_chunk_skipc (chunk, p);
comments_nested ++;
ucl_chunk_skipc (chunk, p);
while (p < chunk->end) {
- if (*p == '*') {
- ucl_chunk_skipc (chunk, p);
- if (*p == '/') {
- comments_nested --;
- if (comments_nested == 0) {
- ucl_chunk_skipc (chunk, p);
- goto start;
+ if (*p == '"' && *(p - 1) != '\\') {
+ quoted = !quoted;
+ }
+
+ if (!quoted) {
+ if (*p == '*') {
+ ucl_chunk_skipc (chunk, p);
+ if (*p == '/') {
+ comments_nested --;
+ if (comments_nested == 0) {
+ ucl_chunk_skipc (chunk, p);
+ goto start;
+ }
}
+ ucl_chunk_skipc (chunk, p);
+ }
+ else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
+ comments_nested ++;
+ ucl_chunk_skipc (chunk, p);
+ ucl_chunk_skipc (chunk, p);
+ continue;
}
- ucl_chunk_skipc (chunk, p);
- }
- else if (p[0] == '/' && chunk->remain >= 2 && p[1] == '*') {
- comments_nested ++;
- ucl_chunk_skipc (chunk, p);
- ucl_chunk_skipc (chunk, p);
- continue;
}
ucl_chunk_skipc (chunk, p);
}
if (comments_nested != 0) {
- ucl_set_err (chunk, UCL_ENESTED, "unfinished multiline comment", &parser->err);
+ ucl_set_err (parser, UCL_ENESTED,
+ "unfinished multiline comment", &parser->err);
return false;
}
}
@@ -492,7 +513,8 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
/* Copy string */
*dst = UCL_ALLOC (in_len + 1);
if (*dst == NULL) {
- ucl_set_err (parser->chunks, 0, "cannot allocate memory for a string", &parser->err);
+ ucl_set_err (parser, 0, "cannot allocate memory for a string",
+ &parser->err);
return false;
}
if (need_lowercase) {
@@ -514,6 +536,10 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
*dst = tmp;
ret = tret;
}
+ else {
+ /* Free unexpanded value */
+ UCL_FREE (in_len + 1, tmp);
+ }
}
*dst_const = *dst;
}
@@ -539,7 +565,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
if (!is_array) {
if (obj == NULL) {
- obj = ucl_object_typed_new (UCL_OBJECT);
+ obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
}
else {
obj->type = UCL_OBJECT;
@@ -549,7 +575,7 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
}
else {
if (obj == NULL) {
- obj = ucl_object_typed_new (UCL_ARRAY);
+ obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
}
else {
obj->type = UCL_ARRAY;
@@ -559,7 +585,9 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
st = UCL_ALLOC (sizeof (struct ucl_stack));
if (st == NULL) {
- ucl_set_err (parser->chunks, 0, "cannot allocate memory for an object", &parser->err);
+ ucl_set_err (parser, 0, "cannot allocate memory for an object",
+ &parser->err);
+ ucl_object_unref (obj);
return NULL;
}
st->obj = obj;
@@ -676,8 +704,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
}
/* Now check endptr */
- if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' ||
- ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+ if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
p = endptr;
goto set_obj;
}
@@ -788,8 +815,21 @@ ucl_maybe_parse_number (ucl_object_t *obj,
goto set_obj;
}
break;
+ case '\t':
+ case ' ':
+ while (p < end && ucl_test_character(*p, UCL_CHARACTER_WHITESPACE)) {
+ p++;
+ }
+ if (ucl_lex_is_atom_end(*p))
+ goto set_obj;
+ break;
}
}
+ else if (endptr == end) {
+ /* Just a number at the end of chunk */
+ p = endptr;
+ goto set_obj;
+ }
*pos = c;
return EINVAL;
@@ -835,7 +875,7 @@ ucl_lex_number (struct ucl_parser *parser,
return true;
}
else if (ret == ERANGE) {
- ucl_set_err (chunk, ERANGE, "numeric value out of range", &parser->err);
+ ucl_set_err (parser, ERANGE, "numeric value out of range", &parser->err);
}
return false;
@@ -860,10 +900,12 @@ ucl_lex_json_string (struct ucl_parser *parser,
if (c < 0x1F) {
/* Unmasked control character */
if (c == '\n') {
- ucl_set_err (chunk, UCL_ESYNTAX, "unexpected newline", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unexpected newline",
+ &parser->err);
}
else {
- ucl_set_err (chunk, UCL_ESYNTAX, "unexpected control character", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unexpected control character",
+ &parser->err);
}
return false;
}
@@ -871,7 +913,8 @@ ucl_lex_json_string (struct ucl_parser *parser,
ucl_chunk_skipc (chunk, p);
c = *p;
if (p >= chunk->end) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
+ &parser->err);
return false;
}
else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {
@@ -879,13 +922,15 @@ ucl_lex_json_string (struct ucl_parser *parser,
ucl_chunk_skipc (chunk, p);
for (i = 0; i < 4 && p < chunk->end; i ++) {
if (!isxdigit (*p)) {
- ucl_set_err (chunk, UCL_ESYNTAX, "invalid utf escape", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "invalid utf escape",
+ &parser->err);
return false;
}
ucl_chunk_skipc (chunk, p);
}
if (p >= chunk->end) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unfinished escape character", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
+ &parser->err);
return false;
}
}
@@ -910,10 +955,42 @@ ucl_lex_json_string (struct ucl_parser *parser,
ucl_chunk_skipc (chunk, p);
}
- ucl_set_err (chunk, UCL_ESYNTAX, "no quote at the end of json string", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
+ &parser->err);
return false;
}
+static void
+ucl_parser_append_elt (struct ucl_parser *parser, ucl_hash_t *cont,
+ ucl_object_t *top,
+ ucl_object_t *elt)
+{
+ ucl_object_t *nobj;
+
+ if ((parser->flags & UCL_PARSER_NO_IMPLICIT_ARRAYS) == 0) {
+ /* Implicit array */
+ top->flags |= UCL_OBJECT_MULTIVALUE;
+ DL_APPEND (top, elt);
+ }
+ else {
+ if ((top->flags & UCL_OBJECT_MULTIVALUE) != 0) {
+ /* Just add to the explicit array */
+ DL_APPEND (top->value.av, elt);
+ }
+ else {
+ /* Convert to an array */
+ ucl_hash_delete (cont, top);
+ nobj = ucl_object_typed_new (UCL_ARRAY);
+ nobj->key = top->key;
+ nobj->keylen = top->keylen;
+ nobj->flags |= UCL_OBJECT_MULTIVALUE;
+ DL_APPEND (nobj->value.av, top);
+ DL_APPEND (nobj->value.av, elt);
+ ucl_hash_insert (cont, nobj, nobj->key, nobj->keylen);
+ }
+ }
+}
+
/**
* Parse a key in an object
* @param parser
@@ -981,7 +1058,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
}
else {
/* Invalid identifier */
- ucl_set_err (chunk, UCL_ESYNTAX, "key must begin with a letter", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "key must begin with a letter",
+ &parser->err);
return false;
}
}
@@ -997,7 +1075,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
break;
}
else {
- ucl_set_err (chunk, UCL_ESYNTAX, "invalid character in a key", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "invalid character in a key",
+ &parser->err);
return false;
}
}
@@ -1015,7 +1094,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
}
if (p >= chunk->end && got_content) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
return false;
}
else if (!got_content) {
@@ -1033,7 +1112,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
got_eq = true;
}
else {
- ucl_set_err (chunk, UCL_ESYNTAX, "unexpected '=' character", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unexpected '=' character",
+ &parser->err);
return false;
}
}
@@ -1043,7 +1123,8 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
got_semicolon = true;
}
else {
- ucl_set_err (chunk, UCL_ESYNTAX, "unexpected ':' character", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unexpected ':' character",
+ &parser->err);
return false;
}
}
@@ -1061,7 +1142,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
}
if (p >= chunk->end && got_content) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unfinished key", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);
return false;
}
@@ -1096,7 +1177,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
}
/* Create a new object */
- nobj = ucl_object_new ();
+ nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
if (keylen == -1) {
@@ -1104,7 +1185,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
return false;
}
else if (keylen == 0) {
- ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
ucl_object_unref (nobj);
return false;
}
@@ -1120,7 +1201,27 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
parser->stack->obj->len ++;
}
else {
- DL_APPEND (tobj, nobj);
+ /*
+ * The logic here is the following:
+ *
+ * - if we have two objects with the same priority, then we form an
+ * implicit or explicit array
+ * - if a new object has bigger priority, then we overwrite an old one
+ * - if a new object has lower priority, then we ignore it
+ */
+ unsigned priold = ucl_object_get_priority (tobj),
+ prinew = ucl_object_get_priority (nobj);
+ if (priold == prinew) {
+ ucl_parser_append_elt (parser, container, tobj, nobj);
+ }
+ else if (priold > prinew) {
+ ucl_object_unref (nobj);
+ return true;
+ }
+ else {
+ ucl_hash_replace (container, tobj, nobj);
+ ucl_object_unref (tobj);
+ }
}
if (ucl_escape) {
@@ -1197,11 +1298,6 @@ ucl_parse_string_value (struct ucl_parser *parser,
ucl_chunk_skipc (chunk, p);
}
- if (p >= chunk->end) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unfinished value", &parser->err);
- return false;
- }
-
return true;
}
@@ -1219,7 +1315,7 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
int term_len, unsigned char const **beg,
bool *var_expand)
{
- const unsigned char *p, *c;
+ const unsigned char *p, *c, *tend;
bool newline = false;
int len = 0;
@@ -1232,7 +1328,13 @@ ucl_parse_multiline_string (struct ucl_parser *parser,
if (chunk->end - p < term_len) {
return 0;
}
- else if (memcmp (p, term, term_len) == 0 && (p[term_len] == '\n' || p[term_len] == '\r')) {
+ else if (memcmp (p, term, term_len) == 0) {
+ tend = p + term_len;
+ if (*tend != '\n' && *tend != ';' && *tend != ',') {
+ /* Incomplete terminator */
+ ucl_chunk_skipc (chunk, p);
+ continue;
+ }
len = p - c;
chunk->remain -= term_len;
chunk->pos = p + term_len;
@@ -1263,7 +1365,7 @@ ucl_get_value_object (struct ucl_parser *parser)
if (parser->stack->obj->type == UCL_ARRAY) {
/* Object must be allocated */
- obj = ucl_object_new ();
+ obj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
t = parser->stack->obj->value.av;
DL_APPEND (t, obj);
parser->cur_obj = obj;
@@ -1378,7 +1480,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
chunk->line ++;
if ((str_len = ucl_parse_multiline_string (parser, chunk, c,
p - c, &c, &var_expand)) == 0) {
- ucl_set_err (chunk, UCL_ESYNTAX, "unterminated multiline value", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "unterminated multiline value", &parser->err);
return false;
}
obj->type = UCL_STRING;
@@ -1423,7 +1526,8 @@ parse_string:
}
str_len = chunk->pos - c - stripped_spaces;
if (str_len <= 0) {
- ucl_set_err (chunk, 0, "string value must not be empty", &parser->err);
+ ucl_set_err (parser, 0, "string value must not be empty",
+ &parser->err);
return false;
}
else if (str_len == 4 && memcmp (c, "null", 4) == 0) {
@@ -1482,7 +1586,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
else if (ucl_test_character (*p, UCL_CHARACTER_VALUE_END)) {
if (*p == '}' || *p == ']') {
if (parser->stack == NULL) {
- ucl_set_err (chunk, UCL_ESYNTAX, "end of array or object detected without corresponding start", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "end of array or object detected without corresponding start",
+ &parser->err);
return false;
}
if ((*p == '}' && parser->stack->obj->type == UCL_OBJECT) ||
@@ -1503,7 +1609,9 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
}
}
else {
- ucl_set_err (chunk, UCL_ESYNTAX, "unexpected terminating symbol detected", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX,
+ "unexpected terminating symbol detected",
+ &parser->err);
return false;
}
@@ -1525,7 +1633,8 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
else {
/* Anything else */
if (!got_sep) {
- ucl_set_err (chunk, UCL_ESYNTAX, "delimiter is missing", &parser->err);
+ ucl_set_err (parser, UCL_ESYNTAX, "delimiter is missing",
+ &parser->err);
return false;
}
return true;
@@ -1613,6 +1722,120 @@ ucl_parse_macro_value (struct ucl_parser *parser,
}
/**
+ * Parse macro arguments as UCL object
+ * @param parser parser structure
+ * @param chunk the current data chunk
+ * @return
+ */
+static ucl_object_t *
+ucl_parse_macro_arguments (struct ucl_parser *parser,
+ struct ucl_chunk *chunk)
+{
+ ucl_object_t *res = NULL;
+ struct ucl_parser *params_parser;
+ int obraces = 1, ebraces = 0, state = 0;
+ const unsigned char *p, *c;
+ size_t args_len = 0;
+ struct ucl_parser_saved_state saved;
+
+ saved.column = chunk->column;
+ saved.line = chunk->line;
+ saved.pos = chunk->pos;
+ saved.remain = chunk->remain;
+ p = chunk->pos;
+
+ if (*p != '(' || chunk->remain < 2) {
+ return NULL;
+ }
+
+ /* Set begin and start */
+ ucl_chunk_skipc (chunk, p);
+ c = p;
+
+ while ((p) < (chunk)->end) {
+ switch (state) {
+ case 0:
+ /* Parse symbols and check for '(', ')' and '"' */
+ if (*p == '(') {
+ obraces ++;
+ }
+ else if (*p == ')') {
+ ebraces ++;
+ }
+ else if (*p == '"') {
+ state = 1;
+ }
+ /* Check pairing */
+ if (obraces == ebraces) {
+ state = 99;
+ }
+ else {
+ args_len ++;
+ }
+ /* Check overflow */
+ if (chunk->remain == 0) {
+ goto restore_chunk;
+ }
+ ucl_chunk_skipc (chunk, p);
+ break;
+ case 1:
+ /* We have quote character, so skip all but quotes */
+ if (*p == '"' && *(p - 1) != '\\') {
+ state = 0;
+ }
+ if (chunk->remain == 0) {
+ goto restore_chunk;
+ }
+ ucl_chunk_skipc (chunk, p);
+ break;
+ case 99:
+ /*
+ * We have read the full body of arguments, so we need to parse and set
+ * object from that
+ */
+ params_parser = ucl_parser_new (parser->flags);
+ if (!ucl_parser_add_chunk (params_parser, c, args_len)) {
+ ucl_set_err (parser, UCL_ESYNTAX, "macro arguments parsing error",
+ &parser->err);
+ }
+ else {
+ res = ucl_parser_get_object (params_parser);
+ }
+ ucl_parser_free (params_parser);
+
+ return res;
+
+ break;
+ }
+ }
+
+ return res;
+
+restore_chunk:
+ chunk->column = saved.column;
+ chunk->line = saved.line;
+ chunk->pos = saved.pos;
+ chunk->remain = saved.remain;
+
+ return NULL;
+}
+
+#define SKIP_SPACES_COMMENTS(parser, chunk, p) do { \
+ while ((p) < (chunk)->end) { \
+ if (!ucl_test_character (*(p), UCL_CHARACTER_WHITESPACE_UNSAFE)) { \
+ if ((chunk)->remain >= 2 && ucl_lex_is_comment ((p)[0], (p)[1])) { \
+ if (!ucl_skip_comments (parser)) { \
+ return false; \
+ } \
+ p = (chunk)->pos; \
+ } \
+ break; \
+ } \
+ ucl_chunk_skipc (chunk, p); \
+ } \
+} while(0)
+
+/**
* Handle the main states of rcl parser
* @param parser parser structure
* @param data the pointer to the beginning of a chunk
@@ -1622,13 +1845,13 @@ ucl_parse_macro_value (struct ucl_parser *parser,
static bool
ucl_state_machine (struct ucl_parser *parser)
{
- ucl_object_t *obj;
+ ucl_object_t *obj, *macro_args;
struct ucl_chunk *chunk = parser->chunks;
const unsigned char *p, *c = NULL, *macro_start = NULL;
unsigned char *macro_escaped;
size_t macro_len = 0;
struct ucl_macro *macro = NULL;
- bool next_key = false, end_of_object = false;
+ bool next_key = false, end_of_object = false, ret;
if (parser->top_obj == NULL) {
if (*chunk->pos == '[') {
@@ -1654,7 +1877,6 @@ 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->cur_obj;
if (!ucl_skip_comments (parser)) {
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
@@ -1691,7 +1913,7 @@ ucl_state_machine (struct ucl_parser *parser)
}
if (parser->stack == NULL) {
/* No objects are on stack, but we want to parse a key */
- ucl_set_err (chunk, UCL_ESYNTAX, "top object is finished but the parser "
+ ucl_set_err (parser, UCL_ESYNTAX, "top object is finished but the parser "
"expects a key", &parser->err);
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
@@ -1757,7 +1979,8 @@ ucl_state_machine (struct ucl_parser *parser)
p = chunk->pos;
break;
case UCL_STATE_MACRO_NAME:
- if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
+ if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE) &&
+ *p != '(') {
ucl_chunk_skipc (chunk, p);
}
else if (p - c > 0) {
@@ -1772,48 +1995,51 @@ ucl_state_machine (struct ucl_parser *parser)
return false;
}
/* Now we need to skip all spaces */
- while (p < chunk->end) {
- if (!ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
- if (chunk->remain >= 2 && ucl_lex_is_comment (p[0], p[1])) {
- /* Skip comment */
- if (!ucl_skip_comments (parser)) {
- return false;
- }
- p = chunk->pos;
- }
- break;
- }
- ucl_chunk_skipc (chunk, p);
- }
+ SKIP_SPACES_COMMENTS(parser, chunk, p);
parser->state = UCL_STATE_MACRO;
}
break;
case UCL_STATE_MACRO:
+ if (*chunk->pos == '(') {
+ macro_args = ucl_parse_macro_arguments (parser, chunk);
+ p = chunk->pos;
+ if (macro_args) {
+ SKIP_SPACES_COMMENTS(parser, chunk, p);
+ }
+ }
+ else {
+ macro_args = NULL;
+ }
if (!ucl_parse_macro_value (parser, chunk, macro,
&macro_start, &macro_len)) {
parser->prev_state = parser->state;
parser->state = UCL_STATE_ERROR;
return false;
}
- macro_len = ucl_expand_variable (parser, &macro_escaped, macro_start, macro_len);
+ macro_len = ucl_expand_variable (parser, &macro_escaped,
+ macro_start, macro_len);
parser->state = parser->prev_state;
if (macro_escaped == NULL) {
- if (!macro->handler (macro_start, macro_len, macro->ud)) {
- return false;
- }
+ ret = macro->handler (macro_start, macro_len, macro_args,
+ macro->ud);
}
else {
- if (!macro->handler (macro_escaped, macro_len, macro->ud)) {
- UCL_FREE (macro_len + 1, macro_escaped);
- return false;
- }
+ ret = macro->handler (macro_escaped, macro_len, macro_args,
+ macro->ud);
UCL_FREE (macro_len + 1, macro_escaped);
}
p = chunk->pos;
+ if (macro_args) {
+ ucl_object_unref (macro_args);
+ }
+ if (!ret) {
+ return false;
+ }
break;
default:
/* TODO: add all states */
- ucl_set_err (chunk, UCL_EINTERNAL, "internal error: parser is in an unknown state", &parser->err);
+ ucl_set_err (parser, UCL_EINTERNAL,
+ "internal error: parser is in an unknown state", &parser->err);
parser->state = UCL_STATE_ERROR;
return false;
}
@@ -1888,7 +2114,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
if (new != NULL) {
/* Remove variable */
- LL_DELETE (parser->variables, new);
+ DL_DELETE (parser->variables, new);
free (new->var);
free (new->value);
UCL_FREE (sizeof (struct ucl_variable), new);
@@ -1910,7 +2136,7 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
new->value = strdup (value);
new->value_len = strlen (value);
- LL_PREPEND (parser->variables, new);
+ DL_APPEND (parser->variables, new);
}
else {
free (new->value);
@@ -1929,15 +2155,19 @@ ucl_parser_set_variables_handler (struct ucl_parser *parser,
}
bool
-ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
- size_t len)
+ucl_parser_add_chunk_priority (struct ucl_parser *parser, const unsigned char *data,
+ size_t len, unsigned priority)
{
struct ucl_chunk *chunk;
- if (data == NULL || len == 0) {
+ if (data == NULL) {
ucl_create_err (&parser->err, "invalid chunk added");
return false;
}
+ if (len == 0) {
+ parser->top_obj = ucl_object_new_full (UCL_OBJECT, priority);
+ return true;
+ }
if (parser->state != UCL_STATE_ERROR) {
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
if (chunk == NULL) {
@@ -1950,6 +2180,7 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
chunk->end = chunk->begin + len;
chunk->line = 1;
chunk->column = 0;
+ chunk->priority = priority;
LL_PREPEND (parser->chunks, chunk);
parser->recursion ++;
if (parser->recursion > UCL_MAX_RECURSION) {
@@ -1966,6 +2197,13 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
}
bool
+ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
+ size_t len)
+{
+ return ucl_parser_add_chunk_priority (parser, data, len, 0);
+}
+
+bool
ucl_parser_add_string (struct ucl_parser *parser, const char *data,
size_t len)
{
diff --git a/contrib/libucl/src/ucl_util.c b/contrib/libucl/src/ucl_util.c
index 63f5e62..41702e9 100644
--- a/contrib/libucl/src/ucl_util.c
+++ b/contrib/libucl/src/ucl_util.c
@@ -25,6 +25,8 @@
#include "ucl_internal.h"
#include "ucl_chartable.h"
+#include <glob.h>
+
#ifdef HAVE_LIBGEN_H
#include <libgen.h> /* For dirname */
#endif
@@ -129,11 +131,6 @@ static char* ucl_realpath(const char *path, char *resolved_path) {
#define ucl_realpath realpath
#endif
-/**
- * @file rcl_util.c
- * Utilities for rcl parsing
- */
-
typedef void (*ucl_object_dtor) (ucl_object_t *obj);
static void ucl_object_free_internal (ucl_object_t *obj, bool allow_rec,
ucl_object_dtor dtor);
@@ -148,7 +145,19 @@ ucl_object_dtor_free (ucl_object_t *obj)
if (obj->trash_stack[UCL_TRASH_VALUE] != NULL) {
UCL_FREE (obj->len, obj->trash_stack[UCL_TRASH_VALUE]);
}
- UCL_FREE (sizeof (ucl_object_t), obj);
+ /* Do not free ephemeral objects */
+ if ((obj->flags & UCL_OBJECT_EPHEMERAL) == 0) {
+ if (obj->type != UCL_USERDATA) {
+ UCL_FREE (sizeof (ucl_object_t), obj);
+ }
+ else {
+ struct ucl_object_userdata *ud = (struct ucl_object_userdata *)obj;
+ if (ud->dtor) {
+ ud->dtor (obj->value.ud);
+ }
+ UCL_FREE (sizeof (*ud), obj);
+ }
+ }
}
/*
@@ -423,7 +432,11 @@ ucl_parser_free (struct ucl_parser *parser)
}
if (parser->err != NULL) {
- utstring_free(parser->err);
+ utstring_free (parser->err);
+ }
+
+ if (parser->cur_file) {
+ free (parser->cur_file);
}
UCL_FREE (sizeof (struct ucl_parser), parser);
@@ -701,7 +714,8 @@ ucl_sig_check (const unsigned char *data, size_t datalen,
*/
static bool
ucl_include_url (const unsigned char *data, size_t len,
- struct ucl_parser *parser, bool check_signature, bool must_exist)
+ struct ucl_parser *parser, bool check_signature, bool must_exist,
+ unsigned priority)
{
bool res;
@@ -744,7 +758,7 @@ ucl_include_url (const unsigned char *data, size_t len,
prev_state = parser->state;
parser->state = UCL_STATE_INIT;
- res = ucl_parser_add_chunk (parser, buf, buflen);
+ res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
if (res == true) {
/* Remove chunk from the stack */
chunk = parser->chunks;
@@ -761,23 +775,30 @@ ucl_include_url (const unsigned char *data, size_t len,
}
/**
- * Include a file to configuration
+ * Include a single file to the parser
* @param data
* @param len
* @param parser
- * @param err
+ * @param check_signature
+ * @param must_exist
+ * @param allow_glob
+ * @param priority
* @return
*/
static bool
-ucl_include_file (const unsigned char *data, size_t len,
- struct ucl_parser *parser, bool check_signature, bool must_exist)
+ucl_include_file_single (const unsigned char *data, size_t len,
+ struct ucl_parser *parser, bool check_signature, bool must_exist,
+ unsigned priority)
{
bool res;
struct ucl_chunk *chunk;
unsigned char *buf = NULL;
+ char *old_curfile;
size_t buflen;
char filebuf[PATH_MAX], realbuf[PATH_MAX];
int prev_state;
+ struct ucl_variable *cur_var, *tmp_var, *old_curdir = NULL,
+ *old_filename = NULL;
snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);
if (ucl_realpath (filebuf, realbuf) == NULL) {
@@ -790,6 +811,13 @@ ucl_include_file (const unsigned char *data, size_t len,
return false;
}
+ if (parser->cur_file && strcmp (realbuf, parser->cur_file) == 0) {
+ /* We are likely including the file itself */
+ ucl_create_err (&parser->err, "trying to include the file %s from itself",
+ realbuf);
+ return false;
+ }
+
if (!ucl_fetch_file (realbuf, &buf, &buflen, &parser->err, must_exist)) {
return (!must_exist || false);
}
@@ -818,19 +846,66 @@ ucl_include_file (const unsigned char *data, size_t len,
#endif
}
+ old_curfile = parser->cur_file;
+ parser->cur_file = strdup (realbuf);
+
+ /* Store old file vars */
+ DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
+ if (strcmp (cur_var->var, "CURDIR") == 0) {
+ old_curdir = cur_var;
+ DL_DELETE (parser->variables, cur_var);
+ }
+ else if (strcmp (cur_var->var, "FILENAME") == 0) {
+ old_filename = cur_var;
+ DL_DELETE (parser->variables, cur_var);
+ }
+ }
+
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 */
- chunk = parser->chunks;
- if (chunk != NULL) {
- parser->chunks = chunk->next;
- UCL_FREE (sizeof (struct ucl_chunk), chunk);
+ res = ucl_parser_add_chunk_priority (parser, buf, buflen, priority);
+ if (!res && !must_exist) {
+ /* Free error */
+ utstring_free (parser->err);
+ parser->err = NULL;
+ parser->state = UCL_STATE_AFTER_VALUE;
+ }
+
+ /* Remove chunk from the stack */
+ chunk = parser->chunks;
+ if (chunk != NULL) {
+ parser->chunks = chunk->next;
+ UCL_FREE (sizeof (struct ucl_chunk), chunk);
+ parser->recursion --;
+ }
+
+ /* Restore old file vars */
+ parser->cur_file = old_curfile;
+ DL_FOREACH_SAFE (parser->variables, cur_var, tmp_var) {
+ if (strcmp (cur_var->var, "CURDIR") == 0 && old_curdir) {
+ DL_DELETE (parser->variables, cur_var);
+ free (cur_var->var);
+ free (cur_var->value);
+ UCL_FREE (sizeof (struct ucl_variable), cur_var);
}
+ else if (strcmp (cur_var->var, "FILENAME") == 0 && old_filename) {
+ DL_DELETE (parser->variables, cur_var);
+ free (cur_var->var);
+ free (cur_var->value);
+ UCL_FREE (sizeof (struct ucl_variable), cur_var);
+ }
+ }
+ if (old_filename) {
+ DL_APPEND (parser->variables, old_filename);
+ }
+ if (old_curdir) {
+ DL_APPEND (parser->variables, old_curdir);
+ }
+ if (old_curfile) {
+ free (old_curfile);
}
parser->state = prev_state;
@@ -843,6 +918,138 @@ ucl_include_file (const unsigned char *data, size_t len,
}
/**
+ * Include a file to configuration
+ * @param data
+ * @param len
+ * @param parser
+ * @param err
+ * @return
+ */
+static bool
+ucl_include_file (const unsigned char *data, size_t len,
+ struct ucl_parser *parser, bool check_signature, bool must_exist,
+ bool allow_glob, unsigned priority)
+{
+ const unsigned char *p = data, *end = data + len;
+ bool need_glob = false;
+ int cnt = 0;
+ glob_t globbuf;
+ char glob_pattern[PATH_MAX];
+ size_t i;
+
+ if (!allow_glob) {
+ return ucl_include_file_single (data, len, parser, check_signature,
+ must_exist, priority);
+ }
+ else {
+ /* Check for special symbols in a filename */
+ while (p != end) {
+ if (*p == '*' || *p == '?') {
+ need_glob = true;
+ break;
+ }
+ p ++;
+ }
+ if (need_glob) {
+ memset (&globbuf, 0, sizeof (globbuf));
+ ucl_strlcpy (glob_pattern, (const char *)data, sizeof (glob_pattern));
+ if (glob (glob_pattern, 0, NULL, &globbuf) != 0) {
+ return (!must_exist || false);
+ }
+ for (i = 0; i < globbuf.gl_pathc; i ++) {
+ if (!ucl_include_file_single ((unsigned char *)globbuf.gl_pathv[i],
+ strlen (globbuf.gl_pathv[i]), parser, check_signature,
+ must_exist, priority)) {
+ globfree (&globbuf);
+ return false;
+ }
+ cnt ++;
+ }
+ globfree (&globbuf);
+
+ if (cnt == 0 && must_exist) {
+ ucl_create_err (&parser->err, "cannot match any files for pattern %s",
+ glob_pattern);
+ return false;
+ }
+ }
+ else {
+ return ucl_include_file_single (data, len, parser, check_signature,
+ must_exist, priority);
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Common function to handle .*include* macros
+ * @param data
+ * @param len
+ * @param args
+ * @param parser
+ * @param default_try
+ * @param default_sign
+ * @return
+ */
+static bool
+ucl_include_common (const unsigned char *data, size_t len,
+ const ucl_object_t *args, struct ucl_parser *parser,
+ bool default_try,
+ bool default_sign)
+{
+ bool try_load, allow_glob, allow_url, need_sign;
+ unsigned priority;
+ const ucl_object_t *param;
+ ucl_object_iter_t it = NULL;
+
+ /* Default values */
+ try_load = default_try;
+ allow_glob = false;
+ allow_url = true;
+ need_sign = default_sign;
+ priority = 0;
+
+ /* Process arguments */
+ if (args != NULL && args->type == UCL_OBJECT) {
+ while ((param = ucl_iterate_object (args, &it, true)) != NULL) {
+ if (param->type == UCL_BOOLEAN) {
+ if (strcmp (param->key, "try") == 0) {
+ try_load = ucl_object_toboolean (param);
+ }
+ else if (strcmp (param->key, "sign") == 0) {
+ need_sign = ucl_object_toboolean (param);
+ }
+ else if (strcmp (param->key, "glob") == 0) {
+ allow_glob = ucl_object_toboolean (param);
+ }
+ else if (strcmp (param->key, "url") == 0) {
+ allow_url = ucl_object_toboolean (param);
+ }
+ }
+ else if (param->type == UCL_INT) {
+ if (strcmp (param->key, "priority") == 0) {
+ priority = ucl_object_toint (param);
+ }
+ }
+ }
+ }
+
+ if (*data == '/' || *data == '.') {
+ /* Try to load a file */
+ return ucl_include_file (data, len, parser, need_sign, !try_load,
+ allow_glob, priority);
+ }
+ else if (allow_url) {
+ /* Globbing is not used for URL's */
+ return ucl_include_url (data, len, parser, need_sign, !try_load,
+ priority);
+ }
+
+ return false;
+}
+
+/**
* Handle include macro
* @param data include data
* @param len length of data
@@ -851,16 +1058,12 @@ ucl_include_file (const unsigned char *data, size_t len,
* @return
*/
UCL_EXTERN bool
-ucl_include_handler (const unsigned char *data, size_t len, void* ud)
+ucl_include_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud)
{
struct ucl_parser *parser = ud;
- if (*data == '/' || *data == '.') {
- /* Try to load a file */
- return ucl_include_file (data, len, parser, false, true);
- }
-
- return ucl_include_url (data, len, parser, false, true);
+ return ucl_include_common (data, len, args, parser, false, false);
}
/**
@@ -872,30 +1075,22 @@ ucl_include_handler (const unsigned char *data, size_t len, void* ud)
* @return
*/
UCL_EXTERN bool
-ucl_includes_handler (const unsigned char *data, size_t len, void* ud)
+ucl_includes_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud)
{
struct ucl_parser *parser = ud;
- if (*data == '/' || *data == '.') {
- /* Try to load a file */
- return ucl_include_file (data, len, parser, true, true);
- }
-
- return ucl_include_url (data, len, parser, true, true);
+ return ucl_include_common (data, len, args, parser, false, true);
}
UCL_EXTERN bool
-ucl_try_include_handler (const unsigned char *data, size_t len, void* ud)
+ucl_try_include_handler (const unsigned char *data, size_t len,
+ const ucl_object_t *args, void* ud)
{
struct ucl_parser *parser = ud;
- if (*data == '/' || *data == '.') {
- /* Try to load a file */
- return ucl_include_file (data, len, parser, false, false);
- }
-
- return ucl_include_url (data, len, parser, false, false);
+ return ucl_include_common (data, len, args, parser, true, false);
}
UCL_EXTERN bool
@@ -947,6 +1142,10 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
return false;
}
+ if (parser->cur_file) {
+ free (parser->cur_file);
+ }
+ parser->cur_file = strdup (realbuf);
ucl_parser_set_filevars (parser, realbuf, false);
ret = ucl_parser_add_chunk (parser, buf, len);
@@ -957,6 +1156,39 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
return ret;
}
+UCL_EXTERN bool
+ucl_parser_add_fd (struct ucl_parser *parser, int fd)
+{
+ unsigned char *buf;
+ size_t len;
+ bool ret;
+ struct stat st;
+
+ if (fstat (fd, &st) == -1) {
+ ucl_create_err (&parser->err, "cannot stat fd %d: %s",
+ fd, strerror (errno));
+ return false;
+ }
+ if ((buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) {
+ ucl_create_err (&parser->err, "cannot mmap fd %d: %s",
+ fd, strerror (errno));
+ return false;
+ }
+
+ if (parser->cur_file) {
+ free (parser->cur_file);
+ }
+ parser->cur_file = NULL;
+ len = st.st_size;
+ ret = ucl_parser_add_chunk (parser, buf, len);
+
+ if (len > 0) {
+ ucl_munmap (buf, len);
+ }
+
+ return ret;
+}
+
size_t
ucl_strlcpy (char *dst, const char *src, size_t siz)
{
@@ -1176,6 +1408,15 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
}
}
+ /* workaround for some use cases */
+ if (elt->trash_stack[UCL_TRASH_KEY] != NULL &&
+ key != (const char *)elt->trash_stack[UCL_TRASH_KEY]) {
+ /* Remove copied key */
+ free (elt->trash_stack[UCL_TRASH_KEY]);
+ elt->trash_stack[UCL_TRASH_KEY] = NULL;
+ elt->flags &= ~UCL_OBJECT_ALLOCATED_KEY;
+ }
+
elt->key = key;
elt->keylen = keylen;
@@ -1185,9 +1426,8 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
found = __DECONST (ucl_object_t *, ucl_hash_search_obj (top->value.ov, elt));
- if (!found) {
+ if (found == NULL) {
top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
- DL_APPEND (found, elt);
top->len ++;
if (replace) {
ret = false;
@@ -1195,11 +1435,8 @@ ucl_object_insert_key_common (ucl_object_t *top, ucl_object_t *elt,
}
else {
if (replace) {
- ucl_hash_delete (top->value.ov, found);
+ ucl_hash_replace (top->value.ov, found, elt);
ucl_object_unref (found);
- top->value.ov = ucl_hash_insert_object (top->value.ov, elt);
- found = NULL;
- DL_APPEND (found, elt);
}
else if (merge) {
if (found->type != UCL_OBJECT && elt->type == UCL_OBJECT) {
@@ -1310,6 +1547,40 @@ ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
return ucl_object_insert_key_common (top, elt, key, keylen, copy_key, false, true);
}
+bool
+ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
+{
+ ucl_object_t *cur = NULL, *cp = NULL, *found = NULL;
+ ucl_object_iter_t iter = NULL;
+
+ if (top == NULL || top->type != UCL_OBJECT || elt == NULL || elt->type != UCL_OBJECT) {
+ return false;
+ }
+
+ /* Mix two hashes */
+ while ((cur = (ucl_object_t*)ucl_hash_iterate (elt->value.ov, &iter))) {
+ if (copy) {
+ cp = ucl_object_copy (cur);
+ }
+ else {
+ cp = ucl_object_ref (cur);
+ }
+ found = __DECONST(ucl_object_t *, ucl_hash_search (top->value.ov, cp->key, cp->keylen));
+ if (found == NULL) {
+ /* The key does not exist */
+ top->value.ov = ucl_hash_insert_object (top->value.ov, cp);
+ top->len ++;
+ }
+ else {
+ /* The key already exists, replace it */
+ ucl_hash_replace (top->value.ov, found, cp);
+ ucl_object_unref (found);
+ }
+ }
+
+ return true;
+}
+
const ucl_object_t *
ucl_object_find_keyl (const ucl_object_t *obj, const char *key, size_t klen)
{
@@ -1372,9 +1643,6 @@ ucl_iterate_object (const ucl_object_t *obj, ucl_object_iter_t *iter, bool expan
elt = *iter;
if (elt == NULL) {
elt = obj;
- if (elt == NULL) {
- return NULL;
- }
}
else if (elt == obj) {
return NULL;
@@ -1442,29 +1710,59 @@ ucl_lookup_path (const ucl_object_t *top, const char *path_in) {
ucl_object_t *
ucl_object_new (void)
{
- ucl_object_t *new;
- new = malloc (sizeof (ucl_object_t));
- if (new != NULL) {
- memset (new, 0, sizeof (ucl_object_t));
- new->ref = 1;
- new->type = UCL_NULL;
- }
- return new;
+ return ucl_object_typed_new (UCL_NULL);
}
ucl_object_t *
ucl_object_typed_new (ucl_type_t type)
{
+ return ucl_object_new_full (type, 0);
+}
+
+ucl_object_t *
+ucl_object_new_full (ucl_type_t type, unsigned priority)
+{
ucl_object_t *new;
- new = malloc (sizeof (ucl_object_t));
- if (new != NULL) {
- memset (new, 0, sizeof (ucl_object_t));
- new->ref = 1;
- new->type = (type <= UCL_NULL ? type : UCL_NULL);
+
+ if (type != UCL_USERDATA) {
+ new = UCL_ALLOC (sizeof (ucl_object_t));
+ if (new != NULL) {
+ memset (new, 0, sizeof (ucl_object_t));
+ new->ref = 1;
+ new->type = (type <= UCL_NULL ? type : UCL_NULL);
+ new->next = NULL;
+ new->prev = new;
+ ucl_object_set_priority (new, priority);
+ }
+ }
+ else {
+ new = ucl_object_new_userdata (NULL, NULL);
+ ucl_object_set_priority (new, priority);
}
+
return new;
}
+ucl_object_t*
+ucl_object_new_userdata (ucl_userdata_dtor dtor, ucl_userdata_emitter emitter)
+{
+ struct ucl_object_userdata *new;
+ size_t nsize = sizeof (*new);
+
+ new = UCL_ALLOC (nsize);
+ if (new != NULL) {
+ memset (new, 0, nsize);
+ new->obj.ref = 1;
+ new->obj.type = UCL_USERDATA;
+ new->obj.next = NULL;
+ new->obj.prev = (ucl_object_t *)new;
+ new->dtor = dtor;
+ new->emitter = emitter;
+ }
+
+ return (ucl_object_t *)new;
+}
+
ucl_type_t
ucl_object_type (const ucl_object_t *obj)
{
@@ -1576,6 +1874,30 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
return true;
}
+bool
+ucl_array_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)
+{
+ ucl_object_t *cur, *tmp, *cp;
+
+ if (elt == NULL || top == NULL || top->type != UCL_ARRAY || elt->type != UCL_ARRAY) {
+ return false;
+ }
+
+ DL_FOREACH_SAFE (elt->value.av, cur, tmp) {
+ if (copy) {
+ cp = ucl_object_copy (cur);
+ }
+ else {
+ cp = ucl_object_ref (cur);
+ }
+ if (cp != NULL) {
+ ucl_array_append (top, cp);
+ }
+ }
+
+ return true;
+}
+
ucl_object_t *
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
{
@@ -1661,6 +1983,28 @@ ucl_array_find_index (const ucl_object_t *top, unsigned int index)
}
ucl_object_t *
+ucl_array_replace_index (ucl_object_t *top, ucl_object_t *elt,
+ unsigned int index)
+{
+ ucl_object_t *cur, *tmp;
+
+ if (top == NULL || top->type != UCL_ARRAY || elt == NULL ||
+ top->len == 0 || (index + 1) > top->len) {
+ return NULL;
+ }
+
+ DL_FOREACH_SAFE (top->value.av, cur, tmp) {
+ if (index == 0) {
+ DL_REPLACE_ELEM (top->value.av, cur, elt);
+ return cur;
+ }
+ --index;
+ }
+
+ return NULL;
+}
+
+ucl_object_t *
ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
{
@@ -1849,16 +2193,99 @@ ucl_object_ref (const ucl_object_t *obj)
ucl_object_t *res = NULL;
if (obj != NULL) {
- res = __DECONST (ucl_object_t *, obj);
+ if (obj->flags & UCL_OBJECT_EPHEMERAL) {
+ /*
+ * Use deep copy for ephemeral objects, note that its refcount
+ * is NOT increased, since ephemeral objects does not need refcount
+ * at all
+ */
+ res = ucl_object_copy (obj);
+ }
+ else {
+ res = __DECONST (ucl_object_t *, obj);
#ifdef HAVE_ATOMIC_BUILTINS
- (void)__sync_add_and_fetch (&res->ref, 1);
+ (void)__sync_add_and_fetch (&res->ref, 1);
#else
- res->ref ++;
+ res->ref ++;
#endif
+ }
}
return res;
}
+static ucl_object_t *
+ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)
+{
+
+ ucl_object_t *new;
+ ucl_object_iter_t it = NULL;
+ const ucl_object_t *cur;
+
+ new = malloc (sizeof (*new));
+
+ if (new != NULL) {
+ memcpy (new, other, sizeof (*new));
+ if (other->flags & UCL_OBJECT_EPHEMERAL) {
+ /* Copied object is always non ephemeral */
+ new->flags &= ~UCL_OBJECT_EPHEMERAL;
+ }
+ new->ref = 1;
+ /* Unlink from others */
+ new->next = NULL;
+ new->prev = new;
+
+ /* deep copy of values stored */
+ if (other->trash_stack[UCL_TRASH_KEY] != NULL) {
+ new->trash_stack[UCL_TRASH_KEY] =
+ strdup (other->trash_stack[UCL_TRASH_KEY]);
+ if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) {
+ new->key = new->trash_stack[UCL_TRASH_KEY];
+ }
+ }
+ if (other->trash_stack[UCL_TRASH_VALUE] != NULL) {
+ new->trash_stack[UCL_TRASH_VALUE] =
+ strdup (other->trash_stack[UCL_TRASH_VALUE]);
+ if (new->type == UCL_STRING) {
+ new->value.sv = new->trash_stack[UCL_TRASH_VALUE];
+ }
+ }
+
+ if (other->type == UCL_ARRAY || other->type == UCL_OBJECT) {
+ /* reset old value */
+ memset (&new->value, 0, sizeof (new->value));
+
+ while ((cur = ucl_iterate_object (other, &it, true)) != NULL) {
+ if (other->type == UCL_ARRAY) {
+ ucl_array_append (new, ucl_object_copy_internal (cur, false));
+ }
+ else {
+ ucl_object_t *cp = ucl_object_copy_internal (cur, true);
+ if (cp != NULL) {
+ ucl_object_insert_key (new, cp, cp->key, cp->keylen,
+ false);
+ }
+ }
+ }
+ }
+ else if (allow_array && other->next != NULL) {
+ LL_FOREACH (other->next, cur) {
+ ucl_object_t *cp = ucl_object_copy_internal (cur, false);
+ if (cp != NULL) {
+ DL_APPEND (new, cp);
+ }
+ }
+ }
+ }
+
+ return new;
+}
+
+ucl_object_t *
+ucl_object_copy (const ucl_object_t *other)
+{
+ return ucl_object_copy_internal (other, true);
+}
+
void
ucl_object_unref (ucl_object_t *obj)
{
@@ -1956,3 +2383,25 @@ ucl_object_array_sort (ucl_object_t *ar,
DL_SORT (ar->value.av, cmp);
}
+
+#define PRIOBITS 4
+
+unsigned int
+ucl_object_get_priority (const ucl_object_t *obj)
+{
+ if (obj == NULL) {
+ return 0;
+ }
+
+ return (obj->flags >> ((sizeof (obj->flags) * NBBY) - PRIOBITS));
+}
+
+void
+ucl_object_set_priority (ucl_object_t *obj,
+ unsigned int priority)
+{
+ if (obj != NULL) {
+ priority &= (0x1 << PRIOBITS) - 1;
+ obj->flags |= priority << ((sizeof (obj->flags) * NBBY) - PRIOBITS);
+ }
+}
OpenPOWER on IntegriCloud