Import libucl 20170219
MFC after: 3 days
This commit is contained in:
commit
11dd9ed664
@ -35,7 +35,7 @@
|
||||
|
||||
### Libucl 0.7.3
|
||||
|
||||
- Fixed a bug with macroes that come after an empty object
|
||||
- Fixed a bug with macros that come after an empty object
|
||||
- Fixed a bug in include processing when an incorrect variable has been destroyed (use-after-free)
|
||||
|
||||
### Libucl 0.8.0
|
||||
|
@ -1,6 +1,8 @@
|
||||
# LIBUCL
|
||||
|
||||
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)
|
||||
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)
|
||||
[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)
|
||||
[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)
|
||||
|
||||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
|
||||
|
||||
@ -217,8 +219,8 @@ Multiline comments may be nested:
|
||||
|
||||
UCL supports external macros both multiline and single line ones:
|
||||
```nginx
|
||||
.macro "sometext";
|
||||
.macro {
|
||||
.macro_name "sometext";
|
||||
.macro_name {
|
||||
Some long text
|
||||
....
|
||||
};
|
||||
@ -229,12 +231,12 @@ arguments themselves are the UCL object that is parsed and passed to a macro as
|
||||
options:
|
||||
|
||||
```nginx
|
||||
.macro(param=value) "something";
|
||||
.macro(param={key=value}) "something";
|
||||
.macro(.include "params.conf") "something";
|
||||
.macro(#this is multiline macro
|
||||
.macro_name(param=value) "something";
|
||||
.macro_name(param={key=value}) "something";
|
||||
.macro_name(.include "params.conf") "something";
|
||||
.macro_name(#this is multiline macro
|
||||
param = [value1, value2]) "something";
|
||||
.macro(key="()") "something";
|
||||
.macro_name(key="()") "something";
|
||||
```
|
||||
|
||||
UCL also provide a convenient `include` macro to load content from another files
|
||||
|
@ -39,6 +39,7 @@ AC_CHECK_HEADERS_ONCE([stdarg.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdbool.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdint.h])
|
||||
AC_CHECK_HEADERS_ONCE([string.h])
|
||||
AC_CHECK_HEADERS_ONCE([strings.h])
|
||||
AC_CHECK_HEADERS_ONCE([unistd.h])
|
||||
AC_CHECK_HEADERS_ONCE([ctype.h])
|
||||
AC_CHECK_HEADERS_ONCE([errno.h])
|
||||
|
@ -154,7 +154,8 @@ typedef enum ucl_parser_flags {
|
||||
UCL_PARSER_NO_TIME = (1 << 2), /**< Do not parse time and treat time values as strings */
|
||||
UCL_PARSER_NO_IMPLICIT_ARRAYS = (1 << 3), /** Create explicit arrays instead of implicit ones */
|
||||
UCL_PARSER_SAVE_COMMENTS = (1 << 4), /** Save comments in the parser context */
|
||||
UCL_PARSER_DISABLE_MACRO = (1 << 5) /** Treat macros as comments */
|
||||
UCL_PARSER_DISABLE_MACRO = (1 << 5), /** Treat macros as comments */
|
||||
UCL_PARSER_NO_FILEVARS = (1 << 6) /** Do not set file vars */
|
||||
} ucl_parser_flags_t;
|
||||
|
||||
/**
|
||||
@ -205,7 +206,8 @@ enum ucl_duplicate_strategy {
|
||||
enum ucl_parse_type {
|
||||
UCL_PARSE_UCL = 0, /**< Default ucl format */
|
||||
UCL_PARSE_MSGPACK, /**< Message pack input format */
|
||||
UCL_PARSE_CSEXP /**< Canonical S-expressions */
|
||||
UCL_PARSE_CSEXP, /**< Canonical S-expressions */
|
||||
UCL_PARSE_AUTO /**< Try to detect parse type */
|
||||
};
|
||||
|
||||
/**
|
||||
@ -227,7 +229,7 @@ typedef struct ucl_object_s {
|
||||
const char *key; /**< Key of an object */
|
||||
struct ucl_object_s *next; /**< Array handle */
|
||||
struct ucl_object_s *prev; /**< Array handle */
|
||||
uint32_t keylen; /**< Lenght of a key */
|
||||
uint32_t keylen; /**< Length of a key */
|
||||
uint32_t len; /**< Size of an object */
|
||||
uint32_t ref; /**< Reference count */
|
||||
uint16_t flags; /**< Object flags */
|
||||
@ -831,10 +833,29 @@ UCL_EXTERN ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it,
|
||||
* Get the next object from the `obj`. This fucntion iterates over arrays, objects
|
||||
* and implicit arrays
|
||||
* @param iter safe iterator
|
||||
* @param expand_values expand explicit arrays and objects
|
||||
* @return the next object in sequence
|
||||
*/
|
||||
UCL_EXTERN const ucl_object_t* ucl_object_iterate_safe (ucl_object_iter_t iter,
|
||||
bool expand_values);
|
||||
/**
|
||||
* Iteration type enumerator
|
||||
*/
|
||||
enum ucl_iterate_type {
|
||||
UCL_ITERATE_EXPLICIT = 1 << 0, /**< Iterate just explicit arrays and objects */
|
||||
UCL_ITERATE_IMPLICIT = 1 << 1, /**< Iterate just implicit arrays */
|
||||
UCL_ITERATE_BOTH = (1 << 0) | (1 << 1), /**< Iterate both explicit and implicit arrays*/
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the next object from the `obj`. This fucntion iterates over arrays, objects
|
||||
* and implicit arrays if needed
|
||||
* @param iter safe iterator
|
||||
* @param
|
||||
* @return the next object in sequence
|
||||
*/
|
||||
UCL_EXTERN const ucl_object_t* ucl_object_iterate_full (ucl_object_iter_t iter,
|
||||
enum ucl_iterate_type type);
|
||||
|
||||
/**
|
||||
* Free memory associated with the safe iterator
|
||||
@ -1016,6 +1037,7 @@ UCL_EXTERN bool ucl_parser_add_string_priority (struct ucl_parser *parser,
|
||||
* Load and add data from a file
|
||||
* @param parser parser structure
|
||||
* @param filename the name of file
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @return true if chunk has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser,
|
||||
@ -1025,6 +1047,7 @@ UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser,
|
||||
* Load and add data from a file
|
||||
* @param parser parser structure
|
||||
* @param filename the name of file
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @param priority the desired priority of a chunk (only 4 least significant bits
|
||||
* are considered for this parameter)
|
||||
* @return true if chunk has been added and false in case of error
|
||||
@ -1068,6 +1091,21 @@ UCL_EXTERN bool ucl_parser_add_fd (struct ucl_parser *parser,
|
||||
UCL_EXTERN bool ucl_parser_add_fd_priority (struct ucl_parser *parser,
|
||||
int fd, unsigned priority);
|
||||
|
||||
/**
|
||||
* Load and add data from a file descriptor
|
||||
* @param parser parser structure
|
||||
* @param filename the name of file
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @param priority the desired priority of a chunk (only 4 least significant bits
|
||||
* are considered for this parameter)
|
||||
* @param strat Merge strategy to use while parsing this file
|
||||
* @param parse_type Parser type to use while parsing this file
|
||||
* @return true if chunk has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_fd_full (struct ucl_parser *parser, int fd,
|
||||
unsigned priority, enum ucl_duplicate_strategy strat,
|
||||
enum ucl_parse_type parse_type);
|
||||
|
||||
/**
|
||||
* Provide a UCL_ARRAY of paths to search for include files. The object is
|
||||
* copied so caller must unref the object.
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "ucl_internal.h"
|
||||
#include "lua_ucl.h"
|
||||
#include <strings.h>
|
||||
#include <zconf.h>
|
||||
|
||||
/***
|
||||
* @module ucl
|
||||
@ -187,6 +186,8 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
||||
lua_rawseti (L, -2, i);
|
||||
i ++;
|
||||
}
|
||||
|
||||
ucl_object_iterate_free (it);
|
||||
}
|
||||
else {
|
||||
/* Optimize allocation by preallocation of table */
|
||||
@ -482,7 +483,7 @@ static int
|
||||
lua_ucl_parser_init (lua_State *L)
|
||||
{
|
||||
struct ucl_parser *parser, **pparser;
|
||||
int flags = 0;
|
||||
int flags = UCL_PARSER_NO_FILEVARS;
|
||||
|
||||
if (lua_gettop (L) >= 1) {
|
||||
flags = lua_tonumber (L, 1);
|
||||
@ -524,6 +525,27 @@ lua_ucl_push_opaque (lua_State *L, ucl_object_t *obj)
|
||||
lua_setmetatable (L, -2);
|
||||
}
|
||||
|
||||
static inline enum ucl_parse_type
|
||||
lua_ucl_str_to_parse_type (const char *str)
|
||||
{
|
||||
enum ucl_parse_type type = UCL_PARSE_UCL;
|
||||
|
||||
if (str != NULL) {
|
||||
if (strcasecmp (str, "msgpack") == 0) {
|
||||
type = UCL_PARSE_MSGPACK;
|
||||
}
|
||||
else if (strcasecmp (str, "sexp") == 0 ||
|
||||
strcasecmp (str, "csexp") == 0) {
|
||||
type = UCL_PARSE_CSEXP;
|
||||
}
|
||||
else if (strcasecmp (str, "auto") == 0) {
|
||||
type = UCL_PARSE_AUTO;
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/***
|
||||
* @method parser:parse_file(name)
|
||||
* Parse UCL object from file.
|
||||
@ -579,13 +601,19 @@ lua_ucl_parser_parse_string (lua_State *L)
|
||||
struct ucl_parser *parser;
|
||||
const char *string;
|
||||
size_t llen;
|
||||
enum ucl_parse_type type = UCL_PARSE_UCL;
|
||||
int ret = 2;
|
||||
|
||||
parser = lua_ucl_parser_get (L, 1);
|
||||
string = luaL_checklstring (L, 2, &llen);
|
||||
|
||||
if (lua_type (L, 3) == LUA_TSTRING) {
|
||||
type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
|
||||
}
|
||||
|
||||
if (parser != NULL && string != NULL) {
|
||||
if (ucl_parser_add_chunk (parser, (const unsigned char *)string, llen)) {
|
||||
if (ucl_parser_add_chunk_full (parser, (const unsigned char *)string,
|
||||
llen, 0, UCL_DUPLICATE_APPEND, type)) {
|
||||
lua_pushboolean (L, true);
|
||||
ret = 1;
|
||||
}
|
||||
@ -761,6 +789,28 @@ lua_ucl_object_unwrap (lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline enum ucl_emitter
|
||||
lua_ucl_str_to_emit_type (const char *strtype)
|
||||
{
|
||||
enum ucl_emitter format = UCL_EMIT_JSON_COMPACT;
|
||||
|
||||
if (strcasecmp (strtype, "json") == 0) {
|
||||
format = UCL_EMIT_JSON;
|
||||
}
|
||||
else if (strcasecmp (strtype, "json-compact") == 0) {
|
||||
format = UCL_EMIT_JSON_COMPACT;
|
||||
}
|
||||
else if (strcasecmp (strtype, "yaml") == 0) {
|
||||
format = UCL_EMIT_YAML;
|
||||
}
|
||||
else if (strcasecmp (strtype, "config") == 0 ||
|
||||
strcasecmp (strtype, "ucl") == 0) {
|
||||
format = UCL_EMIT_CONFIG;
|
||||
}
|
||||
|
||||
return format;
|
||||
}
|
||||
|
||||
/***
|
||||
* @method object:tostring(type)
|
||||
* Unwraps opaque ucl object to string (json by default). Optionally you can
|
||||
@ -787,19 +837,7 @@ lua_ucl_object_tostring (lua_State *L)
|
||||
if (lua_type (L, 2) == LUA_TSTRING) {
|
||||
const char *strtype = lua_tostring (L, 2);
|
||||
|
||||
if (strcasecmp (strtype, "json") == 0) {
|
||||
format = UCL_EMIT_JSON;
|
||||
}
|
||||
else if (strcasecmp (strtype, "json-compact") == 0) {
|
||||
format = UCL_EMIT_JSON_COMPACT;
|
||||
}
|
||||
else if (strcasecmp (strtype, "yaml") == 0) {
|
||||
format = UCL_EMIT_YAML;
|
||||
}
|
||||
else if (strcasecmp (strtype, "config") == 0 ||
|
||||
strcasecmp (strtype, "ucl") == 0) {
|
||||
format = UCL_EMIT_CONFIG;
|
||||
}
|
||||
format = lua_ucl_str_to_emit_type (strtype);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1088,6 +1126,9 @@ lua_ucl_to_format (lua_State *L)
|
||||
strcasecmp (strtype, "ucl") == 0) {
|
||||
format = UCL_EMIT_CONFIG;
|
||||
}
|
||||
else if (strcasecmp (strtype, "msgpack") == 0) {
|
||||
format = UCL_EMIT_MSGPACK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||
|
||||
while (size) {
|
||||
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE)) {
|
||||
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_DENIED)) {
|
||||
if (len > 0) {
|
||||
func->ucl_emitter_append_len (c, len, func->ud);
|
||||
}
|
||||
@ -128,6 +128,10 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
||||
case '"':
|
||||
func->ucl_emitter_append_len ("\\\"", 2, func->ud);
|
||||
break;
|
||||
default:
|
||||
/* Emit unicode unknown character */
|
||||
func->ucl_emitter_append_len ("\\uFFFD", 5, func->ud);
|
||||
break;
|
||||
}
|
||||
len = 0;
|
||||
c = ++p;
|
||||
@ -138,9 +142,11 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
||||
}
|
||||
size --;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
func->ucl_emitter_append_len (c, len, func->ud);
|
||||
}
|
||||
|
||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,9 @@
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
#include "utlist.h"
|
||||
#include "utstring.h"
|
||||
@ -127,19 +130,19 @@ enum ucl_parser_state {
|
||||
};
|
||||
|
||||
enum ucl_character_type {
|
||||
UCL_CHARACTER_DENIED = 0,
|
||||
UCL_CHARACTER_KEY = 1,
|
||||
UCL_CHARACTER_KEY_START = 1 << 1,
|
||||
UCL_CHARACTER_WHITESPACE = 1 << 2,
|
||||
UCL_CHARACTER_WHITESPACE_UNSAFE = 1 << 3,
|
||||
UCL_CHARACTER_VALUE_END = 1 << 4,
|
||||
UCL_CHARACTER_VALUE_STR = 1 << 5,
|
||||
UCL_CHARACTER_VALUE_DIGIT = 1 << 6,
|
||||
UCL_CHARACTER_VALUE_DIGIT_START = 1 << 7,
|
||||
UCL_CHARACTER_ESCAPE = 1 << 8,
|
||||
UCL_CHARACTER_KEY_SEP = 1 << 9,
|
||||
UCL_CHARACTER_JSON_UNSAFE = 1 << 10,
|
||||
UCL_CHARACTER_UCL_UNSAFE = 1 << 11
|
||||
UCL_CHARACTER_DENIED = (1 << 0),
|
||||
UCL_CHARACTER_KEY = (1 << 1),
|
||||
UCL_CHARACTER_KEY_START = (1 << 2),
|
||||
UCL_CHARACTER_WHITESPACE = (1 << 3),
|
||||
UCL_CHARACTER_WHITESPACE_UNSAFE = (1 << 4),
|
||||
UCL_CHARACTER_VALUE_END = (1 << 5),
|
||||
UCL_CHARACTER_VALUE_STR = (1 << 6),
|
||||
UCL_CHARACTER_VALUE_DIGIT = (1 << 7),
|
||||
UCL_CHARACTER_VALUE_DIGIT_START = (1 << 8),
|
||||
UCL_CHARACTER_ESCAPE = (1 << 9),
|
||||
UCL_CHARACTER_KEY_SEP = (1 << 10),
|
||||
UCL_CHARACTER_JSON_UNSAFE = (1 << 11),
|
||||
UCL_CHARACTER_UCL_UNSAFE = (1 << 12)
|
||||
};
|
||||
|
||||
struct ucl_macro {
|
||||
@ -568,4 +571,6 @@ bool ucl_parser_process_object_element (struct ucl_parser *parser,
|
||||
*/
|
||||
bool ucl_parse_msgpack (struct ucl_parser *parser);
|
||||
|
||||
bool ucl_parse_csexp (struct ucl_parser *parser);
|
||||
|
||||
#endif /* UCL_INTERNAL_H_ */
|
||||
|
@ -2469,8 +2469,10 @@ ucl_parser_new (int flags)
|
||||
parser->comments = ucl_object_typed_new (UCL_OBJECT);
|
||||
}
|
||||
|
||||
/* Initial assumption about filevars */
|
||||
ucl_parser_set_filevars (parser, NULL, false);
|
||||
if (!(flags & UCL_PARSER_NO_FILEVARS)) {
|
||||
/* Initial assumption about filevars */
|
||||
ucl_parser_set_filevars (parser, NULL, false);
|
||||
}
|
||||
|
||||
return parser;
|
||||
}
|
||||
@ -2617,6 +2619,19 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (parse_type == UCL_PARSE_AUTO && len > 0) {
|
||||
/* We need to detect parse type by the first symbol */
|
||||
if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
|
||||
parse_type = UCL_PARSE_MSGPACK;
|
||||
}
|
||||
else if (*data == '(') {
|
||||
parse_type = UCL_PARSE_CSEXP;
|
||||
}
|
||||
else {
|
||||
parse_type = UCL_PARSE_UCL;
|
||||
}
|
||||
}
|
||||
|
||||
chunk->begin = data;
|
||||
chunk->remain = len;
|
||||
chunk->pos = chunk->begin;
|
||||
@ -2643,6 +2658,8 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
|
||||
return ucl_state_machine (parser);
|
||||
case UCL_PARSE_MSGPACK:
|
||||
return ucl_parse_msgpack (parser);
|
||||
case UCL_PARSE_CSEXP:
|
||||
return ucl_parse_csexp (parser);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -26,11 +26,17 @@
|
||||
#include "ucl_internal.h"
|
||||
#include "ucl_chartable.h"
|
||||
#include "kvec.h"
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h> /* for snprintf */
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <glob.h>
|
||||
#include <sys/param.h>
|
||||
#else
|
||||
#ifndef NBBY
|
||||
#define NBBY 8
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
@ -81,11 +87,6 @@ typedef kvec_t(ucl_object_t *) ucl_array_t;
|
||||
#define MAP_FAILED ((void *) -1)
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <limits.h>
|
||||
#define NBBY CHAR_BIT
|
||||
#endif
|
||||
|
||||
static void *ucl_mmap(char *addr, size_t length, int prot, int access, int fd, off_t offset)
|
||||
{
|
||||
void *map = NULL;
|
||||
@ -1854,9 +1855,11 @@ ucl_parser_add_file (struct ucl_parser *parser, const char *filename)
|
||||
UCL_PARSE_UCL);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
|
||||
unsigned priority)
|
||||
ucl_parser_add_fd_full (struct ucl_parser *parser, int fd,
|
||||
unsigned priority, enum ucl_duplicate_strategy strat,
|
||||
enum ucl_parse_type parse_type)
|
||||
{
|
||||
unsigned char *buf;
|
||||
size_t len;
|
||||
@ -1882,7 +1885,8 @@ ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
|
||||
}
|
||||
parser->cur_file = NULL;
|
||||
len = st.st_size;
|
||||
ret = ucl_parser_add_chunk_priority (parser, buf, len, priority);
|
||||
ret = ucl_parser_add_chunk_full (parser, buf, len, priority, strat,
|
||||
parse_type);
|
||||
|
||||
if (len > 0) {
|
||||
ucl_munmap (buf, len);
|
||||
@ -1891,6 +1895,18 @@ ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_parser_add_fd_priority (struct ucl_parser *parser, int fd,
|
||||
unsigned priority)
|
||||
{
|
||||
if (parser == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ucl_parser_add_fd_full(parser, fd, parser->default_priority,
|
||||
UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_parser_add_fd (struct ucl_parser *parser, int fd)
|
||||
{
|
||||
@ -2488,6 +2504,10 @@ ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
|
||||
|
||||
UCL_SAFE_ITER_CHECK (rit);
|
||||
|
||||
if (rit->expl_it != NULL) {
|
||||
UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
|
||||
}
|
||||
|
||||
rit->impl_it = obj;
|
||||
rit->expl_it = NULL;
|
||||
|
||||
@ -2496,6 +2516,13 @@ ucl_object_iterate_reset (ucl_object_iter_t it, const ucl_object_t *obj)
|
||||
|
||||
const ucl_object_t*
|
||||
ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
|
||||
{
|
||||
return ucl_object_iterate_full (it, expand_values ? UCL_ITERATE_BOTH :
|
||||
UCL_ITERATE_IMPLICIT);
|
||||
}
|
||||
|
||||
const ucl_object_t*
|
||||
ucl_object_iterate_full (ucl_object_iter_t it, enum ucl_iterate_type type)
|
||||
{
|
||||
struct ucl_object_safe_iter *rit = UCL_SAFE_ITER (it);
|
||||
const ucl_object_t *ret = NULL;
|
||||
@ -2509,21 +2536,23 @@ ucl_object_iterate_safe (ucl_object_iter_t it, bool expand_values)
|
||||
if (rit->impl_it->type == UCL_OBJECT || rit->impl_it->type == UCL_ARRAY) {
|
||||
ret = ucl_object_iterate (rit->impl_it, &rit->expl_it, true);
|
||||
|
||||
if (ret == NULL) {
|
||||
if (ret == NULL && (type & UCL_ITERATE_IMPLICIT)) {
|
||||
/* Need to switch to another implicit object in chain */
|
||||
rit->impl_it = rit->impl_it->next;
|
||||
rit->expl_it = NULL;
|
||||
return ucl_object_iterate_safe (it, expand_values);
|
||||
|
||||
return ucl_object_iterate_safe (it, type);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Just iterate over the implicit array */
|
||||
ret = rit->impl_it;
|
||||
rit->impl_it = rit->impl_it->next;
|
||||
if (expand_values) {
|
||||
|
||||
if (type & UCL_ITERATE_EXPLICIT) {
|
||||
/* We flatten objects if need to expand values */
|
||||
if (ret->type == UCL_OBJECT || ret->type == UCL_ARRAY) {
|
||||
return ucl_object_iterate_safe (it, expand_values);
|
||||
return ucl_object_iterate_safe (it, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2538,6 +2567,10 @@ ucl_object_iterate_free (ucl_object_iter_t it)
|
||||
|
||||
UCL_SAFE_ITER_CHECK (rit);
|
||||
|
||||
if (rit->expl_it != NULL) {
|
||||
UCL_FREE (sizeof (*rit->expl_it), rit->expl_it);
|
||||
}
|
||||
|
||||
UCL_FREE (sizeof (*rit), it);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user