libucl: import latest snapshot from 2021-03-14
This commit is contained in:
parent
8392e70f8a
commit
3c319408d0
105
CMakeLists.txt
105
CMakeLists.txt
@ -9,13 +9,16 @@ SET(LIBUCL_VERSION
|
|||||||
"${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
|
"${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
|
||||||
|
|
||||||
INCLUDE(CheckCCompilerFlag)
|
INCLUDE(CheckCCompilerFlag)
|
||||||
|
INCLUDE(CheckCSourceCompiles)
|
||||||
INCLUDE(FindOpenSSL)
|
INCLUDE(FindOpenSSL)
|
||||||
|
INCLUDE(GNUInstallDirs)
|
||||||
|
|
||||||
OPTION(ENABLE_URL_INCLUDE "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF)
|
OPTION(ENABLE_URL_INCLUDE "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF)
|
||||||
OPTION(ENABLE_URL_SIGN "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF)
|
OPTION(ENABLE_URL_SIGN "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF)
|
||||||
OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF)
|
OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF)
|
||||||
OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF)
|
OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF)
|
||||||
OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF)
|
OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF)
|
||||||
|
OPTION(ENABLE_UTILS "Enable building utility binaries [default: OFF]" OFF)
|
||||||
|
|
||||||
# Find lua installation
|
# Find lua installation
|
||||||
MACRO(FindLua)
|
MACRO(FindLua)
|
||||||
@ -150,40 +153,47 @@ IF(ENABLE_URL_INCLUDE MATCHES "ON")
|
|||||||
DOC "Path to libfetch header")
|
DOC "Path to libfetch header")
|
||||||
ELSE(LIBFETCH_LIBRARY)
|
ELSE(LIBFETCH_LIBRARY)
|
||||||
# Try to find libcurl
|
# Try to find libcurl
|
||||||
ProcessPackage(CURL libcurl)
|
FIND_PACKAGE(CURL)
|
||||||
IF(NOT CURL_FOUND)
|
IF(NOT CURL_FOUND)
|
||||||
MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration")
|
MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration")
|
||||||
ENDIF(NOT CURL_FOUND)
|
ENDIF(NOT CURL_FOUND)
|
||||||
ENDIF(LIBFETCH_LIBRARY)
|
ENDIF(LIBFETCH_LIBRARY)
|
||||||
ENDIF(ENABLE_URL_INCLUDE MATCHES "ON")
|
ENDIF(ENABLE_URL_INCLUDE MATCHES "ON")
|
||||||
|
|
||||||
|
set(SYNC_BUILTINS_TEST_SOURCE [====[
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
unsigned long val;
|
||||||
|
|
||||||
|
__sync_bool_compare_and_swap(&val, 0, 1);
|
||||||
|
__sync_add_and_fetch(&val, 1);
|
||||||
|
__sync_fetch_and_add(&val, 0);
|
||||||
|
__sync_sub_and_fetch(&val, 1);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
]====])
|
||||||
|
|
||||||
|
CHECK_C_SOURCE_COMPILES("${SYNC_BUILTINS_TEST_SOURCE}" HAVE_ATOMIC_BUILTINS)
|
||||||
|
IF(NOT HAVE_ATOMIC_BUILTINS)
|
||||||
|
MESSAGE(WARNING "Libucl references could be thread-unsafe because atomic builtins are missing")
|
||||||
|
ENDIF(NOT HAVE_ATOMIC_BUILTINS)
|
||||||
|
|
||||||
SET(CMAKE_C_WARN_FLAGS "")
|
SET(CMAKE_C_WARN_FLAGS "")
|
||||||
CHECK_C_COMPILER_FLAG(-Wall SUPPORT_WALL)
|
|
||||||
CHECK_C_COMPILER_FLAG(-W SUPPORT_W)
|
CHECK_C_COMPILER_FLAG(-W SUPPORT_W)
|
||||||
CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WPARAM)
|
|
||||||
CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN)
|
CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN)
|
||||||
CHECK_C_COMPILER_FLAG(-Wstrict-prototypes SUPPORT_WSTRICT_PROTOTYPES)
|
CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WUNUSED_PARAMETER)
|
||||||
IF(NOT "${CMAKE_C_COMPILER_ID}" MATCHES SunPro)
|
|
||||||
CHECK_C_COMPILER_FLAG("-std=c99" SUPPORT_STD_FLAG)
|
|
||||||
ENDIF(NOT "${CMAKE_C_COMPILER_ID}" MATCHES SunPro)
|
|
||||||
IF(SUPPORT_W)
|
IF(SUPPORT_W)
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W")
|
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W")
|
||||||
ENDIF(SUPPORT_W)
|
ENDIF(SUPPORT_W)
|
||||||
IF(SUPPORT_WALL)
|
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wall")
|
|
||||||
ENDIF(SUPPORT_WALL)
|
|
||||||
IF(SUPPORT_WPARAM)
|
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter")
|
|
||||||
ENDIF(SUPPORT_WPARAM)
|
|
||||||
IF(SUPPORT_WPOINTER_SIGN)
|
IF(SUPPORT_WPOINTER_SIGN)
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign")
|
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign")
|
||||||
ENDIF(SUPPORT_WPOINTER_SIGN)
|
ENDIF(SUPPORT_WPOINTER_SIGN)
|
||||||
IF(SUPPORT_WSTRICT_PROTOTYPES)
|
IF(SUPPORT_WUNUSED_PARAMETER)
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wstrict-prototypes")
|
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter")
|
||||||
ENDIF(SUPPORT_WSTRICT_PROTOTYPES)
|
ENDIF(SUPPORT_WUNUSED_PARAMETER)
|
||||||
IF(SUPPORT_STD_FLAG)
|
|
||||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -std=c99")
|
SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_WARN_FLAGS}" )
|
||||||
ENDIF(SUPPORT_STD_FLAG)
|
|
||||||
|
|
||||||
IF(ENABLE_URL_SIGN MATCHES "ON")
|
IF(ENABLE_URL_SIGN MATCHES "ON")
|
||||||
IF(OPENSSL_FOUND)
|
IF(OPENSSL_FOUND)
|
||||||
@ -192,10 +202,19 @@ IF(ENABLE_URL_SIGN MATCHES "ON")
|
|||||||
ENDIF(OPENSSL_FOUND)
|
ENDIF(OPENSSL_FOUND)
|
||||||
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
|
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
|
||||||
|
|
||||||
INCLUDE_DIRECTORIES("src")
|
SET(UCL_COMPILE_DEFS)
|
||||||
INCLUDE_DIRECTORIES("include")
|
IF(HAVE_FETCH_H)
|
||||||
INCLUDE_DIRECTORIES("uthash")
|
LIST(APPEND UCL_COMPILE_DEFS -DHAVE_FETCH_H=1)
|
||||||
INCLUDE_DIRECTORIES("klib")
|
ENDIF(HAVE_FETCH_H)
|
||||||
|
IF(CURL_FOUND)
|
||||||
|
LIST(APPEND UCL_COMPILE_DEFS -DCURL_FOUND=1)
|
||||||
|
ENDIF(CURL_FOUND)
|
||||||
|
IF(HAVE_OPENSSL)
|
||||||
|
LIST(APPEND UCL_COMPILE_DEFS -DHAVE_OPENSSL=1)
|
||||||
|
ENDIF(HAVE_OPENSSL)
|
||||||
|
IF(HAVE_ATOMIC_BUILTINS)
|
||||||
|
LIST(APPEND UCL_COMPILE_DEFS -DHAVE_ATOMIC_BUILTINS=1)
|
||||||
|
ENDIF(HAVE_ATOMIC_BUILTINS)
|
||||||
|
|
||||||
SET(UCLSRC src/ucl_util.c
|
SET(UCLSRC src/ucl_util.c
|
||||||
src/ucl_parser.c
|
src/ucl_parser.c
|
||||||
@ -207,13 +226,27 @@ SET(UCLSRC src/ucl_util.c
|
|||||||
src/ucl_msgpack.c
|
src/ucl_msgpack.c
|
||||||
src/ucl_sexp.c)
|
src/ucl_sexp.c)
|
||||||
|
|
||||||
|
SET(UCLHDR include/ucl.h
|
||||||
|
include/ucl++.h)
|
||||||
|
|
||||||
SET (LIB_TYPE STATIC)
|
SET (LIB_TYPE STATIC)
|
||||||
IF (BUILD_SHARED_LIBS)
|
IF (BUILD_SHARED_LIBS)
|
||||||
SET (LIB_TYPE SHARED)
|
SET (LIB_TYPE SHARED)
|
||||||
ENDIF (BUILD_SHARED_LIBS)
|
ENDIF (BUILD_SHARED_LIBS)
|
||||||
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
||||||
|
ADD_LIBRARY(ucl::ucl ALIAS ucl)
|
||||||
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(ucl
|
||||||
|
PUBLIC
|
||||||
|
include
|
||||||
|
PRIVATE
|
||||||
|
src
|
||||||
|
uthash
|
||||||
|
klib)
|
||||||
|
TARGET_COMPILE_DEFINITIONS(ucl
|
||||||
|
PRIVATE
|
||||||
|
${UCL_COMPILE_DEFS}
|
||||||
|
)
|
||||||
|
|
||||||
IF(ENABLE_LUA MATCHES "ON")
|
IF(ENABLE_LUA MATCHES "ON")
|
||||||
IF(ENABLE_LUAJIT MATCHES "ON")
|
IF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
@ -236,13 +269,20 @@ IF(ENABLE_LUA MATCHES "ON")
|
|||||||
ENDIF(ENABLE_LUAJIT MATCHES "ON")
|
ENDIF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
SET(UCL_LUA_SRC lua/lua_ucl.c)
|
SET(UCL_LUA_SRC lua/lua_ucl.c)
|
||||||
ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
|
ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
|
||||||
|
ADD_LIBRARY(ucl::lua ALIAS lua-ucl)
|
||||||
IF(ENABLE_LUAJIT MATCHES "ON")
|
IF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
|
TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
|
||||||
ELSE(ENABLE_LUAJIT MATCHES "ON")
|
ELSE(ENABLE_LUAJIT MATCHES "ON")
|
||||||
TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
|
TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}")
|
||||||
ENDIF(ENABLE_LUAJIT MATCHES "ON")
|
ENDIF(ENABLE_LUAJIT MATCHES "ON")
|
||||||
TARGET_LINK_LIBRARIES(lua-ucl ucl)
|
TARGET_LINK_LIBRARIES(lua-ucl ucl)
|
||||||
SET_TARGET_PROPERTIES(lua-ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
TARGET_INCLUDE_DIRECTORIES(lua-ucl PUBLIC include PRIVATE src uthash)
|
||||||
|
SET_TARGET_PROPERTIES(lua-ucl PROPERTIES
|
||||||
|
VERSION ${LIBUCL_VERSION}
|
||||||
|
SOVERSION ${LIBUCL_VERSION_MAJOR}
|
||||||
|
PUBLIC_HEADER include/lua_ucl.h)
|
||||||
|
INSTALL(TARGETS lua-ucl DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
IF(HAVE_FETCH_H)
|
IF(HAVE_FETCH_H)
|
||||||
@ -257,3 +297,18 @@ IF(ENABLE_URL_SIGN MATCHES "ON")
|
|||||||
TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES})
|
TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES})
|
||||||
ENDIF(OPENSSL_FOUND)
|
ENDIF(OPENSSL_FOUND)
|
||||||
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
|
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
|
||||||
|
|
||||||
|
IF(UNIX)
|
||||||
|
TARGET_LINK_LIBRARIES(ucl -lm)
|
||||||
|
ENDIF(UNIX)
|
||||||
|
|
||||||
|
SET_TARGET_PROPERTIES(ucl PROPERTIES
|
||||||
|
PUBLIC_HEADER "${UCLHDR}")
|
||||||
|
|
||||||
|
INSTALL(TARGETS ucl DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
|
|
||||||
|
IF(ENABLE_UTILS MATCHES "ON")
|
||||||
|
ADD_SUBDIRECTORY(utils)
|
||||||
|
ENDIF()
|
||||||
|
|
||||||
|
36
ChangeLog.md
36
ChangeLog.md
@ -65,3 +65,39 @@
|
|||||||
**Incompatible changes**:
|
**Incompatible changes**:
|
||||||
|
|
||||||
- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output
|
- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output
|
||||||
|
|
||||||
|
### Libucl 0.8.1
|
||||||
|
|
||||||
|
- Create ucl_parser_add_file_full() to be able to specify merge mode and parser type (by Allan Jude)
|
||||||
|
- C++ wrapper improvements (by @ftilde)
|
||||||
|
- C++ wrapper: add convenience method at() and lookup() (by Yonghee Kim)
|
||||||
|
- C++ wrapper: add assignment operator to Ucl class (by Yonghee Kim)
|
||||||
|
- C++ wrapper: support variables in parser (by Yonghee Kim)
|
||||||
|
- C++ wrapper: refactoring C++ interface (by Yonghee Kim):
|
||||||
|
- use auto variables (if possible)
|
||||||
|
- remove dangling expressions
|
||||||
|
- use std::set::emplace instead of std::set::insert
|
||||||
|
- not use std::move in return statement; considering copy elision
|
||||||
|
- C++ wrapper: fix compilation error and warnings (by Zhe Wang)
|
||||||
|
- C++ wrapper: fix iteration over objects in which the first value is `false` (by Zhe Wang)
|
||||||
|
- C++ wrapper: Macro helper functions (by Chris Meacham)
|
||||||
|
- C++ wrapper: Changing the duplicate strategy in the C++ API (by Chris Meacham)
|
||||||
|
- C++ wrapper: Added access functions for the size of a UCL_ARRAY (by Chris Meacham)
|
||||||
|
- Fix caseless comparison
|
||||||
|
- Fix include when EPERM is issued
|
||||||
|
- Fix Windows build
|
||||||
|
- Allow to reserve space in arrays and hashes
|
||||||
|
- Fix bug with including of empty files
|
||||||
|
- Move to mum_hash from xxhash
|
||||||
|
- Fix msgpack on non-x86
|
||||||
|
- python: Add support to Python 3 (by Denis Volpato Martins)
|
||||||
|
- python: Add support for Python 2.6 tests (by Denis Volpato Martins)
|
||||||
|
- python: Implement validation function and tests (by Denis Volpato Martins)
|
||||||
|
- python: Added UCL_NULL handling and tests (by Denis Volpato Martins)
|
||||||
|
- Fix schema validation for patternProperties with object data (by Denis Volpato Martins)
|
||||||
|
- Remove the dependency on NBBY, add missing <strings.h> include (by Ed Schouten)
|
||||||
|
- Allow to emit msgpack from Lua
|
||||||
|
- Performance improvements in Lua API
|
||||||
|
- Allow to pass opaque objects in Lua API for transparent C passthrough
|
||||||
|
- Various bugs fixed
|
||||||
|
- Couple of memory leaks plugged
|
64
README.md
64
README.md
@ -1,6 +1,6 @@
|
|||||||
# LIBUCL
|
# LIBUCL
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/vstakhov/libucl.svg?branch=master)](https://travis-ci.org/vstakhov/libucl)
|
[![CircleCI](https://circleci.com/gh/vstakhov/libucl.svg?style=svg)](https://circleci.com/gh/vstakhov/libucl)
|
||||||
[![Coverity](https://scan.coverity.com/projects/4138/badge.svg)](https://scan.coverity.com/projects/4138)
|
[![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)
|
[![Coverage Status](https://coveralls.io/repos/github/vstakhov/libucl/badge.svg?branch=master)](https://coveralls.io/github/vstakhov/libucl?branch=master)
|
||||||
|
|
||||||
@ -18,6 +18,7 @@
|
|||||||
- [Macros support](#macros-support)
|
- [Macros support](#macros-support)
|
||||||
- [Variables support](#variables-support)
|
- [Variables support](#variables-support)
|
||||||
- [Multiline strings](#multiline-strings)
|
- [Multiline strings](#multiline-strings)
|
||||||
|
- [Single quoted strings](#single-quoted-strings)
|
||||||
- [Emitter](#emitter)
|
- [Emitter](#emitter)
|
||||||
- [Validation](#validation)
|
- [Validation](#validation)
|
||||||
- [Performance](#performance)
|
- [Performance](#performance)
|
||||||
@ -65,19 +66,25 @@ section {
|
|||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"param": "value",
|
"param": "value",
|
||||||
"param1": "value1",
|
"section": {
|
||||||
"flag": true,
|
"param": "value",
|
||||||
"subsection": {
|
"param1": "value1",
|
||||||
"host": [
|
"flag": true,
|
||||||
{
|
"number": 10000,
|
||||||
"host": "hostname",
|
"time": "0.2s",
|
||||||
"port": 900
|
"string": "something",
|
||||||
},
|
"subsection": {
|
||||||
{
|
"host": [
|
||||||
"host": "hostname",
|
{
|
||||||
"port": 901
|
"host": "hostname",
|
||||||
|
"port": 900
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"host": "hostname",
|
||||||
|
"port": 901
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -288,7 +295,22 @@ as following:
|
|||||||
|
|
||||||
By default, the priority of top-level object is set to zero (lowest priority). Currently,
|
By default, the priority of top-level object is set to zero (lowest priority). Currently,
|
||||||
you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will
|
you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will
|
||||||
rewrite keys from the objects with lower priorities as specified by the policy.
|
rewrite keys from the objects with lower priorities as specified by the policy. The priority
|
||||||
|
of the top-level or any other object can be changed with the `.priority` macro, which has no
|
||||||
|
options and takes the new priority:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Default priority: 0.
|
||||||
|
foo = 6
|
||||||
|
.priority 5
|
||||||
|
# The following will have priority 5.
|
||||||
|
bar = 6
|
||||||
|
baz = 7
|
||||||
|
# The following will be included with a priority of 3, 5, and 6 respectively.
|
||||||
|
.include(priority=3) "path.conf"
|
||||||
|
.include(priority=5) "equivalent-path.conf"
|
||||||
|
.include(priority=6) "highpriority-path.conf"
|
||||||
|
```
|
||||||
|
|
||||||
### Variables support
|
### Variables support
|
||||||
|
|
||||||
@ -333,9 +355,21 @@ text
|
|||||||
EOD
|
EOD
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Single quoted strings
|
||||||
|
|
||||||
|
It is possible to use single quoted strings to simplify escaping rules. All values passed in single quoted strings are *NOT* escaped, with two exceptions: a single `'` character just before `\` character, and a newline character just after `\` character that is ignored.
|
||||||
|
|
||||||
|
```
|
||||||
|
key = 'value'; # Read as value
|
||||||
|
key = 'value\n\'; # Read as value\n\
|
||||||
|
key = 'value\''; # Read as value'
|
||||||
|
key = 'value\
|
||||||
|
bla'; # Read as valuebla
|
||||||
|
```
|
||||||
|
|
||||||
## Emitter
|
## Emitter
|
||||||
|
|
||||||
Each UCL object can be serialized to one of the three supported formats:
|
Each UCL object can be serialized to one of the four supported formats:
|
||||||
|
|
||||||
* `JSON` - canonic json notation (with spaces indented structure);
|
* `JSON` - canonic json notation (with spaces indented structure);
|
||||||
* `Compacted JSON` - compact json notation (without spaces or newlines);
|
* `Compacted JSON` - compact json notation (without spaces or newlines);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
m4_define([maj_ver], [0])
|
m4_define([maj_ver], [0])
|
||||||
m4_define([med_ver], [8])
|
m4_define([med_ver], [8])
|
||||||
m4_define([min_ver], [0])
|
m4_define([min_ver], [1])
|
||||||
m4_define([so_version], [6:0:0])
|
m4_define([so_version], [6:0:1])
|
||||||
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
||||||
|
|
||||||
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
||||||
@ -73,11 +73,11 @@ AC_ARG_ENABLE([utils],
|
|||||||
AM_CONDITIONAL([UTILS], [test x$utils = xtrue])
|
AM_CONDITIONAL([UTILS], [test x$utils = xtrue])
|
||||||
|
|
||||||
AS_IF([test "x$enable_signatures" = "xyes"], [
|
AS_IF([test "x$enable_signatures" = "xyes"], [
|
||||||
AC_SEARCH_LIBS([EVP_MD_CTX_create], [crypto], [
|
AC_SEARCH_LIBS([CRYPTO_new_ex_data], [crypto], [
|
||||||
AC_DEFINE(HAVE_OPENSSL, 1, [Define to 1 if you have the 'crypto' library (-lcrypto).])
|
AC_DEFINE(HAVE_OPENSSL, 1, [Define to 1 if you have the 'crypto' library (-lcrypto).])
|
||||||
LIBCRYPTO_LIB="-lcrypto"
|
LIBCRYPTO_LIB="-lcrypto"
|
||||||
LIBS_EXTRA="${LIBS_EXTRA} -lcrypto"
|
LIBS_EXTRA="${LIBS_EXTRA} -lcrypto"
|
||||||
], [AC_MSG_ERROR([unable to find the EVP_MD_CTX_create() function])])
|
], [AC_MSG_ERROR([unable to find the CRYPTO_new_ex_data() function])])
|
||||||
])
|
])
|
||||||
AC_SUBST(LIBCRYPTO_LIB)
|
AC_SUBST(LIBCRYPTO_LIB)
|
||||||
AC_PATH_PROG(PANDOC, pandoc, [/non/existent])
|
AC_PATH_PROG(PANDOC, pandoc, [/non/existent])
|
||||||
|
17
doc/api.md
17
doc/api.md
@ -243,7 +243,7 @@ return ret;
|
|||||||
|
|
||||||
# Emitting functions
|
# Emitting functions
|
||||||
|
|
||||||
Libucl can transform UCL objects to a number of tectual formats:
|
Libucl can transform UCL objects to a number of textual formats:
|
||||||
|
|
||||||
- configuration (`UCL_EMIT_CONFIG`) - nginx like human readable configuration file where implicit arrays are transformed to the duplicate keys
|
- configuration (`UCL_EMIT_CONFIG`) - nginx like human readable configuration file where implicit arrays are transformed to the duplicate keys
|
||||||
- compact json: `UCL_EMIT_JSON_COMPACT` - single line valid json without spaces
|
- compact json: `UCL_EMIT_JSON_COMPACT` - single line valid json without spaces
|
||||||
@ -349,7 +349,7 @@ This object should be released by caller.
|
|||||||
Libucl provides the functions similar to inverse conversion functions called with the specific C type:
|
Libucl provides the functions similar to inverse conversion functions called with the specific C type:
|
||||||
- `ucl_object_fromint` - converts `int64_t` to UCL object
|
- `ucl_object_fromint` - converts `int64_t` to UCL object
|
||||||
- `ucl_object_fromdouble` - converts `double` to UCL object
|
- `ucl_object_fromdouble` - converts `double` to UCL object
|
||||||
- `ucl_object_fromboolean` - converts `bool` to UCL object
|
- `ucl_object_frombool` - converts `bool` to UCL object
|
||||||
- `ucl_object_fromstring` - converts `const char *` to UCL object (this string should be NULL terminated)
|
- `ucl_object_fromstring` - converts `const char *` to UCL object (this string should be NULL terminated)
|
||||||
- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string does not need to be NULL terminated)
|
- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string does not need to be NULL terminated)
|
||||||
|
|
||||||
@ -432,7 +432,8 @@ UCL defines the following functions to manage safe iterators:
|
|||||||
|
|
||||||
- `ucl_object_iterate_new` - creates new safe iterator
|
- `ucl_object_iterate_new` - creates new safe iterator
|
||||||
- `ucl_object_iterate_reset` - resets iterator to a new object
|
- `ucl_object_iterate_reset` - resets iterator to a new object
|
||||||
- `ucl_object_iterate_safe` - safely iterate the object inside iterator
|
- `ucl_object_iterate_safe` - safely iterate the object inside iterator. Note: function may allocate and free memory during its operation. Therefore it returns `NULL` either while trying to access item after the last one or when exception (such as memory allocation failure) happens.
|
||||||
|
- `ucl_object_iter_chk_excpn` - check if the last call to `ucl_object_iterate_safe` ended up in unrecoverable exception (e.g. `ENOMEM`).
|
||||||
- `ucl_object_iterate_free` - free memory associated with the safe iterator
|
- `ucl_object_iterate_free` - free memory associated with the safe iterator
|
||||||
|
|
||||||
Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed.
|
Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed.
|
||||||
@ -447,6 +448,11 @@ it = ucl_object_iterate_new (obj);
|
|||||||
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
|
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
|
||||||
/* Do something */
|
/* Do something */
|
||||||
}
|
}
|
||||||
|
/* Check error condition */
|
||||||
|
if (ucl_object_iter_chk_excpn (it)) {
|
||||||
|
ucl_object_iterate_free (it);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Switch to another object */
|
/* Switch to another object */
|
||||||
it = ucl_object_iterate_reset (it, another_obj);
|
it = ucl_object_iterate_reset (it, another_obj);
|
||||||
@ -454,6 +460,11 @@ it = ucl_object_iterate_reset (it, another_obj);
|
|||||||
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
|
while ((cur = ucl_object_iterate_safe (it, true)) != NULL) {
|
||||||
/* Do something else */
|
/* Do something else */
|
||||||
}
|
}
|
||||||
|
/* Check error condition */
|
||||||
|
if (ucl_object_iter_chk_excpn (it)) {
|
||||||
|
ucl_object_iterate_free (it);
|
||||||
|
exit (1);
|
||||||
|
}
|
||||||
|
|
||||||
ucl_object_iterate_free (it);
|
ucl_object_iterate_free (it);
|
||||||
~~~
|
~~~
|
||||||
|
26
doc/libucl.3
26
doc/libucl.3
@ -612,15 +612,23 @@ Iteration\ without\ expansion:
|
|||||||
.PP
|
.PP
|
||||||
UCL defines the following functions to manage safe iterators:
|
UCL defines the following functions to manage safe iterators:
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator
|
\f[C]ucl_object_iterate_new\f[] \- creates new safe iterator.
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object
|
\f[C]ucl_object_iterate_reset\f[] \- resets iterator to a new object.
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[C]ucl_object_iterate_safe\f[] \- safely iterate the object inside
|
\f[C]ucl_object_iterate_safe\f[] \- safely iterate the object inside
|
||||||
iterator
|
iterator.
|
||||||
|
Note: function may allocate and free memory during its operation.
|
||||||
|
Therefore it returns \f[C]NULL\f[] either while trying to access item
|
||||||
|
after the last one or when exception (such as memory allocation
|
||||||
|
failure) happens.
|
||||||
|
.IP \[bu] 2
|
||||||
|
\f[C]ucl_object_iter_chk_excpn\f[] \- check if the last call to
|
||||||
|
\f[C]ucl_object_iterate_safe\f[] ended up in unrecoverable exception
|
||||||
|
(e.g. \f[C]ENOMEM\f[]).
|
||||||
.IP \[bu] 2
|
.IP \[bu] 2
|
||||||
\f[C]ucl_object_iterate_free\f[] \- free memory associated with the safe
|
\f[C]ucl_object_iterate_free\f[] \- free memory associated with the safe
|
||||||
iterator
|
iterator.
|
||||||
.PP
|
.PP
|
||||||
Please note that unlike unsafe iterators, safe iterators \f[I]must\f[]
|
Please note that unlike unsafe iterators, safe iterators \f[I]must\f[]
|
||||||
be explicitly initialized and freed.
|
be explicitly initialized and freed.
|
||||||
@ -637,6 +645,11 @@ it\ =\ ucl_object_iterate_new\ (obj);
|
|||||||
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
|
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
|
||||||
\ \ \ \ /*\ Do\ something\ */
|
\ \ \ \ /*\ Do\ something\ */
|
||||||
}
|
}
|
||||||
|
/*\ Check\ error\ condition\ */
|
||||||
|
if\ (ucl_object_iter_chk_excpn\ (it))\ {
|
||||||
|
\ \ \ \ ucl_object_iterate_free\ (it);
|
||||||
|
\ \ \ \ exit\ (1);
|
||||||
|
}
|
||||||
|
|
||||||
/*\ Switch\ to\ another\ object\ */
|
/*\ Switch\ to\ another\ object\ */
|
||||||
it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
|
it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
|
||||||
@ -644,6 +657,11 @@ it\ =\ ucl_object_iterate_reset\ (it,\ another_obj);
|
|||||||
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
|
while\ ((cur\ =\ ucl_object_iterate_safe\ (it,\ true))\ !=\ NULL)\ {
|
||||||
\ \ \ \ /*\ Do\ something\ else\ */
|
\ \ \ \ /*\ Do\ something\ else\ */
|
||||||
}
|
}
|
||||||
|
/*\ Check\ error\ condition\ */
|
||||||
|
if\ (ucl_object_iter_chk_excpn\ (it))\ {
|
||||||
|
\ \ \ \ ucl_object_iterate_free\ (it);
|
||||||
|
\ \ \ \ exit\ (1);
|
||||||
|
}
|
||||||
|
|
||||||
ucl_object_iterate_free\ (it);
|
ucl_object_iterate_free\ (it);
|
||||||
\f[]
|
\f[]
|
||||||
|
@ -69,8 +69,8 @@ converts `obj` to lua representation using the following conversions:
|
|||||||
- *scalar* values are directly presented by lua objects
|
- *scalar* values are directly presented by lua objects
|
||||||
- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
|
- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`,
|
||||||
this can be used to pass functions from lua to c and vice-versa
|
this can be used to pass functions from lua to c and vice-versa
|
||||||
- *arrays* are converted to lua tables with numeric indicies suitable for `ipairs` iterations
|
- *arrays* are converted to lua tables with numeric indices suitable for `ipairs` iterations
|
||||||
- *objects* are converted to lua tables with string indicies
|
- *objects* are converted to lua tables with string indices
|
||||||
|
|
||||||
**Parameters:**
|
**Parameters:**
|
||||||
|
|
||||||
|
@ -54,6 +54,14 @@ UCL_EXTERN int luaopen_ucl (lua_State *L);
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);
|
UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import UCL object from lua state, escaping JSON strings
|
||||||
|
* @param L lua state
|
||||||
|
* @param idx index of object at the lua stack to convert to UCL
|
||||||
|
* @return new UCL object or NULL, the caller should unref object after using
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t* ucl_object_lua_import_escape (lua_State *L, int idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push an object to lua
|
* Push an object to lua
|
||||||
* @param L lua state
|
* @param L lua state
|
||||||
@ -62,8 +70,16 @@ UCL_EXTERN ucl_object_t* ucl_object_lua_import (lua_State *L, int idx);
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN int ucl_object_push_lua (lua_State *L,
|
UCL_EXTERN int ucl_object_push_lua (lua_State *L,
|
||||||
const ucl_object_t *obj, bool allow_array);
|
const ucl_object_t *obj, bool allow_array);
|
||||||
|
/**
|
||||||
|
* Push an object to lua replacing all ucl.null with `false`
|
||||||
|
* @param L lua state
|
||||||
|
* @param obj object to push
|
||||||
|
* @param allow_array traverse over implicit arrays
|
||||||
|
*/
|
||||||
|
UCL_EXTERN int ucl_object_push_lua_filter_nil (lua_State *L,
|
||||||
|
const ucl_object_t *obj,
|
||||||
|
bool allow_array);
|
||||||
|
|
||||||
UCL_EXTERN struct ucl_lua_funcdata* ucl_object_toclosure (
|
UCL_EXTERN struct ucl_lua_funcdata* ucl_object_toclosure (const ucl_object_t *obj);
|
||||||
const ucl_object_t *obj);
|
|
||||||
|
|
||||||
#endif /* LUA_UCL_H_ */
|
#endif /* LUA_UCL_H_ */
|
||||||
|
189
include/ucl++.h
189
include/ucl++.h
@ -29,6 +29,7 @@
|
|||||||
#include <set>
|
#include <set>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
#include "ucl.h"
|
#include "ucl.h"
|
||||||
|
|
||||||
@ -106,7 +107,7 @@ class Ucl final {
|
|||||||
static bool ucl_variable_getter(const unsigned char *data, size_t len,
|
static bool ucl_variable_getter(const unsigned char *data, size_t len,
|
||||||
unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
|
unsigned char ** /*replace*/, size_t * /*replace_len*/, bool *need_free, void* ud)
|
||||||
{
|
{
|
||||||
*need_free = false;
|
*need_free = false;
|
||||||
|
|
||||||
auto vars = reinterpret_cast<std::set<std::string> *>(ud);
|
auto vars = reinterpret_cast<std::set<std::string> *>(ud);
|
||||||
if (vars && data && len != 0) {
|
if (vars && data && len != 0) {
|
||||||
@ -123,17 +124,17 @@ class Ucl final {
|
|||||||
auto replacer = reinterpret_cast<variable_replacer *>(ud);
|
auto replacer = reinterpret_cast<variable_replacer *>(ud);
|
||||||
if (!replacer) {
|
if (!replacer) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string var_name (data, data + len);
|
std::string var_name (data, data + len);
|
||||||
if (!replacer->is_variable (var_name)) {
|
if (!replacer->is_variable (var_name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string var_value = replacer->replace (var_name);
|
std::string var_value = replacer->replace (var_name);
|
||||||
if (var_value.empty ()) {
|
if (var_value.empty ()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
*replace = (unsigned char *)UCL_ALLOC (var_value.size ());
|
*replace = (unsigned char *)UCL_ALLOC (var_value.size ());
|
||||||
memcpy (*replace, var_value.data (), var_value.size ());
|
memcpy (*replace, var_value.data (), var_value.size ());
|
||||||
@ -152,7 +153,8 @@ class Ucl final {
|
|||||||
config_func (parser);
|
config_func (parser);
|
||||||
|
|
||||||
if (!parse_func (parser)) {
|
if (!parse_func (parser)) {
|
||||||
err.assign (ucl_parser_get_error (parser));
|
const char *error = ucl_parser_get_error (parser); //Assigning here without checking result first causes a
|
||||||
|
if( error != NULL ) err.assign(error); // crash if ucl_parser_get_error returns NULL
|
||||||
ucl_parser_free (parser);
|
ucl_parser_free (parser);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -168,6 +170,16 @@ class Ucl final {
|
|||||||
std::unique_ptr<ucl_object_t, ucl_deleter> obj;
|
std::unique_ptr<ucl_object_t, ucl_deleter> obj;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct macro_handler_s {
|
||||||
|
ucl_macro_handler handler;
|
||||||
|
ucl_context_macro_handler ctx_handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct macro_userdata_s {
|
||||||
|
ucl_parser *parser;
|
||||||
|
void *userdata;
|
||||||
|
};
|
||||||
|
|
||||||
class const_iterator {
|
class const_iterator {
|
||||||
private:
|
private:
|
||||||
struct ucl_iter_deleter {
|
struct ucl_iter_deleter {
|
||||||
@ -184,7 +196,7 @@ class Ucl final {
|
|||||||
it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
|
it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
|
||||||
ucl_iter_deleter());
|
ucl_iter_deleter());
|
||||||
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
|
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
|
||||||
if (cur->type() == UCL_NULL) {
|
if (!cur->obj) {
|
||||||
it.reset ();
|
it.reset ();
|
||||||
cur.reset ();
|
cur.reset ();
|
||||||
}
|
}
|
||||||
@ -218,7 +230,7 @@ class Ucl final {
|
|||||||
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
|
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur && cur->type() == UCL_NULL) {
|
if (cur && !cur->obj) {
|
||||||
it.reset ();
|
it.reset ();
|
||||||
cur.reset ();
|
cur.reset ();
|
||||||
}
|
}
|
||||||
@ -330,7 +342,7 @@ class Ucl final {
|
|||||||
return UCL_NULL;
|
return UCL_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string key () const {
|
std::string key () const {
|
||||||
std::string res;
|
std::string res;
|
||||||
|
|
||||||
if (obj->key) {
|
if (obj->key) {
|
||||||
@ -373,7 +385,7 @@ class Ucl final {
|
|||||||
return default_val;
|
return default_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string string_value (const std::string& default_val = "") const
|
std::string string_value (const std::string& default_val = "") const
|
||||||
{
|
{
|
||||||
const char* res = nullptr;
|
const char* res = nullptr;
|
||||||
|
|
||||||
@ -384,7 +396,16 @@ class Ucl final {
|
|||||||
return default_val;
|
return default_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ucl at (size_t i) const
|
size_t size () const
|
||||||
|
{
|
||||||
|
if (type () == UCL_ARRAY) {
|
||||||
|
return ucl_array_size (obj.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ucl at (size_t i) const
|
||||||
{
|
{
|
||||||
if (type () == UCL_ARRAY) {
|
if (type () == UCL_ARRAY) {
|
||||||
return Ucl (ucl_array_find_index (obj.get(), i));
|
return Ucl (ucl_array_find_index (obj.get(), i));
|
||||||
@ -393,7 +414,7 @@ class Ucl final {
|
|||||||
return Ucl (nullptr);
|
return Ucl (nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
const Ucl lookup (const std::string &key) const
|
Ucl lookup (const std::string &key) const
|
||||||
{
|
{
|
||||||
if (type () == UCL_OBJECT) {
|
if (type () == UCL_OBJECT) {
|
||||||
return Ucl (ucl_object_lookup_len (obj.get(),
|
return Ucl (ucl_object_lookup_len (obj.get(),
|
||||||
@ -403,12 +424,12 @@ class Ucl final {
|
|||||||
return Ucl (nullptr);
|
return Ucl (nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Ucl operator[] (size_t i) const
|
inline Ucl operator[] (size_t i) const
|
||||||
{
|
{
|
||||||
return at(i);
|
return at(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const Ucl operator[](const std::string &key) const
|
inline Ucl operator[](const std::string &key) const
|
||||||
{
|
{
|
||||||
return lookup(key);
|
return lookup(key);
|
||||||
}
|
}
|
||||||
@ -432,43 +453,116 @@ class Ucl final {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const std::string &in, std::string &err)
|
static Ucl parse (const std::string &in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
{
|
{
|
||||||
return parse (in, std::map<std::string, std::string>(), err);
|
return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars, std::string &err)
|
static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
{
|
{
|
||||||
auto config_func = [&vars] (ucl_parser *parser) {
|
std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
|
||||||
|
return parse ( in, vars, emptyVector, err, duplicate_strategy );
|
||||||
|
}
|
||||||
|
|
||||||
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const std::string &in,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const std::string &in, const std::map<std::string, std::string> &vars,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
|
||||||
|
std::vector<macro_userdata_s> userdata_list;
|
||||||
|
userdata_list.reserve (macros.size());
|
||||||
|
auto config_func = [&userdata_list, &vars, ¯os] (ucl_parser *parser) {
|
||||||
for (const auto & item : vars) {
|
for (const auto & item : vars) {
|
||||||
ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
|
ucl_parser_register_variable (parser, item.first.c_str (), item.second.c_str ());
|
||||||
}
|
}
|
||||||
|
for (auto & macro : macros) {
|
||||||
|
userdata_list.push_back ({parser, std::get<2>(macro)});
|
||||||
|
if (std::get<1>(macro).handler != NULL) {
|
||||||
|
ucl_parser_register_macro (parser,
|
||||||
|
std::get<0>(macro).c_str(),
|
||||||
|
std::get<1>(macro).handler,
|
||||||
|
reinterpret_cast<void*>(&userdata_list.back()));
|
||||||
|
}
|
||||||
|
else if (std::get<1>(macro).ctx_handler != NULL) {
|
||||||
|
ucl_parser_register_context_macro (parser,
|
||||||
|
std::get<0>(macro).c_str(),
|
||||||
|
std::get<1>(macro).ctx_handler,
|
||||||
|
reinterpret_cast<void*>(&userdata_list.back()));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parse_func = [&in] (ucl_parser *parser) {
|
auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
|
||||||
return ucl_parser_add_chunk (parser, (unsigned char *)in.data (), in.size ());
|
return ucl_parser_add_chunk_full (parser,
|
||||||
|
(unsigned char *) in.data (),
|
||||||
|
in.size (),
|
||||||
|
(unsigned int)ucl_parser_get_default_priority (parser),
|
||||||
|
duplicate_strategy,
|
||||||
|
UCL_PARSE_UCL);
|
||||||
};
|
};
|
||||||
|
|
||||||
return parse_with_strategy_function (config_func, parse_func, err);
|
return parse_with_strategy_function (config_func, parse_func, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const std::string &in, const variable_replacer &replacer, std::string &err)
|
static Ucl parse (const std::string &in, const variable_replacer &replacer,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
{
|
{
|
||||||
auto config_func = [&replacer] (ucl_parser *parser) {
|
std::vector< std::tuple< std::string, macro_handler_s, void * > > emptyVector;
|
||||||
ucl_parser_set_variables_handler (parser, ucl_variable_replacer,
|
return parse ( in, replacer, emptyVector, err, duplicate_strategy );
|
||||||
&const_cast<variable_replacer &>(replacer));
|
}
|
||||||
|
|
||||||
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const std::string &in, const variable_replacer &replacer,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
//Preserve macro_userdata_s memory for later use in parse_with_strategy_function()
|
||||||
|
std::vector<macro_userdata_s> userdata_list;
|
||||||
|
userdata_list.reserve (macros.size());
|
||||||
|
auto config_func = [&userdata_list, &replacer, ¯os] (ucl_parser *parser) {
|
||||||
|
ucl_parser_set_variables_handler (parser, ucl_variable_replacer, &const_cast<variable_replacer &>(replacer));
|
||||||
|
for (auto & macro : macros) {
|
||||||
|
userdata_list.push_back ({parser, std::get<2>(macro)});
|
||||||
|
if (std::get<1>(macro).handler != NULL) {
|
||||||
|
ucl_parser_register_macro (parser,
|
||||||
|
std::get<0>(macro).c_str(),
|
||||||
|
std::get<1>(macro).handler,
|
||||||
|
reinterpret_cast<void*>(&userdata_list.back()));
|
||||||
|
}
|
||||||
|
else if (std::get<1>(macro).ctx_handler != NULL) {
|
||||||
|
ucl_parser_register_context_macro (parser,
|
||||||
|
std::get<0>(macro).c_str(),
|
||||||
|
std::get<1>(macro).ctx_handler,
|
||||||
|
reinterpret_cast<void*>(&userdata_list.back()));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
auto parse_func = [&in] (ucl_parser *parser) {
|
auto parse_func = [&in, &duplicate_strategy] (struct ucl_parser *parser) -> bool {
|
||||||
return ucl_parser_add_chunk (parser, (unsigned char *) in.data (), in.size ());
|
return ucl_parser_add_chunk_full (parser,
|
||||||
|
(unsigned char *) in.data (),
|
||||||
|
in.size (),
|
||||||
|
(unsigned int)ucl_parser_get_default_priority (parser),
|
||||||
|
duplicate_strategy,
|
||||||
|
UCL_PARSE_UCL);
|
||||||
};
|
};
|
||||||
|
|
||||||
return parse_with_strategy_function (config_func, parse_func, err);
|
return parse_with_strategy_function (config_func, parse_func, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const char *in, std::string &err)
|
static Ucl parse (const char *in, std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
{
|
{
|
||||||
return parse (in, std::map<std::string, std::string>(), err);
|
return parse (in, std::map<std::string, std::string>(), err, duplicate_strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
|
static Ucl parse (const char *in, const std::map<std::string, std::string> &vars, std::string &err)
|
||||||
@ -480,13 +574,46 @@ class Ucl final {
|
|||||||
return parse (std::string (in), vars, err);
|
return parse (std::string (in), vars, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse (const char *in, const variable_replacer &replacer, std::string &err)
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const char *in,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
return parse (in, std::map<std::string, std::string>(), macros, err, duplicate_strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const char *in, const std::map<std::string, std::string> &vars,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
{
|
{
|
||||||
if (!in) {
|
if (!in) {
|
||||||
err = "null input";
|
err = "null input";
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return parse (std::string(in), replacer, err);
|
return parse (std::string (in), vars, macros, err, duplicate_strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Ucl parse (const char *in, const variable_replacer &replacer,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
if (!in) {
|
||||||
|
err = "null input";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return parse (std::string(in), replacer, err, duplicate_strategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Macro handler will receive a macro_userdata_s as void *ud
|
||||||
|
static Ucl parse (const char *in, const variable_replacer &replacer,
|
||||||
|
std::vector< std::tuple< std::string /*name*/, macro_handler_s, void * /*userdata*/ > > ¯os,
|
||||||
|
std::string &err, enum ucl_duplicate_strategy duplicate_strategy = UCL_DUPLICATE_APPEND)
|
||||||
|
{
|
||||||
|
if (!in) {
|
||||||
|
err = "null input";
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return parse (std::string (in), replacer, macros, err, duplicate_strategy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Ucl parse_from_file (const std::string &filename, std::string &err)
|
static Ucl parse_from_file (const std::string &filename, std::string &err)
|
||||||
@ -556,7 +683,7 @@ class Ucl final {
|
|||||||
|
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
std::move (vars.begin (), vars.end (), std::back_inserter (result));
|
std::move (vars.begin (), vars.end (), std::back_inserter (result));
|
||||||
return std::move (result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ucl& operator= (Ucl rhs)
|
Ucl& operator= (Ucl rhs)
|
||||||
|
191
include/ucl.h
191
include/ucl.h
@ -105,10 +105,11 @@ typedef enum ucl_error {
|
|||||||
UCL_EIO, /**< IO error occurred during parsing */
|
UCL_EIO, /**< IO error occurred during parsing */
|
||||||
UCL_ESTATE, /**< Invalid state machine state */
|
UCL_ESTATE, /**< Invalid state machine state */
|
||||||
UCL_ENESTED, /**< Input has too many recursion levels */
|
UCL_ENESTED, /**< Input has too many recursion levels */
|
||||||
|
UCL_EUNPAIRED, /**< Input has too many recursion levels */
|
||||||
UCL_EMACRO, /**< Error processing a macro */
|
UCL_EMACRO, /**< Error processing a macro */
|
||||||
UCL_EINTERNAL, /**< Internal unclassified error */
|
UCL_EINTERNAL, /**< Internal unclassified error */
|
||||||
UCL_ESSL, /**< SSL error */
|
UCL_ESSL, /**< SSL error */
|
||||||
UCL_EMERGE /**< A merge error occured */
|
UCL_EMERGE /**< A merge error occurred */
|
||||||
} ucl_error_t;
|
} ucl_error_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -177,7 +178,8 @@ typedef enum ucl_string_flags {
|
|||||||
} ucl_string_flags_t;
|
} ucl_string_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic flags for an object
|
* Basic flags for an object (can use up to 12 bits as higher 4 bits are used
|
||||||
|
* for priorities)
|
||||||
*/
|
*/
|
||||||
typedef enum ucl_object_flags {
|
typedef enum ucl_object_flags {
|
||||||
UCL_OBJECT_ALLOCATED_KEY = (1 << 0), /**< An object has key allocated internally */
|
UCL_OBJECT_ALLOCATED_KEY = (1 << 0), /**< An object has key allocated internally */
|
||||||
@ -187,7 +189,8 @@ typedef enum ucl_object_flags {
|
|||||||
UCL_OBJECT_MULTILINE = (1 << 4), /**< String should be displayed as multiline string */
|
UCL_OBJECT_MULTILINE = (1 << 4), /**< String should be displayed as multiline string */
|
||||||
UCL_OBJECT_MULTIVALUE = (1 << 5), /**< Object is a key with multiple values */
|
UCL_OBJECT_MULTIVALUE = (1 << 5), /**< Object is a key with multiple values */
|
||||||
UCL_OBJECT_INHERITED = (1 << 6), /**< Object has been inherited from another */
|
UCL_OBJECT_INHERITED = (1 << 6), /**< Object has been inherited from another */
|
||||||
UCL_OBJECT_BINARY = (1 << 7) /**< Object contains raw binary data */
|
UCL_OBJECT_BINARY = (1 << 7), /**< Object contains raw binary data */
|
||||||
|
UCL_OBJECT_SQUOTED = (1 << 8) /**< Object has been enclosed in single quotes */
|
||||||
} ucl_object_flags_t;
|
} ucl_object_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -462,6 +465,14 @@ UCL_EXTERN ucl_object_t* ucl_object_pop_key (ucl_object_t *top, const char *key)
|
|||||||
UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
|
UCL_EXTERN bool ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
|
||||||
const char *key, size_t keylen, bool copy_key);
|
const char *key, size_t keylen, bool copy_key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserve space in ucl array or object for `elt` elements
|
||||||
|
* @param obj object to reserve
|
||||||
|
* @param reserved size to reserve in an object
|
||||||
|
* @return 0 on success, -1 on failure (i.e. ENOMEM)
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_object_reserve (ucl_object_t *obj, size_t reserved);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append an element to the end of array object
|
* Append an element to the end of array object
|
||||||
* @param top destination object (must NOT be NULL)
|
* @param top destination object (must NOT be NULL)
|
||||||
@ -533,6 +544,13 @@ UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
|
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return size of the array `top`
|
||||||
|
* @param top object to get size from (must be of type UCL_ARRAY)
|
||||||
|
* @return size of the array
|
||||||
|
*/
|
||||||
|
UCL_EXTERN unsigned int ucl_array_size (const ucl_object_t *top);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return object identified by index of the array `top`
|
* Return object identified by index of the array `top`
|
||||||
* @param top object to get a key from (must be of type UCL_ARRAY)
|
* @param top object to get a key from (must be of type UCL_ARRAY)
|
||||||
@ -782,6 +800,19 @@ UCL_EXTERN int ucl_object_compare_qsort (const ucl_object_t **o1,
|
|||||||
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
|
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
|
||||||
int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2));
|
int (*cmp)(const ucl_object_t **o1, const ucl_object_t **o2));
|
||||||
|
|
||||||
|
enum ucl_object_keys_sort_flags {
|
||||||
|
UCL_SORT_KEYS_DEFAULT = 0,
|
||||||
|
UCL_SORT_KEYS_ICASE = (1u << 0u),
|
||||||
|
UCL_SORT_KEYS_RECURSIVE = (1u << 1u),
|
||||||
|
};
|
||||||
|
/***
|
||||||
|
* Sorts keys in object in place
|
||||||
|
* @param obj
|
||||||
|
* @param how
|
||||||
|
*/
|
||||||
|
UCL_EXTERN void ucl_object_sort_keys (ucl_object_t *obj,
|
||||||
|
enum ucl_object_keys_sort_flags how);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the priority for specific UCL object
|
* Get the priority for specific UCL object
|
||||||
* @param obj any ucl object
|
* @param obj any ucl object
|
||||||
@ -808,11 +839,14 @@ typedef void* ucl_object_iter_t;
|
|||||||
* @param iter opaque iterator, must be set to NULL on the first call:
|
* @param iter opaque iterator, must be set to NULL on the first call:
|
||||||
* ucl_object_iter_t it = NULL;
|
* ucl_object_iter_t it = NULL;
|
||||||
* while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
|
* while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
|
||||||
|
* @param ep pointer record exception (such as ENOMEM), could be NULL
|
||||||
* @return the next object or NULL
|
* @return the next object or NULL
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj,
|
UCL_EXTERN const ucl_object_t* ucl_object_iterate_with_error (const ucl_object_t *obj,
|
||||||
ucl_object_iter_t *iter, bool expand_values);
|
ucl_object_iter_t *iter, bool expand_values, int *ep);
|
||||||
|
|
||||||
#define ucl_iterate_object ucl_object_iterate
|
#define ucl_iterate_object ucl_object_iterate
|
||||||
|
#define ucl_object_iterate(ob, it, ev) ucl_object_iterate_with_error((ob), (it), (ev), NULL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new safe iterator for the specified object
|
* Create new safe iterator for the specified object
|
||||||
@ -821,6 +855,15 @@ UCL_EXTERN const ucl_object_t* ucl_object_iterate (const ucl_object_t *obj,
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj)
|
UCL_EXTERN ucl_object_iter_t ucl_object_iterate_new (const ucl_object_t *obj)
|
||||||
UCL_WARN_UNUSED_RESULT;
|
UCL_WARN_UNUSED_RESULT;
|
||||||
|
/**
|
||||||
|
* Check safe iterator object after performing some operations on it
|
||||||
|
* (such as ucl_object_iterate_safe()) to see if operation has encountered
|
||||||
|
* fatal exception while performing that operation (e.g. ENOMEM).
|
||||||
|
* @param iter opaque iterator
|
||||||
|
* @return true if exception has occured, false otherwise
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_object_iter_chk_excpn(ucl_object_iter_t *it);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset initialized iterator to a new object
|
* Reset initialized iterator to a new object
|
||||||
* @param obj new object to iterate
|
* @param obj new object to iterate
|
||||||
@ -830,7 +873,7 @@ UCL_EXTERN ucl_object_iter_t ucl_object_iterate_reset (ucl_object_iter_t it,
|
|||||||
const ucl_object_t *obj);
|
const ucl_object_t *obj);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next object from the `obj`. This fucntion iterates over arrays, objects
|
* Get the next object from the `obj`. This function iterates over arrays, objects
|
||||||
* and implicit arrays
|
* and implicit arrays
|
||||||
* @param iter safe iterator
|
* @param iter safe iterator
|
||||||
* @param expand_values expand explicit arrays and objects
|
* @param expand_values expand explicit arrays and objects
|
||||||
@ -848,7 +891,7 @@ enum ucl_iterate_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the next object from the `obj`. This fucntion iterates over arrays, objects
|
* Get the next object from the `obj`. This function iterates over arrays, objects
|
||||||
* and implicit arrays if needed
|
* and implicit arrays if needed
|
||||||
* @param iter safe iterator
|
* @param iter safe iterator
|
||||||
* @param
|
* @param
|
||||||
@ -912,7 +955,7 @@ struct ucl_parser;
|
|||||||
UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
|
UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the default priority for the parser applied to chunks that does not
|
* Sets the default priority for the parser applied to chunks that do not
|
||||||
* specify priority explicitly
|
* specify priority explicitly
|
||||||
* @param parser parser object
|
* @param parser parser object
|
||||||
* @param prio default priority (0 .. 16)
|
* @param prio default priority (0 .. 16)
|
||||||
@ -920,14 +963,23 @@ UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_parser_set_default_priority (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_set_default_priority (struct ucl_parser *parser,
|
||||||
unsigned prio);
|
unsigned prio);
|
||||||
|
/**
|
||||||
|
* Gets the default priority for the parser applied to chunks that do not
|
||||||
|
* specify priority explicitly
|
||||||
|
* @param parser parser object
|
||||||
|
* @return true default priority (0 .. 16), -1 for failure
|
||||||
|
*/
|
||||||
|
UCL_EXTERN int ucl_parser_get_default_priority (struct ucl_parser *parser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register new handler for a macro
|
* Register new handler for a macro
|
||||||
* @param parser parser object
|
* @param parser parser object
|
||||||
* @param macro macro name (without leading dot)
|
* @param macro macro name (without leading dot)
|
||||||
* @param handler handler (it is called immediately after macro is parsed)
|
* @param handler handler (it is called immediately after macro is parsed)
|
||||||
* @param ud opaque user data for a handler
|
* @param ud opaque user data for a handler
|
||||||
|
* @return true on success, false on failure (i.e. ENOMEM)
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_register_macro (struct ucl_parser *parser,
|
||||||
const char *macro,
|
const char *macro,
|
||||||
ucl_macro_handler handler, void* ud);
|
ucl_macro_handler handler, void* ud);
|
||||||
|
|
||||||
@ -937,8 +989,9 @@ UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser,
|
|||||||
* @param macro macro name (without leading dot)
|
* @param macro macro name (without leading dot)
|
||||||
* @param handler handler (it is called immediately after macro is parsed)
|
* @param handler handler (it is called immediately after macro is parsed)
|
||||||
* @param ud opaque user data for a handler
|
* @param ud opaque user data for a handler
|
||||||
|
* @return true on success, false on failure (i.e. ENOMEM)
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN void ucl_parser_register_context_macro (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_register_context_macro (struct ucl_parser *parser,
|
||||||
const char *macro,
|
const char *macro,
|
||||||
ucl_context_macro_handler handler,
|
ucl_context_macro_handler handler,
|
||||||
void* ud);
|
void* ud);
|
||||||
@ -996,6 +1049,16 @@ UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
|
|||||||
UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_add_chunk_priority (struct ucl_parser *parser,
|
||||||
const unsigned char *data, size_t len, unsigned priority);
|
const unsigned char *data, size_t len, unsigned priority);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Insert new chunk to a parser (must have previously processed data with an existing top object)
|
||||||
|
* @param parser parser structure
|
||||||
|
* @param data the pointer to the beginning of a chunk
|
||||||
|
* @param len the length of a chunk
|
||||||
|
* @return true if chunk has been added and false in case of error
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_parser_insert_chunk (struct ucl_parser *parser,
|
||||||
|
const unsigned char *data, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full version of ucl_add_chunk with priority and duplicate strategy
|
* Full version of ucl_add_chunk with priority and duplicate strategy
|
||||||
* @param parser parser structure
|
* @param parser parser structure
|
||||||
@ -1019,7 +1082,7 @@ UCL_EXTERN bool ucl_parser_add_chunk_full (struct ucl_parser *parser,
|
|||||||
* @return true if string has been added and false in case of error
|
* @return true if string has been added and false in case of error
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_parser_add_string (struct ucl_parser *parser,
|
UCL_EXTERN bool ucl_parser_add_string (struct ucl_parser *parser,
|
||||||
const char *data,size_t len);
|
const char *data, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load ucl object from a string
|
* Load ucl object from a string
|
||||||
@ -1124,6 +1187,29 @@ UCL_EXTERN bool ucl_set_include_path (struct ucl_parser *parser,
|
|||||||
*/
|
*/
|
||||||
UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
|
UCL_EXTERN ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current stack object as stack accessor function for use in macro
|
||||||
|
* functions (refcount is increased)
|
||||||
|
* @param parser parser object
|
||||||
|
* @param depth depth of stack to retrieve (top is 0)
|
||||||
|
* @return current stack object or NULL
|
||||||
|
*/
|
||||||
|
UCL_EXTERN ucl_object_t* ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Peek at the character at the current chunk position
|
||||||
|
* @param parser parser structure
|
||||||
|
* @return current chunk position character
|
||||||
|
*/
|
||||||
|
UCL_EXTERN unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Skip the character at the current chunk position
|
||||||
|
* @param parser parser structure
|
||||||
|
* @return success boolean
|
||||||
|
*/
|
||||||
|
UCL_EXTERN bool ucl_parser_chunk_skip (struct ucl_parser *parser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the error string if parsing has been failed
|
* Get the error string if parsing has been failed
|
||||||
* @param parser parser object
|
* @param parser parser object
|
||||||
@ -1185,7 +1271,7 @@ UCL_EXTERN const ucl_object_t * ucl_comments_find (const ucl_object_t *comments,
|
|||||||
* Move comment from `from` object to `to` object
|
* Move comment from `from` object to `to` object
|
||||||
* @param comments comments object
|
* @param comments comments object
|
||||||
* @param what source object
|
* @param what source object
|
||||||
* @param whith destination object
|
* @param with destination object
|
||||||
* @return `true` if `from` has comment and it has been moved to `to`
|
* @return `true` if `from` has comment and it has been moved to `to`
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_comments_move (ucl_object_t *comments,
|
UCL_EXTERN bool ucl_comments_move (ucl_object_t *comments,
|
||||||
@ -1221,6 +1307,76 @@ UCL_EXTERN bool ucl_parser_pubkey_add (struct ucl_parser *parser,
|
|||||||
UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename,
|
UCL_EXTERN bool ucl_parser_set_filevars (struct ucl_parser *parser, const char *filename,
|
||||||
bool need_expand);
|
bool need_expand);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns current file for the parser
|
||||||
|
* @param parser parser object
|
||||||
|
* @return current file or NULL if parsing memory
|
||||||
|
*/
|
||||||
|
UCL_EXTERN const char *ucl_parser_get_cur_file (struct ucl_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines special handler for certain types of data (identified by magic)
|
||||||
|
*/
|
||||||
|
typedef bool (*ucl_parser_special_handler_t) (struct ucl_parser *parser,
|
||||||
|
const unsigned char *source, size_t source_len,
|
||||||
|
unsigned char **destination, size_t *dest_len,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special handler flags
|
||||||
|
*/
|
||||||
|
enum ucl_special_handler_flags {
|
||||||
|
UCL_SPECIAL_HANDLER_DEFAULT = 0,
|
||||||
|
UCL_SPECIAL_HANDLER_PREPROCESS_ALL = (1u << 0),
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Special handler structure
|
||||||
|
*/
|
||||||
|
struct ucl_parser_special_handler {
|
||||||
|
const unsigned char *magic;
|
||||||
|
size_t magic_len;
|
||||||
|
enum ucl_special_handler_flags flags;
|
||||||
|
ucl_parser_special_handler_t handler;
|
||||||
|
void (*free_function) (unsigned char *data, size_t len, void *user_data);
|
||||||
|
void *user_data;
|
||||||
|
struct ucl_parser_special_handler *next; /* Used internally */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add special handler for a parser, handles special sequences identified by magic
|
||||||
|
* @param parser parser structure
|
||||||
|
* @param handler handler structure
|
||||||
|
*/
|
||||||
|
UCL_EXTERN void ucl_parser_add_special_handler (struct ucl_parser *parser,
|
||||||
|
struct ucl_parser_special_handler *handler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for include traces:
|
||||||
|
* @param parser parser object
|
||||||
|
* @param parent where include is done from
|
||||||
|
* @param args arguments to an include
|
||||||
|
* @param path path of the include
|
||||||
|
* @param pathlen length of the path
|
||||||
|
* @param user_data opaque userdata
|
||||||
|
*/
|
||||||
|
typedef void (ucl_include_trace_func_t) (struct ucl_parser *parser,
|
||||||
|
const ucl_object_t *parent,
|
||||||
|
const ucl_object_t *args,
|
||||||
|
const char *path,
|
||||||
|
size_t pathlen,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register trace function for an include handler
|
||||||
|
* @param parser parser object
|
||||||
|
* @param func function to trace includes
|
||||||
|
* @param user_data opaque data
|
||||||
|
*/
|
||||||
|
UCL_EXTERN void ucl_parser_set_include_tracer (struct ucl_parser *parser,
|
||||||
|
ucl_include_trace_func_t func,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1420,7 +1576,7 @@ enum ucl_schema_error_code {
|
|||||||
struct ucl_schema_error {
|
struct ucl_schema_error {
|
||||||
enum ucl_schema_error_code code; /**< error code */
|
enum ucl_schema_error_code code; /**< error code */
|
||||||
char msg[128]; /**< error message */
|
char msg[128]; /**< error message */
|
||||||
const ucl_object_t *obj; /**< object where error occured */
|
const ucl_object_t *obj; /**< object where error occurred */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1428,7 +1584,7 @@ struct ucl_schema_error {
|
|||||||
* @param schema schema object
|
* @param schema schema object
|
||||||
* @param obj object to validate
|
* @param obj object to validate
|
||||||
* @param err error pointer, if this parameter is not NULL and error has been
|
* @param err error pointer, if this parameter is not NULL and error has been
|
||||||
* occured, then `err` is filled with the exact error definition.
|
* occurred, then `err` is filled with the exact error definition.
|
||||||
* @return true if `obj` is valid using `schema`
|
* @return true if `obj` is valid using `schema`
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
|
UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
|
||||||
@ -1440,7 +1596,7 @@ UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
|
|||||||
* @param obj object to validate
|
* @param obj object to validate
|
||||||
* @param root root schema object
|
* @param root root schema object
|
||||||
* @param err error pointer, if this parameter is not NULL and error has been
|
* @param err error pointer, if this parameter is not NULL and error has been
|
||||||
* occured, then `err` is filled with the exact error definition.
|
* occurred, then `err` is filled with the exact error definition.
|
||||||
* @return true if `obj` is valid using `schema`
|
* @return true if `obj` is valid using `schema`
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
|
UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
|
||||||
@ -1456,7 +1612,7 @@ UCL_EXTERN bool ucl_object_validate_root (const ucl_object_t *schema,
|
|||||||
* @param root root schema object
|
* @param root root schema object
|
||||||
* @param ext_refs external references (might be modified during validation)
|
* @param ext_refs external references (might be modified during validation)
|
||||||
* @param err error pointer, if this parameter is not NULL and error has been
|
* @param err error pointer, if this parameter is not NULL and error has been
|
||||||
* occured, then `err` is filled with the exact error definition.
|
* occurred, then `err` is filled with the exact error definition.
|
||||||
* @return true if `obj` is valid using `schema`
|
* @return true if `obj` is valid using `schema`
|
||||||
*/
|
*/
|
||||||
UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema,
|
UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema,
|
||||||
@ -1491,4 +1647,7 @@ UCL_EXTERN bool ucl_object_validate_root_ext (const ucl_object_t *schema,
|
|||||||
#define ucl_obj_ref ucl_object_ref
|
#define ucl_obj_ref ucl_object_ref
|
||||||
#define ucl_obj_free ucl_object_free
|
#define ucl_obj_free ucl_object_free
|
||||||
|
|
||||||
|
#define UCL_PRIORITY_MIN 0
|
||||||
|
#define UCL_PRIORITY_MAX 15
|
||||||
|
|
||||||
#endif /* UCL_H_ */
|
#endif /* UCL_H_ */
|
||||||
|
78
klib/kvec.h
78
klib/kvec.h
@ -30,11 +30,13 @@
|
|||||||
int main() {
|
int main() {
|
||||||
kvec_t(int) array;
|
kvec_t(int) array;
|
||||||
kv_init(array);
|
kv_init(array);
|
||||||
kv_push(int, array, 10); // append
|
kv_push_safe(int, array, 10, e0); // append
|
||||||
kv_a(int, array, 20) = 5; // dynamic
|
kv_a(int, array, 20) = 5; // dynamic
|
||||||
kv_A(array, 20) = 4; // static
|
kv_A(array, 20) = 4; // static
|
||||||
kv_destroy(array);
|
kv_destroy(array);
|
||||||
return 0;
|
return 0;
|
||||||
|
e0:
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -60,8 +62,71 @@ int main() {
|
|||||||
#define kv_size(v) ((v).n)
|
#define kv_size(v) ((v).n)
|
||||||
#define kv_max(v) ((v).m)
|
#define kv_max(v) ((v).m)
|
||||||
|
|
||||||
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
#define kv_resize_safe(type, v, s, el) do { \
|
||||||
|
type *_tp = (type*)realloc((v).a, sizeof(type) * (s)); \
|
||||||
|
if (_tp == NULL) { \
|
||||||
|
goto el; \
|
||||||
|
} else { \
|
||||||
|
(v).a = _tp; \
|
||||||
|
(v).m = (s); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#define kv_grow_factor 1.5
|
#define kv_grow_factor 1.5
|
||||||
|
#define kv_grow_safe(type, v, el) do { \
|
||||||
|
size_t _ts = ((v).m > 1 ? (v).m * kv_grow_factor : 2); \
|
||||||
|
type *_tp = (type*)realloc((v).a, sizeof(type) * _ts); \
|
||||||
|
if (_tp == NULL) { \
|
||||||
|
goto el; \
|
||||||
|
} else { \
|
||||||
|
(v).a = _tp; \
|
||||||
|
(v).m = _ts; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_copy_safe(type, v1, v0, el) do { \
|
||||||
|
if ((v1).m < (v0).n) kv_resize_safe(type, v1, (v0).n, el); \
|
||||||
|
(v1).n = (v0).n; \
|
||||||
|
memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_push_safe(type, v, x, el) do { \
|
||||||
|
if ((v).n == (v).m) { \
|
||||||
|
kv_grow_safe(type, v, el); \
|
||||||
|
} \
|
||||||
|
(v).a[(v).n++] = (x); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_prepend_safe(type, v, x, el) do { \
|
||||||
|
if ((v).n == (v).m) { \
|
||||||
|
kv_grow_safe(type, v, el); \
|
||||||
|
} \
|
||||||
|
memmove((v).a + 1, (v).a, sizeof(type) * (v).n); \
|
||||||
|
(v).a[0] = (x); \
|
||||||
|
(v).n ++; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_concat_safe(type, v1, v0, el) do { \
|
||||||
|
if ((v1).m < (v0).n + (v1).n) \
|
||||||
|
kv_resize_safe(type, v1, (v0).n + (v1).n, el); \
|
||||||
|
memcpy((v1).a + (v1).n, (v0).a, sizeof(type) * (v0).n); \
|
||||||
|
(v1).n = (v0).n + (v1).n; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_del(type, v, i) do { \
|
||||||
|
if ((i) < (v).n) { \
|
||||||
|
memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
|
||||||
|
(v).n --; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Old (ENOMEM-unsafe) version of kv_xxx macros. Compat-only, not for use in
|
||||||
|
* the new library code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
||||||
|
|
||||||
#define kv_grow(type, v) ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \
|
#define kv_grow(type, v) ((v).m = ((v).m > 1 ? (v).m * kv_grow_factor : 2), \
|
||||||
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
||||||
|
|
||||||
@ -93,11 +158,4 @@ int main() {
|
|||||||
(v1).n = (v0).n + (v1).n; \
|
(v1).n = (v0).n + (v1).n; \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define kv_del(type, v, i) do { \
|
#endif /* AC_KVEC_H */
|
||||||
if ((i) < (v).n) { \
|
|
||||||
memmove((v).a + (i), (v).a + ((i) + 1), sizeof(type) * ((v).n - (i) - 1)); \
|
|
||||||
(v).n --; \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
450
lua/lua_ucl.c
450
lua/lua_ucl.c
@ -68,16 +68,27 @@ func = "huh";
|
|||||||
|
|
||||||
#define PARSER_META "ucl.parser.meta"
|
#define PARSER_META "ucl.parser.meta"
|
||||||
#define EMITTER_META "ucl.emitter.meta"
|
#define EMITTER_META "ucl.emitter.meta"
|
||||||
#define NULL_META "null.emitter.meta"
|
#define NULL_META "ucl.null.meta"
|
||||||
#define OBJECT_META "ucl.object.meta"
|
#define OBJECT_META "ucl.object.meta"
|
||||||
|
#define UCL_OBJECT_TYPE_META "ucl.type.object"
|
||||||
|
#define UCL_ARRAY_TYPE_META "ucl.type.array"
|
||||||
|
#define UCL_IMPL_ARRAY_TYPE_META "ucl.type.impl_array"
|
||||||
|
|
||||||
static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj);
|
static int ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags);
|
||||||
static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, bool allow_array);
|
static int ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj, int flags);
|
||||||
static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx);
|
static int ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags);
|
||||||
static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx);
|
static ucl_object_t* ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags);
|
||||||
|
static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags);
|
||||||
|
|
||||||
static void *ucl_null;
|
static void *ucl_null;
|
||||||
|
|
||||||
|
|
||||||
|
enum lua_ucl_push_flags {
|
||||||
|
LUA_UCL_DEFAULT_FLAGS = 0,
|
||||||
|
LUA_UCL_ALLOW_ARRAY = (1u << 0u),
|
||||||
|
LUA_UCL_CONVERT_NIL = (1u << 1u),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push a single element of an object to lua
|
* Push a single element of an object to lua
|
||||||
* @param L
|
* @param L
|
||||||
@ -86,10 +97,10 @@ static void *ucl_null;
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
ucl_object_lua_push_element (lua_State *L, const char *key,
|
ucl_object_lua_push_element (lua_State *L, const char *key,
|
||||||
const ucl_object_t *obj)
|
const ucl_object_t *obj, int flags)
|
||||||
{
|
{
|
||||||
lua_pushstring (L, key);
|
lua_pushstring (L, key);
|
||||||
ucl_object_push_lua (L, obj, true);
|
ucl_object_push_lua_common (L, obj, flags|LUA_UCL_ALLOW_ARRAY);
|
||||||
lua_settable (L, -3);
|
lua_settable (L, -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,29 +148,26 @@ lua_ucl_userdata_emitter (void *ud)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
|
ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
|
||||||
bool allow_array)
|
int flags)
|
||||||
{
|
{
|
||||||
const ucl_object_t *cur;
|
const ucl_object_t *cur;
|
||||||
ucl_object_iter_t it = NULL;
|
ucl_object_iter_t it = NULL;
|
||||||
int nelt = 0;
|
|
||||||
|
|
||||||
if (allow_array && obj->next != NULL) {
|
if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
|
||||||
/* Actually we need to push this as an array */
|
/* Actually we need to push this as an array */
|
||||||
return ucl_object_lua_push_array (L, obj);
|
return ucl_object_lua_push_array (L, obj, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Optimize allocation by preallocation of table */
|
lua_createtable (L, 0, obj->len);
|
||||||
while (ucl_object_iterate (obj, &it, true) != NULL) {
|
|
||||||
nelt ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
lua_createtable (L, 0, nelt);
|
|
||||||
it = NULL;
|
it = NULL;
|
||||||
|
|
||||||
while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
|
while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) {
|
||||||
ucl_object_lua_push_element (L, ucl_object_key (cur), cur);
|
ucl_object_lua_push_element (L, ucl_object_key (cur), cur, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaL_getmetatable (L, UCL_OBJECT_TYPE_META);
|
||||||
|
lua_setmetatable (L, -2);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,7 +178,7 @@ ucl_object_lua_push_object (lua_State *L, const ucl_object_t *obj,
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj, int flags)
|
||||||
{
|
{
|
||||||
const ucl_object_t *cur;
|
const ucl_object_t *cur;
|
||||||
ucl_object_iter_t it;
|
ucl_object_iter_t it;
|
||||||
@ -182,11 +190,14 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
|||||||
lua_createtable (L, nelt, 0);
|
lua_createtable (L, nelt, 0);
|
||||||
|
|
||||||
while ((cur = ucl_object_iterate_safe (it, true))) {
|
while ((cur = ucl_object_iterate_safe (it, true))) {
|
||||||
ucl_object_push_lua (L, cur, false);
|
ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
|
||||||
lua_rawseti (L, -2, i);
|
lua_rawseti (L, -2, i);
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaL_getmetatable (L, UCL_ARRAY_TYPE_META);
|
||||||
|
lua_setmetatable (L, -2);
|
||||||
|
|
||||||
ucl_object_iterate_free (it);
|
ucl_object_iterate_free (it);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -198,10 +209,13 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
|||||||
lua_createtable (L, nelt, 0);
|
lua_createtable (L, nelt, 0);
|
||||||
|
|
||||||
LL_FOREACH (obj, cur) {
|
LL_FOREACH (obj, cur) {
|
||||||
ucl_object_push_lua (L, cur, false);
|
ucl_object_push_lua (L, cur, (flags & ~LUA_UCL_ALLOW_ARRAY));
|
||||||
lua_rawseti (L, -2, i);
|
lua_rawseti (L, -2, i);
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
luaL_getmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
|
||||||
|
lua_setmetatable (L, -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -212,13 +226,13 @@ ucl_object_lua_push_array (lua_State *L, const ucl_object_t *obj)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
||||||
bool allow_array)
|
int flags)
|
||||||
{
|
{
|
||||||
struct ucl_lua_funcdata *fd;
|
struct ucl_lua_funcdata *fd;
|
||||||
|
|
||||||
if (allow_array && obj->next != NULL) {
|
if ((flags & LUA_UCL_ALLOW_ARRAY) && obj->next != NULL) {
|
||||||
/* Actually we need to push this as an array */
|
/* Actually we need to push this as an array */
|
||||||
return ucl_object_lua_push_array (L, obj);
|
return ucl_object_lua_push_array (L, obj, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (obj->type) {
|
switch (obj->type) {
|
||||||
@ -240,7 +254,12 @@ ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
|||||||
lua_pushnumber (L, ucl_obj_todouble (obj));
|
lua_pushnumber (L, ucl_obj_todouble (obj));
|
||||||
break;
|
break;
|
||||||
case UCL_NULL:
|
case UCL_NULL:
|
||||||
lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
|
if (flags & LUA_UCL_CONVERT_NIL) {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_getfield (L, LUA_REGISTRYINDEX, "ucl.null");
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case UCL_USERDATA:
|
case UCL_USERDATA:
|
||||||
fd = (struct ucl_lua_funcdata *)obj->value.ud;
|
fd = (struct ucl_lua_funcdata *)obj->value.ud;
|
||||||
@ -254,6 +273,19 @@ ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucl_object_push_lua_common (lua_State *L, const ucl_object_t *obj, int flags)
|
||||||
|
{
|
||||||
|
switch (obj->type) {
|
||||||
|
case UCL_OBJECT:
|
||||||
|
return ucl_object_lua_push_object (L, obj, flags);
|
||||||
|
case UCL_ARRAY:
|
||||||
|
return ucl_object_lua_push_array (L, obj, flags);
|
||||||
|
default:
|
||||||
|
return ucl_object_lua_push_scalar (L, obj, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @function ucl_object_push_lua(L, obj, allow_array)
|
* @function ucl_object_push_lua(L, obj, allow_array)
|
||||||
* This is a `C` function to push `UCL` object as lua variable. This function
|
* This is a `C` function to push `UCL` object as lua variable. This function
|
||||||
@ -272,14 +304,16 @@ ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,
|
|||||||
int
|
int
|
||||||
ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
|
ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
|
||||||
{
|
{
|
||||||
switch (obj->type) {
|
return ucl_object_push_lua_common (L, obj,
|
||||||
case UCL_OBJECT:
|
allow_array ? LUA_UCL_ALLOW_ARRAY : LUA_UCL_DEFAULT_FLAGS);
|
||||||
return ucl_object_lua_push_object (L, obj, allow_array);
|
}
|
||||||
case UCL_ARRAY:
|
|
||||||
return ucl_object_lua_push_array (L, obj);
|
int
|
||||||
default:
|
ucl_object_push_lua_filter_nil (lua_State *L, const ucl_object_t *obj, bool allow_array)
|
||||||
return ucl_object_lua_push_scalar (L, obj, allow_array);
|
{
|
||||||
}
|
return ucl_object_push_lua_common (L, obj,
|
||||||
|
allow_array ? (LUA_UCL_ALLOW_ARRAY|LUA_UCL_CONVERT_NIL) :
|
||||||
|
(LUA_UCL_DEFAULT_FLAGS|LUA_UCL_CONVERT_NIL));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -289,55 +323,107 @@ ucl_object_push_lua (lua_State *L, const ucl_object_t *obj, bool allow_array)
|
|||||||
* @param idx
|
* @param idx
|
||||||
*/
|
*/
|
||||||
static ucl_object_t *
|
static ucl_object_t *
|
||||||
ucl_object_lua_fromtable (lua_State *L, int idx)
|
ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)
|
||||||
{
|
{
|
||||||
ucl_object_t *obj, *top = NULL;
|
ucl_object_t *obj, *top = NULL, *cur;
|
||||||
size_t keylen;
|
size_t keylen;
|
||||||
const char *k;
|
const char *k;
|
||||||
bool is_array = true;
|
bool is_array = true, is_implicit = false, found_mt = false;
|
||||||
int max = INT_MIN;
|
size_t max = 0, nelts = 0;
|
||||||
|
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
/* For negative indicies we want to invert them */
|
/* For negative indicies we want to invert them */
|
||||||
idx = lua_gettop (L) + idx + 1;
|
idx = lua_gettop (L) + idx + 1;
|
||||||
}
|
}
|
||||||
/* Check for array */
|
|
||||||
lua_pushnil (L);
|
/* First, we check from metatable */
|
||||||
while (lua_next (L, idx) != 0) {
|
if (luaL_getmetafield (L, idx, "class") != 0) {
|
||||||
if (lua_type (L, -2) == LUA_TNUMBER) {
|
|
||||||
double num = lua_tonumber (L, -2);
|
if (lua_type (L, -1) == LUA_TSTRING) {
|
||||||
if (num == (int)num) {
|
const char *classname = lua_tostring (L, -1);
|
||||||
if (num > max) {
|
|
||||||
max = num;
|
if (strcmp (classname, UCL_OBJECT_TYPE_META) == 0) {
|
||||||
|
is_array = false;
|
||||||
|
found_mt = true;
|
||||||
|
} else if (strcmp (classname, UCL_ARRAY_TYPE_META) == 0) {
|
||||||
|
is_array = true;
|
||||||
|
found_mt = true;
|
||||||
|
#if LUA_VERSION_NUM >= 502
|
||||||
|
max = lua_rawlen (L, idx);
|
||||||
|
#else
|
||||||
|
max = lua_objlen (L, idx);
|
||||||
|
#endif
|
||||||
|
nelts = max;
|
||||||
|
} else if (strcmp (classname, UCL_IMPL_ARRAY_TYPE_META) == 0) {
|
||||||
|
is_array = true;
|
||||||
|
is_implicit = true;
|
||||||
|
found_mt = true;
|
||||||
|
#if LUA_VERSION_NUM >= 502
|
||||||
|
max = lua_rawlen (L, idx);
|
||||||
|
#else
|
||||||
|
max = lua_objlen (L, idx);
|
||||||
|
#endif
|
||||||
|
nelts = max;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_mt) {
|
||||||
|
/* Check for array (it is all inefficient) */
|
||||||
|
lua_pushnil (L);
|
||||||
|
|
||||||
|
while (lua_next (L, idx) != 0) {
|
||||||
|
lua_pushvalue (L, -2);
|
||||||
|
|
||||||
|
if (lua_type (L, -1) == LUA_TNUMBER) {
|
||||||
|
double num = lua_tonumber (L, -1);
|
||||||
|
if (num == (int) num) {
|
||||||
|
if (num > max) {
|
||||||
|
max = num;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* Keys are not integer */
|
||||||
|
is_array = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Keys are not integer */
|
/* Keys are not numeric */
|
||||||
lua_pop (L, 2);
|
|
||||||
is_array = false;
|
is_array = false;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Keys are not numeric */
|
|
||||||
lua_pop (L, 2);
|
lua_pop (L, 2);
|
||||||
is_array = false;
|
nelts ++;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
lua_pop (L, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Table iterate */
|
/* Table iterate */
|
||||||
if (is_array) {
|
if (is_array) {
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
top = ucl_object_typed_new (UCL_ARRAY);
|
if (!is_implicit) {
|
||||||
|
top = ucl_object_typed_new (UCL_ARRAY);
|
||||||
|
ucl_object_reserve (top, nelts);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
top = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 1; i <= max; i ++) {
|
for (i = 1; i <= max; i ++) {
|
||||||
lua_pushinteger (L, i);
|
lua_pushinteger (L, i);
|
||||||
lua_gettable (L, idx);
|
lua_gettable (L, idx);
|
||||||
obj = ucl_object_lua_fromelt (L, lua_gettop (L));
|
|
||||||
|
obj = ucl_object_lua_fromelt (L, lua_gettop (L), flags);
|
||||||
|
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
ucl_array_append (top, obj);
|
if (is_implicit) {
|
||||||
|
DL_APPEND (top, obj);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_array_append (top, obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lua_pop (L, 1);
|
lua_pop (L, 1);
|
||||||
}
|
}
|
||||||
@ -345,15 +431,25 @@ ucl_object_lua_fromtable (lua_State *L, int idx)
|
|||||||
else {
|
else {
|
||||||
lua_pushnil (L);
|
lua_pushnil (L);
|
||||||
top = ucl_object_typed_new (UCL_OBJECT);
|
top = ucl_object_typed_new (UCL_OBJECT);
|
||||||
|
ucl_object_reserve (top, nelts);
|
||||||
|
|
||||||
while (lua_next (L, idx) != 0) {
|
while (lua_next (L, idx) != 0) {
|
||||||
/* copy key to avoid modifications */
|
/* copy key to avoid modifications */
|
||||||
k = lua_tolstring (L, -2, &keylen);
|
lua_pushvalue (L, -2);
|
||||||
obj = ucl_object_lua_fromelt (L, lua_gettop (L));
|
k = lua_tolstring (L, -1, &keylen);
|
||||||
|
obj = ucl_object_lua_fromelt (L, lua_gettop (L) - 1, flags);
|
||||||
|
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
ucl_object_insert_key (top, obj, k, keylen, true);
|
ucl_object_insert_key (top, obj, k, keylen, true);
|
||||||
|
|
||||||
|
DL_FOREACH (obj, cur) {
|
||||||
|
if (cur->keylen == 0) {
|
||||||
|
cur->keylen = obj->keylen;
|
||||||
|
cur->key = obj->key;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lua_pop (L, 1);
|
lua_pop (L, 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,18 +463,27 @@ ucl_object_lua_fromtable (lua_State *L, int idx)
|
|||||||
* @param idx
|
* @param idx
|
||||||
*/
|
*/
|
||||||
static ucl_object_t *
|
static ucl_object_t *
|
||||||
ucl_object_lua_fromelt (lua_State *L, int idx)
|
ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)
|
||||||
{
|
{
|
||||||
int type;
|
int type;
|
||||||
double num;
|
double num;
|
||||||
ucl_object_t *obj = NULL;
|
ucl_object_t *obj = NULL;
|
||||||
struct ucl_lua_funcdata *fd;
|
struct ucl_lua_funcdata *fd;
|
||||||
|
const char *str;
|
||||||
|
size_t sz;
|
||||||
|
|
||||||
type = lua_type (L, idx);
|
type = lua_type (L, idx);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
obj = ucl_object_fromstring_common (lua_tostring (L, idx), 0, 0);
|
str = lua_tolstring (L, idx, &sz);
|
||||||
|
|
||||||
|
if (str) {
|
||||||
|
obj = ucl_object_fromstring_common (str, sz, flags);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
obj = ucl_object_typed_new (UCL_NULL);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
num = lua_tonumber (L, idx);
|
num = lua_tonumber (L, idx);
|
||||||
@ -406,13 +511,13 @@ ucl_object_lua_fromelt (lua_State *L, int idx)
|
|||||||
lua_insert (L, 1); /* func, gen, obj */
|
lua_insert (L, 1); /* func, gen, obj */
|
||||||
lua_insert (L, 2); /* func, obj, gen */
|
lua_insert (L, 2); /* func, obj, gen */
|
||||||
lua_call(L, 2, 1);
|
lua_call(L, 2, 1);
|
||||||
obj = ucl_object_lua_fromelt (L, 1);
|
obj = ucl_object_lua_fromelt (L, 1, flags);
|
||||||
}
|
}
|
||||||
lua_pop (L, 2);
|
lua_pop (L, 2);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (type == LUA_TTABLE) {
|
if (type == LUA_TTABLE) {
|
||||||
obj = ucl_object_lua_fromtable (L, idx);
|
obj = ucl_object_lua_fromtable (L, idx, flags);
|
||||||
}
|
}
|
||||||
else if (type == LUA_TFUNCTION) {
|
else if (type == LUA_TFUNCTION) {
|
||||||
fd = malloc (sizeof (*fd));
|
fd = malloc (sizeof (*fd));
|
||||||
@ -451,10 +556,38 @@ ucl_object_lua_import (lua_State *L, int idx)
|
|||||||
t = lua_type (L, idx);
|
t = lua_type (L, idx);
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case LUA_TTABLE:
|
case LUA_TTABLE:
|
||||||
obj = ucl_object_lua_fromtable (L, idx);
|
obj = ucl_object_lua_fromtable (L, idx, 0);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
obj = ucl_object_lua_fromelt (L, idx);
|
obj = ucl_object_lua_fromelt (L, idx, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function ucl_object_lua_import_escape(L, idx)
|
||||||
|
* Extracts ucl object from lua variable at `idx` position escaping JSON strings
|
||||||
|
* @see ucl_object_push_lua for conversion definitions
|
||||||
|
* @param {lua_state} L lua state machine pointer
|
||||||
|
* @param {int} idx index where the source variable is placed
|
||||||
|
* @return {ucl_object_t} new ucl object extracted from lua variable. Reference count of this object is 1,
|
||||||
|
* this object thus needs to be unref'ed after usage.
|
||||||
|
*/
|
||||||
|
ucl_object_t *
|
||||||
|
ucl_object_lua_import_escape (lua_State *L, int idx)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
int t;
|
||||||
|
|
||||||
|
t = lua_type (L, idx);
|
||||||
|
switch (t) {
|
||||||
|
case LUA_TTABLE:
|
||||||
|
obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -492,6 +625,7 @@ lua_ucl_parser_init (lua_State *L)
|
|||||||
parser = ucl_parser_new (flags);
|
parser = ucl_parser_new (flags);
|
||||||
if (parser == NULL) {
|
if (parser == NULL) {
|
||||||
lua_pushnil (L);
|
lua_pushnil (L);
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pparser = lua_newuserdata (L, sizeof (parser));
|
pparser = lua_newuserdata (L, sizeof (parser));
|
||||||
@ -589,6 +723,76 @@ lua_ucl_parser_parse_file (lua_State *L)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:register_variable(name, value)
|
||||||
|
* Register parser variable
|
||||||
|
* @param {string} name name of variable
|
||||||
|
* @param {string} value value of variable
|
||||||
|
* @return {bool} success
|
||||||
|
@example
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res = parser:register_variable('CONFDIR', '/etc/foo')
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_register_variable (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
const char *name, *value;
|
||||||
|
int ret = 2;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
name = luaL_checkstring (L, 2);
|
||||||
|
value = luaL_checkstring (L, 3);
|
||||||
|
|
||||||
|
if (parser != NULL && name != NULL && value != NULL) {
|
||||||
|
ucl_parser_register_variable (parser, name, value);
|
||||||
|
lua_pushboolean (L, true);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return luaL_error (L, "invalid arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:register_variables(vars)
|
||||||
|
* Register parser variables
|
||||||
|
* @param {table} vars names/values of variables
|
||||||
|
* @return {bool} success
|
||||||
|
@example
|
||||||
|
local parser = ucl.parser()
|
||||||
|
local res = parser:register_variables({CONFDIR = '/etc/foo', VARDIR = '/var'})
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_register_variables (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
const char *name, *value;
|
||||||
|
int ret = 2;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
|
||||||
|
if (parser != NULL && lua_type (L, 2) == LUA_TTABLE) {
|
||||||
|
for (lua_pushnil (L); lua_next (L, 2); lua_pop (L, 1)) {
|
||||||
|
lua_pushvalue (L, -2);
|
||||||
|
name = luaL_checkstring (L, -1);
|
||||||
|
value = luaL_checkstring (L, -2);
|
||||||
|
ucl_parser_register_variable (parser, name, value);
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_pushboolean (L, true);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return luaL_error (L, "invalid arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @method parser:parse_string(input)
|
* @method parser:parse_string(input)
|
||||||
* Parse UCL object from file.
|
* Parse UCL object from file.
|
||||||
@ -630,6 +834,52 @@ lua_ucl_parser_parse_string (lua_State *L)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct _rspamd_lua_text {
|
||||||
|
const char *start;
|
||||||
|
unsigned int len;
|
||||||
|
unsigned int flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
/***
|
||||||
|
* @method parser:parse_text(input)
|
||||||
|
* Parse UCL object from text object (Rspamd specific).
|
||||||
|
* @param {rspamd_text} input text to parse
|
||||||
|
* @return {bool[, string]} if res is `true` then file has been parsed successfully, otherwise an error string is also returned
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
lua_ucl_parser_parse_text (lua_State *L)
|
||||||
|
{
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
struct _rspamd_lua_text *t;
|
||||||
|
enum ucl_parse_type type = UCL_PARSE_UCL;
|
||||||
|
int ret = 2;
|
||||||
|
|
||||||
|
parser = lua_ucl_parser_get (L, 1);
|
||||||
|
t = lua_touserdata (L, 2);
|
||||||
|
|
||||||
|
if (lua_type (L, 3) == LUA_TSTRING) {
|
||||||
|
type = lua_ucl_str_to_parse_type (lua_tostring (L, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser != NULL && t != NULL) {
|
||||||
|
if (ucl_parser_add_chunk_full (parser, (const unsigned char *)t->start,
|
||||||
|
t->len, 0, UCL_DUPLICATE_APPEND, type)) {
|
||||||
|
lua_pushboolean (L, true);
|
||||||
|
ret = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, ucl_parser_get_error (parser));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushboolean (L, false);
|
||||||
|
lua_pushstring (L, "invalid arguments");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* @method parser:get_object()
|
* @method parser:get_object()
|
||||||
* Get top object from parser and export it to lua representation.
|
* Get top object from parser and export it to lua representation.
|
||||||
@ -977,6 +1227,15 @@ lua_ucl_parser_mt (lua_State *L)
|
|||||||
lua_pushcfunction (L, lua_ucl_parser_parse_string);
|
lua_pushcfunction (L, lua_ucl_parser_parse_string);
|
||||||
lua_setfield (L, -2, "parse_string");
|
lua_setfield (L, -2, "parse_string");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_parse_text);
|
||||||
|
lua_setfield (L, -2, "parse_text");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_register_variable);
|
||||||
|
lua_setfield (L, -2, "register_variable");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_parser_register_variables);
|
||||||
|
lua_setfield (L, -2, "register_variables");
|
||||||
|
|
||||||
lua_pushcfunction (L, lua_ucl_parser_get_object);
|
lua_pushcfunction (L, lua_ucl_parser_get_object);
|
||||||
lua_setfield (L, -2, "get_object");
|
lua_setfield (L, -2, "get_object");
|
||||||
|
|
||||||
@ -1021,6 +1280,49 @@ lua_ucl_object_mt (lua_State *L)
|
|||||||
lua_pop (L, 1);
|
lua_pop (L, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
lua_ucl_types_mt (lua_State *L)
|
||||||
|
{
|
||||||
|
luaL_newmetatable (L, UCL_OBJECT_TYPE_META);
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "__tostring");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "tostring");
|
||||||
|
|
||||||
|
lua_pushstring (L, UCL_OBJECT_TYPE_META);
|
||||||
|
lua_setfield (L, -2, "class");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
|
||||||
|
luaL_newmetatable (L, UCL_ARRAY_TYPE_META);
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "__tostring");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "tostring");
|
||||||
|
|
||||||
|
lua_pushstring (L, UCL_ARRAY_TYPE_META);
|
||||||
|
lua_setfield (L, -2, "class");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
|
||||||
|
luaL_newmetatable (L, UCL_IMPL_ARRAY_TYPE_META);
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "__tostring");
|
||||||
|
|
||||||
|
lua_pushcfunction (L, lua_ucl_object_tostring);
|
||||||
|
lua_setfield (L, -2, "tostring");
|
||||||
|
|
||||||
|
lua_pushstring (L, UCL_IMPL_ARRAY_TYPE_META);
|
||||||
|
lua_setfield (L, -2, "class");
|
||||||
|
|
||||||
|
lua_pop (L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lua_ucl_to_json (lua_State *L)
|
lua_ucl_to_json (lua_State *L)
|
||||||
{
|
{
|
||||||
@ -1073,7 +1375,7 @@ lua_ucl_to_config (lua_State *L)
|
|||||||
* - `yaml` - embedded yaml
|
* - `yaml` - embedded yaml
|
||||||
*
|
*
|
||||||
* If `var` contains function, they are called during output formatting and if
|
* If `var` contains function, they are called during output formatting and if
|
||||||
* they return string value, then this value is used for ouptut.
|
* they return string value, then this value is used for output.
|
||||||
* @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
|
* @param {variant} var any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output)
|
||||||
* @param {string} format any available format
|
* @param {string} format any available format
|
||||||
* @return {string} string representation of `var` in the specific `format`.
|
* @return {string} string representation of `var` in the specific `format`.
|
||||||
@ -1101,6 +1403,7 @@ lua_ucl_to_format (lua_State *L)
|
|||||||
{
|
{
|
||||||
ucl_object_t *obj;
|
ucl_object_t *obj;
|
||||||
int format = UCL_EMIT_JSON;
|
int format = UCL_EMIT_JSON;
|
||||||
|
bool sort = false;
|
||||||
|
|
||||||
if (lua_gettop (L) > 1) {
|
if (lua_gettop (L) > 1) {
|
||||||
if (lua_type (L, 2) == LUA_TNUMBER) {
|
if (lua_type (L, 2) == LUA_TNUMBER) {
|
||||||
@ -1130,10 +1433,22 @@ lua_ucl_to_format (lua_State *L)
|
|||||||
format = UCL_EMIT_MSGPACK;
|
format = UCL_EMIT_MSGPACK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (lua_isboolean (L, 3)) {
|
||||||
|
sort = lua_toboolean (L, 3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = ucl_object_lua_import (L, 1);
|
obj = ucl_object_lua_import (L, 1);
|
||||||
|
|
||||||
if (obj != NULL) {
|
if (obj != NULL) {
|
||||||
|
|
||||||
|
if (sort) {
|
||||||
|
if (ucl_object_type (obj) == UCL_OBJECT) {
|
||||||
|
ucl_object_sort_keys (obj, UCL_SORT_KEYS_RECURSIVE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lua_ucl_to_string (L, obj, format);
|
lua_ucl_to_string (L, obj, format);
|
||||||
ucl_object_unref (obj);
|
ucl_object_unref (obj);
|
||||||
}
|
}
|
||||||
@ -1168,6 +1483,7 @@ luaopen_ucl (lua_State *L)
|
|||||||
lua_ucl_parser_mt (L);
|
lua_ucl_parser_mt (L);
|
||||||
lua_ucl_null_mt (L);
|
lua_ucl_null_mt (L);
|
||||||
lua_ucl_object_mt (L);
|
lua_ucl_object_mt (L);
|
||||||
|
lua_ucl_types_mt (L);
|
||||||
|
|
||||||
/* Create the refs weak table: */
|
/* Create the refs weak table: */
|
||||||
lua_createtable (L, 0, 2);
|
lua_createtable (L, 0, 2);
|
||||||
|
5
python/MANIFEST.in
Normal file
5
python/MANIFEST.in
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
include COPYING
|
||||||
|
recursive-include include *.h
|
||||||
|
recursive-include src *.h
|
||||||
|
recursive-include klib *.h
|
||||||
|
recursive-include uthash *.h
|
@ -1,11 +1,20 @@
|
|||||||
try:
|
try:
|
||||||
from setuptools import setup, Extension
|
from setuptools import setup, Extension
|
||||||
|
# setuptools doesn't support template param for MANIFEST.in
|
||||||
|
from setuptools.command.egg_info import manifest_maker
|
||||||
|
manifest_maker.template = 'python/MANIFEST.in'
|
||||||
except ImportError:
|
except ImportError:
|
||||||
from distutils.core import setup, Extension
|
from distutils.core import setup, Extension
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
LIB_ROOT = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir))
|
||||||
|
if os.getcwd() != LIB_ROOT:
|
||||||
|
os.chdir(LIB_ROOT)
|
||||||
|
if LIB_ROOT not in sys.path:
|
||||||
|
sys.path.append(LIB_ROOT)
|
||||||
|
|
||||||
tests_require = []
|
tests_require = []
|
||||||
|
|
||||||
if sys.version < '2.7':
|
if sys.version < '2.7':
|
||||||
@ -13,16 +22,35 @@
|
|||||||
|
|
||||||
uclmodule = Extension(
|
uclmodule = Extension(
|
||||||
'ucl',
|
'ucl',
|
||||||
libraries = ['ucl'],
|
libraries=['ucl', 'curl'],
|
||||||
sources = ['src/uclmodule.c'],
|
sources=['python/src/uclmodule.c'],
|
||||||
language = 'c'
|
include_dirs=['include'],
|
||||||
|
language='c',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ucl_lib = {
|
||||||
|
'sources': ['src/' + fn for fn in os.listdir('src') if fn.endswith('.c')],
|
||||||
|
'include_dirs': ['include', 'src', 'uthash', 'klib'],
|
||||||
|
'macros': [('CURL_FOUND', '1')],
|
||||||
|
}
|
||||||
|
|
||||||
|
# sdist setup() will pull in the *.c files automatically, but not headers
|
||||||
|
# MANIFEST.in will include the headers for sdist only
|
||||||
|
template = 'python/MANIFEST.in'
|
||||||
|
|
||||||
|
# distutils assume setup.py is in the root of the project
|
||||||
|
# we need to include C source from the parent so trick it
|
||||||
|
in_ucl_root = 'setup.py' in os.listdir('python')
|
||||||
|
if in_ucl_root:
|
||||||
|
os.link('python/setup.py', 'setup.py')
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name = 'ucl',
|
name = 'ucl',
|
||||||
version = '0.8',
|
version = '0.8.1',
|
||||||
description = 'ucl parser and emmitter',
|
description = 'ucl parser and emitter',
|
||||||
ext_modules = [uclmodule],
|
ext_modules = [uclmodule],
|
||||||
|
template=template, # no longer supported with setuptools but doesn't hurt
|
||||||
|
libraries = [('ucl', ucl_lib)],
|
||||||
test_suite = 'tests',
|
test_suite = 'tests',
|
||||||
tests_require = tests_require,
|
tests_require = tests_require,
|
||||||
author = "Eitan Adler, Denis Volpato Martins",
|
author = "Eitan Adler, Denis Volpato Martins",
|
||||||
@ -41,3 +69,7 @@
|
|||||||
"Topic :: Software Development :: Libraries",
|
"Topic :: Software Development :: Libraries",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# clean up the trick after the build
|
||||||
|
if in_ucl_root:
|
||||||
|
os.unlink("setup.py")
|
||||||
|
@ -80,7 +80,8 @@ static PyObject *
|
|||||||
_internal_load_ucl (char *uclstr)
|
_internal_load_ucl (char *uclstr)
|
||||||
{
|
{
|
||||||
PyObject *ret;
|
PyObject *ret;
|
||||||
struct ucl_parser *parser = ucl_parser_new (UCL_PARSER_NO_TIME);
|
struct ucl_parser *parser =
|
||||||
|
ucl_parser_new (UCL_PARSER_NO_TIME|UCL_PARSER_NO_IMPLICIT_ARRAYS);
|
||||||
bool r = ucl_parser_add_string(parser, uclstr, 0);
|
bool r = ucl_parser_add_string(parser, uclstr, 0);
|
||||||
|
|
||||||
if (r) {
|
if (r) {
|
||||||
|
59
python/tests/test_example.py
Normal file
59
python/tests/test_example.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
from .compat import unittest
|
||||||
|
import json
|
||||||
|
import ucl
|
||||||
|
|
||||||
|
_ucl_inp = '''
|
||||||
|
param = value;
|
||||||
|
section {
|
||||||
|
param = value;
|
||||||
|
param1 = value1;
|
||||||
|
flag = true;
|
||||||
|
number = 10k;
|
||||||
|
time = 0.2s;
|
||||||
|
string = "something";
|
||||||
|
subsection {
|
||||||
|
host = {
|
||||||
|
host = "hostname";
|
||||||
|
port = 900;
|
||||||
|
}
|
||||||
|
host = {
|
||||||
|
host = "hostname";
|
||||||
|
port = 901;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
'''
|
||||||
|
|
||||||
|
_json_res = {
|
||||||
|
'param': 'value',
|
||||||
|
'section': {
|
||||||
|
'param': 'value',
|
||||||
|
'param1': 'value1',
|
||||||
|
'flag': True,
|
||||||
|
'number': 10000,
|
||||||
|
'time': '0.2s',
|
||||||
|
'string': 'something',
|
||||||
|
'subsection': {
|
||||||
|
'host': [
|
||||||
|
{
|
||||||
|
'host': 'hostname',
|
||||||
|
'port': 900,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'host': 'hostname',
|
||||||
|
'port': 901,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestExample(unittest.TestCase):
|
||||||
|
def test_example(self):
|
||||||
|
# load in sample UCL
|
||||||
|
u = ucl.load(_ucl_inp)
|
||||||
|
|
||||||
|
# Output and read back the JSON
|
||||||
|
uj = json.loads(json.dumps(u))
|
||||||
|
|
||||||
|
self.assertEqual(uj, _json_res)
|
@ -71,7 +71,22 @@ def test_comment_ignored(self):
|
|||||||
self.assertEqual(ucl.load("{/*1*/}"), {})
|
self.assertEqual(ucl.load("{/*1*/}"), {})
|
||||||
|
|
||||||
def test_1_in(self):
|
def test_1_in(self):
|
||||||
valid = { 'key1': 'value' }
|
valid = {
|
||||||
|
'key1': [
|
||||||
|
'value',
|
||||||
|
'value2',
|
||||||
|
'value;',
|
||||||
|
1.0,
|
||||||
|
-0xdeadbeef,
|
||||||
|
'0xdeadbeef.1',
|
||||||
|
'0xreadbeef',
|
||||||
|
-1e-10,
|
||||||
|
1,
|
||||||
|
True,
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
]
|
||||||
|
}
|
||||||
with open("../tests/basic/1.in", "r") as in1:
|
with open("../tests/basic/1.in", "r") as in1:
|
||||||
self.assertEqual(ucl.load(in1.read()), valid)
|
self.assertEqual(ucl.load(in1.read()), valid)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
Random and Pseudorandom Number Generators for Cryptographic
|
Random and Pseudorandom Number Generators for Cryptographic
|
||||||
Applications (version 2.2.1) with 1000 bitstreams each containing
|
Applications (version 2.2.1) with 1000 bitstreams each containing
|
||||||
1M bits. MUM hashing is also faster Spooky64 and City64 on small
|
1M bits. MUM hashing is also faster Spooky64 and City64 on small
|
||||||
strings (at least upto 512-bit) on Haswell and Power7. The MUM bulk
|
strings (at least up to 512-bit) on Haswell and Power7. The MUM bulk
|
||||||
speed (speed on very long data) is bigger than Spooky and City on
|
speed (speed on very long data) is bigger than Spooky and City on
|
||||||
Power7. On Haswell the bulk speed is bigger than Spooky one and
|
Power7. On Haswell the bulk speed is bigger than Spooky one and
|
||||||
close to City speed. */
|
close to City speed. */
|
||||||
@ -172,7 +172,7 @@ _mum_le (uint64_t v) {
|
|||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
return _mum_bswap64 (v);
|
return _mum_bswap64 (v);
|
||||||
#else
|
#else
|
||||||
#error "Unknown endianess"
|
#error "Unknown endianness"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ _mum_le32 (uint32_t v) {
|
|||||||
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
return _mum_bswap32 (v);
|
return _mum_bswap32 (v);
|
||||||
#else
|
#else
|
||||||
#error "Unknown endianess"
|
#error "Unknown endianness"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +396,7 @@ mum_hash64 (uint64_t key, uint64_t seed) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Hash data KEY of length LEN and SEED. The hash depends on the
|
/* Hash data KEY of length LEN and SEED. The hash depends on the
|
||||||
target endianess and the unroll factor. */
|
target endianness and the unroll factor. */
|
||||||
static inline uint64_t
|
static inline uint64_t
|
||||||
mum_hash (const void *key, size_t len, uint64_t seed) {
|
mum_hash (const void *key, size_t len, uint64_t seed) {
|
||||||
#if defined(__x86_64__) && defined(_MUM_FRESH_GCC)
|
#if defined(__x86_64__) && defined(_MUM_FRESH_GCC)
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "ucl_internal.h"
|
#include "ucl_internal.h"
|
||||||
|
|
||||||
static const unsigned int ucl_chartable[256] = {
|
static const unsigned int ucl_chartable[256] = {
|
||||||
UCL_CHARACTER_VALUE_END, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_VALUE_END|UCL_CHARACTER_UCL_UNSAFE, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
||||||
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
||||||
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
UCL_CHARACTER_DENIED, UCL_CHARACTER_DENIED,
|
||||||
UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
|
UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_UCL_UNSAFE,
|
||||||
@ -49,7 +49,7 @@ UCL_CHARACTER_VALUE_END /* # */, UCL_CHARACTER_VALUE_STR /* $ */,
|
|||||||
UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */,
|
UCL_CHARACTER_VALUE_STR /* % */, UCL_CHARACTER_VALUE_STR /* & */,
|
||||||
UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */,
|
UCL_CHARACTER_VALUE_STR /* ' */, UCL_CHARACTER_VALUE_STR /* ( */,
|
||||||
UCL_CHARACTER_VALUE_STR /* ) */, UCL_CHARACTER_VALUE_STR /* * */,
|
UCL_CHARACTER_VALUE_STR /* ) */, UCL_CHARACTER_VALUE_STR /* * */,
|
||||||
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* + */,
|
UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT|UCL_CHARACTER_UCL_UNSAFE /* + */,
|
||||||
UCL_CHARACTER_VALUE_END /* , */,
|
UCL_CHARACTER_VALUE_END /* , */,
|
||||||
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* - */,
|
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT_START|UCL_CHARACTER_VALUE_DIGIT /* - */,
|
||||||
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* . */,
|
UCL_CHARACTER_KEY|UCL_CHARACTER_VALUE_STR|UCL_CHARACTER_VALUE_DIGIT /* . */,
|
||||||
|
@ -424,8 +424,16 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,
|
|||||||
break;
|
break;
|
||||||
case UCL_STRING:
|
case UCL_STRING:
|
||||||
ucl_emitter_print_key (print_key, ctx, obj, compact);
|
ucl_emitter_print_key (print_key, ctx, obj, compact);
|
||||||
if (ctx->id == UCL_EMIT_CONFIG && ucl_maybe_long_string (obj)) {
|
if (ctx->id == UCL_EMIT_CONFIG) {
|
||||||
ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
|
if (ucl_maybe_long_string (obj)) {
|
||||||
|
ucl_elt_string_write_multiline (obj->value.sv, obj->len, ctx);
|
||||||
|
} else {
|
||||||
|
if (obj->flags & UCL_OBJECT_SQUOTED) {
|
||||||
|
ucl_elt_string_write_squoted (obj->value.sv, obj->len, ctx);
|
||||||
|
} else {
|
||||||
|
ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
|
ucl_elt_string_write_json (obj->value.sv, obj->len, ctx);
|
||||||
|
@ -71,6 +71,13 @@ static const struct ucl_emitter_context ucl_standard_emitters[] = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
_ucl_emitter_free(void *p)
|
||||||
|
{
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get standard emitter context for a specified emit_type
|
* Get standard emitter context for a specified emit_type
|
||||||
* @param emit_type type of emitter
|
* @param emit_type type of emitter
|
||||||
@ -102,7 +109,9 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||||
|
|
||||||
while (size) {
|
while (size) {
|
||||||
if (ucl_test_character (*p, UCL_CHARACTER_JSON_UNSAFE|UCL_CHARACTER_DENIED)) {
|
if (ucl_test_character (*p, (UCL_CHARACTER_JSON_UNSAFE|
|
||||||
|
UCL_CHARACTER_DENIED|
|
||||||
|
UCL_CHARACTER_WHITESPACE_UNSAFE))) {
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
func->ucl_emitter_append_len (c, len, func->ud);
|
func->ucl_emitter_append_len (c, len, func->ud);
|
||||||
}
|
}
|
||||||
@ -122,15 +131,21 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
case '\f':
|
case '\f':
|
||||||
func->ucl_emitter_append_len ("\\f", 2, func->ud);
|
func->ucl_emitter_append_len ("\\f", 2, func->ud);
|
||||||
break;
|
break;
|
||||||
|
case '\v':
|
||||||
|
func->ucl_emitter_append_len ("\\u000B", 6, func->ud);
|
||||||
|
break;
|
||||||
case '\\':
|
case '\\':
|
||||||
func->ucl_emitter_append_len ("\\\\", 2, func->ud);
|
func->ucl_emitter_append_len ("\\\\", 2, func->ud);
|
||||||
break;
|
break;
|
||||||
|
case ' ':
|
||||||
|
func->ucl_emitter_append_character (' ', 1, func->ud);
|
||||||
|
break;
|
||||||
case '"':
|
case '"':
|
||||||
func->ucl_emitter_append_len ("\\\"", 2, func->ud);
|
func->ucl_emitter_append_len ("\\\"", 2, func->ud);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Emit unicode unknown character */
|
/* Emit unicode unknown character */
|
||||||
func->ucl_emitter_append_len ("\\uFFFD", 5, func->ud);
|
func->ucl_emitter_append_len ("\\uFFFD", 6, func->ud);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
len = 0;
|
len = 0;
|
||||||
@ -150,6 +165,40 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
|||||||
func->ucl_emitter_append_character ('"', 1, func->ud);
|
func->ucl_emitter_append_character ('"', 1, func->ud);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ucl_elt_string_write_squoted (const char *str, size_t size,
|
||||||
|
struct ucl_emitter_context *ctx)
|
||||||
|
{
|
||||||
|
const char *p = str, *c = str;
|
||||||
|
size_t len = 0;
|
||||||
|
const struct ucl_emitter_functions *func = ctx->func;
|
||||||
|
|
||||||
|
func->ucl_emitter_append_character ('\'', 1, func->ud);
|
||||||
|
|
||||||
|
while (size) {
|
||||||
|
if (*p == '\'') {
|
||||||
|
if (len > 0) {
|
||||||
|
func->ucl_emitter_append_len (c, len, func->ud);
|
||||||
|
}
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
c = ++p;
|
||||||
|
func->ucl_emitter_append_len ("\\\'", 2, func->ud);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
p ++;
|
||||||
|
len ++;
|
||||||
|
}
|
||||||
|
size --;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len > 0) {
|
||||||
|
func->ucl_emitter_append_len (c, len, func->ud);
|
||||||
|
}
|
||||||
|
|
||||||
|
func->ucl_emitter_append_character ('\'', 1, func->ud);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ucl_elt_string_write_multiline (const char *str, size_t size,
|
ucl_elt_string_write_multiline (const char *str, size_t size,
|
||||||
struct ucl_emitter_context *ctx)
|
struct ucl_emitter_context *ctx)
|
||||||
@ -363,7 +412,7 @@ ucl_object_emit_memory_funcs (void **pmem)
|
|||||||
f->ucl_emitter_append_double = ucl_utstring_append_double;
|
f->ucl_emitter_append_double = ucl_utstring_append_double;
|
||||||
f->ucl_emitter_append_int = ucl_utstring_append_int;
|
f->ucl_emitter_append_int = ucl_utstring_append_int;
|
||||||
f->ucl_emitter_append_len = ucl_utstring_append_len;
|
f->ucl_emitter_append_len = ucl_utstring_append_len;
|
||||||
f->ucl_emitter_free_func = free;
|
f->ucl_emitter_free_func = _ucl_emitter_free;
|
||||||
utstring_new (s);
|
utstring_new (s);
|
||||||
f->ud = s;
|
f->ud = s;
|
||||||
*pmem = s->d;
|
*pmem = s->d;
|
||||||
@ -412,7 +461,7 @@ ucl_object_emit_fd_funcs (int fd)
|
|||||||
f->ucl_emitter_append_double = ucl_fd_append_double;
|
f->ucl_emitter_append_double = ucl_fd_append_double;
|
||||||
f->ucl_emitter_append_int = ucl_fd_append_int;
|
f->ucl_emitter_append_int = ucl_fd_append_int;
|
||||||
f->ucl_emitter_append_len = ucl_fd_append_len;
|
f->ucl_emitter_append_len = ucl_fd_append_len;
|
||||||
f->ucl_emitter_free_func = free;
|
f->ucl_emitter_free_func = _ucl_emitter_free;
|
||||||
f->ud = ip;
|
f->ud = ip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
218
src/ucl_hash.c
218
src/ucl_hash.c
@ -143,10 +143,10 @@ ucl_hash_caseless_func (const ucl_object_t *o)
|
|||||||
u.c.c2 = lc_map[u.c.c2];
|
u.c.c2 = lc_map[u.c.c2];
|
||||||
u.c.c3 = lc_map[u.c.c3];
|
u.c.c3 = lc_map[u.c.c3];
|
||||||
u.c.c4 = lc_map[u.c.c4];
|
u.c.c4 = lc_map[u.c.c4];
|
||||||
u.c.c1 = lc_map[u.c.c5];
|
u.c.c5 = lc_map[u.c.c5];
|
||||||
u.c.c2 = lc_map[u.c.c6];
|
u.c.c6 = lc_map[u.c.c6];
|
||||||
u.c.c3 = lc_map[u.c.c7];
|
u.c.c7 = lc_map[u.c.c7];
|
||||||
u.c.c4 = lc_map[u.c.c8];
|
u.c.c8 = lc_map[u.c.c8];
|
||||||
r = mum_hash_step (r, u.pp);
|
r = mum_hash_step (r, u.pp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,16 +154,22 @@ ucl_hash_caseless_func (const ucl_object_t *o)
|
|||||||
switch (leftover) {
|
switch (leftover) {
|
||||||
case 7:
|
case 7:
|
||||||
u.c.c7 = lc_map[(unsigned char)s[i++]];
|
u.c.c7 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 6:
|
case 6:
|
||||||
u.c.c6 = lc_map[(unsigned char)s[i++]];
|
u.c.c6 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 5:
|
case 5:
|
||||||
u.c.c5 = lc_map[(unsigned char)s[i++]];
|
u.c.c5 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 4:
|
case 4:
|
||||||
u.c.c4 = lc_map[(unsigned char)s[i++]];
|
u.c.c4 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 3:
|
case 3:
|
||||||
u.c.c3 = lc_map[(unsigned char)s[i++]];
|
u.c.c3 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 2:
|
case 2:
|
||||||
u.c.c2 = lc_map[(unsigned char)s[i++]];
|
u.c.c2 = lc_map[(unsigned char)s[i++]];
|
||||||
|
/* FALLTHRU */
|
||||||
case 1:
|
case 1:
|
||||||
u.c.c1 = lc_map[(unsigned char)s[i]];
|
u.c.c1 = lc_map[(unsigned char)s[i]];
|
||||||
r = mum_hash_step (r, u.pp);
|
r = mum_hash_step (r, u.pp);
|
||||||
@ -177,7 +183,45 @@ static inline int
|
|||||||
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
|
ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)
|
||||||
{
|
{
|
||||||
if (k1->keylen == k2->keylen) {
|
if (k1->keylen == k2->keylen) {
|
||||||
return memcmp (k1->key, k2->key, k1->keylen) == 0;
|
unsigned fp, i;
|
||||||
|
const char *s = k1->key, *d = k2->key;
|
||||||
|
unsigned char c1, c2, c3, c4;
|
||||||
|
union {
|
||||||
|
unsigned char c[4];
|
||||||
|
uint32_t n;
|
||||||
|
} cmp1, cmp2;
|
||||||
|
size_t leftover = k1->keylen % 4;
|
||||||
|
|
||||||
|
fp = k1->keylen - leftover;
|
||||||
|
|
||||||
|
for (i = 0; i != fp; i += 4) {
|
||||||
|
c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
|
||||||
|
cmp1.c[0] = lc_map[c1];
|
||||||
|
cmp1.c[1] = lc_map[c2];
|
||||||
|
cmp1.c[2] = lc_map[c3];
|
||||||
|
cmp1.c[3] = lc_map[c4];
|
||||||
|
|
||||||
|
c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
|
||||||
|
cmp2.c[0] = lc_map[c1];
|
||||||
|
cmp2.c[1] = lc_map[c2];
|
||||||
|
cmp2.c[2] = lc_map[c3];
|
||||||
|
cmp2.c[3] = lc_map[c4];
|
||||||
|
|
||||||
|
if (cmp1.n != cmp2.n) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (leftover > 0) {
|
||||||
|
if (lc_map[(unsigned char)s[i]] != lc_map[(unsigned char)d[i]]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
leftover--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -193,17 +237,21 @@ ucl_hash_create (bool ignore_case)
|
|||||||
|
|
||||||
new = UCL_ALLOC (sizeof (ucl_hash_t));
|
new = UCL_ALLOC (sizeof (ucl_hash_t));
|
||||||
if (new != NULL) {
|
if (new != NULL) {
|
||||||
|
void *h;
|
||||||
kv_init (new->ar);
|
kv_init (new->ar);
|
||||||
|
|
||||||
new->caseless = ignore_case;
|
new->caseless = ignore_case;
|
||||||
if (ignore_case) {
|
if (ignore_case) {
|
||||||
khash_t(ucl_hash_caseless_node) *h = kh_init (ucl_hash_caseless_node);
|
h = (void *)kh_init (ucl_hash_caseless_node);
|
||||||
new->hash = (void *)h;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
khash_t(ucl_hash_node) *h = kh_init (ucl_hash_node);
|
h = (void *)kh_init (ucl_hash_node);
|
||||||
new->hash = (void *)h;
|
|
||||||
}
|
}
|
||||||
|
if (h == NULL) {
|
||||||
|
UCL_FREE (sizeof (ucl_hash_t), new);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
new->hash = h;
|
||||||
}
|
}
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
@ -249,7 +297,7 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)
|
|||||||
UCL_FREE (sizeof (*hashlin), hashlin);
|
UCL_FREE (sizeof (*hashlin), hashlin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
||||||
const char *key, unsigned keylen)
|
const char *key, unsigned keylen)
|
||||||
{
|
{
|
||||||
@ -258,7 +306,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
|||||||
struct ucl_hash_elt *elt;
|
struct ucl_hash_elt *elt;
|
||||||
|
|
||||||
if (hashlin == NULL) {
|
if (hashlin == NULL) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hashlin->caseless) {
|
if (hashlin->caseless) {
|
||||||
@ -267,7 +315,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
|||||||
k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
|
k = kh_put (ucl_hash_caseless_node, h, obj, &ret);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
elt = &kh_value (h, k);
|
elt = &kh_value (h, k);
|
||||||
kv_push (const ucl_object_t *, hashlin->ar, obj);
|
kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0);
|
||||||
elt->obj = obj;
|
elt->obj = obj;
|
||||||
elt->ar_idx = kv_size (hashlin->ar) - 1;
|
elt->ar_idx = kv_size (hashlin->ar) - 1;
|
||||||
}
|
}
|
||||||
@ -278,11 +326,16 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
|||||||
k = kh_put (ucl_hash_node, h, obj, &ret);
|
k = kh_put (ucl_hash_node, h, obj, &ret);
|
||||||
if (ret > 0) {
|
if (ret > 0) {
|
||||||
elt = &kh_value (h, k);
|
elt = &kh_value (h, k);
|
||||||
kv_push (const ucl_object_t *, hashlin->ar, obj);
|
kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0);
|
||||||
elt->obj = obj;
|
elt->obj = obj;
|
||||||
elt->ar_idx = kv_size (hashlin->ar) - 1;
|
elt->ar_idx = kv_size (hashlin->ar) - 1;
|
||||||
|
} else if (ret < 0) {
|
||||||
|
goto e0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
e0:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
|
void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,
|
||||||
@ -331,13 +384,16 @@ struct ucl_hash_real_iter {
|
|||||||
const ucl_object_t **end;
|
const ucl_object_t **end;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);}
|
||||||
|
|
||||||
const void*
|
const void*
|
||||||
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep)
|
||||||
{
|
{
|
||||||
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
|
struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(*iter);
|
||||||
const ucl_object_t *ret = NULL;
|
const ucl_object_t *ret = NULL;
|
||||||
|
|
||||||
if (hashlin == NULL) {
|
if (hashlin == NULL) {
|
||||||
|
UHI_SETERR(ep, EINVAL);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -345,6 +401,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
|||||||
it = UCL_ALLOC (sizeof (*it));
|
it = UCL_ALLOC (sizeof (*it));
|
||||||
|
|
||||||
if (it == NULL) {
|
if (it == NULL) {
|
||||||
|
UHI_SETERR(ep, ENOMEM);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,6 +409,7 @@ ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
|||||||
it->end = it->cur + hashlin->ar.n;
|
it->end = it->cur + hashlin->ar.n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UHI_SETERR(ep, 0);
|
||||||
if (it->cur < it->end) {
|
if (it->cur < it->end) {
|
||||||
ret = *it->cur++;
|
ret = *it->cur++;
|
||||||
}
|
}
|
||||||
@ -418,6 +476,7 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
|||||||
{
|
{
|
||||||
khiter_t k;
|
khiter_t k;
|
||||||
struct ucl_hash_elt *elt;
|
struct ucl_hash_elt *elt;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (hashlin == NULL) {
|
if (hashlin == NULL) {
|
||||||
return;
|
return;
|
||||||
@ -430,8 +489,15 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
|||||||
k = kh_get (ucl_hash_caseless_node, h, obj);
|
k = kh_get (ucl_hash_caseless_node, h, obj);
|
||||||
if (k != kh_end (h)) {
|
if (k != kh_end (h)) {
|
||||||
elt = &kh_value (h, k);
|
elt = &kh_value (h, k);
|
||||||
|
i = elt->ar_idx;
|
||||||
kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
|
kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
|
||||||
kh_del (ucl_hash_caseless_node, h, k);
|
kh_del (ucl_hash_caseless_node, h, k);
|
||||||
|
|
||||||
|
/* Update subsequent elts */
|
||||||
|
for (; i < hashlin->ar.n; i ++) {
|
||||||
|
elt = &kh_value (h, i);
|
||||||
|
elt->ar_idx --;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -440,8 +506,132 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
|||||||
k = kh_get (ucl_hash_node, h, obj);
|
k = kh_get (ucl_hash_node, h, obj);
|
||||||
if (k != kh_end (h)) {
|
if (k != kh_end (h)) {
|
||||||
elt = &kh_value (h, k);
|
elt = &kh_value (h, k);
|
||||||
|
i = elt->ar_idx;
|
||||||
kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
|
kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx);
|
||||||
kh_del (ucl_hash_node, h, k);
|
kh_del (ucl_hash_node, h, k);
|
||||||
|
|
||||||
|
/* Update subsequent elts */
|
||||||
|
for (; i < hashlin->ar.n; i ++) {
|
||||||
|
elt = &kh_value (h, i);
|
||||||
|
elt->ar_idx --;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)
|
||||||
|
{
|
||||||
|
if (hashlin == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sz > hashlin->ar.m) {
|
||||||
|
kv_resize_safe (const ucl_object_t *, hashlin->ar, sz, e0);
|
||||||
|
|
||||||
|
if (hashlin->caseless) {
|
||||||
|
khash_t(ucl_hash_caseless_node) *h = (khash_t(
|
||||||
|
ucl_hash_caseless_node) *)
|
||||||
|
hashlin->hash;
|
||||||
|
kh_resize (ucl_hash_caseless_node, h, sz * 2);
|
||||||
|
} else {
|
||||||
|
khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)
|
||||||
|
hashlin->hash;
|
||||||
|
kh_resize (ucl_hash_node, h, sz * 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
e0:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucl_lc_cmp (const char *s, const char *d, size_t l)
|
||||||
|
{
|
||||||
|
unsigned int fp, i;
|
||||||
|
unsigned char c1, c2, c3, c4;
|
||||||
|
union {
|
||||||
|
unsigned char c[4];
|
||||||
|
uint32_t n;
|
||||||
|
} cmp1, cmp2;
|
||||||
|
size_t leftover = l % 4;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
fp = l - leftover;
|
||||||
|
|
||||||
|
for (i = 0; i != fp; i += 4) {
|
||||||
|
c1 = s[i], c2 = s[i + 1], c3 = s[i + 2], c4 = s[i + 3];
|
||||||
|
cmp1.c[0] = lc_map[c1];
|
||||||
|
cmp1.c[1] = lc_map[c2];
|
||||||
|
cmp1.c[2] = lc_map[c3];
|
||||||
|
cmp1.c[3] = lc_map[c4];
|
||||||
|
|
||||||
|
c1 = d[i], c2 = d[i + 1], c3 = d[i + 2], c4 = d[i + 3];
|
||||||
|
cmp2.c[0] = lc_map[c1];
|
||||||
|
cmp2.c[1] = lc_map[c2];
|
||||||
|
cmp2.c[2] = lc_map[c3];
|
||||||
|
cmp2.c[3] = lc_map[c4];
|
||||||
|
|
||||||
|
if (cmp1.n != cmp2.n) {
|
||||||
|
return cmp1.n - cmp2.n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (leftover > 0) {
|
||||||
|
if (lc_map[(unsigned char)s[i]] != lc_map[(unsigned char)d[i]]) {
|
||||||
|
return s[i] - d[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
leftover--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucl_hash_cmp_icase (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const ucl_object_t *oa = *(const ucl_object_t **)a,
|
||||||
|
*ob = *(const ucl_object_t **)b;
|
||||||
|
|
||||||
|
if (oa->keylen == ob->keylen) {
|
||||||
|
return ucl_lc_cmp (oa->key, ob->key, oa->keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((int)(oa->keylen)) - ob->keylen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
ucl_hash_cmp_case_sens (const void *a, const void *b)
|
||||||
|
{
|
||||||
|
const ucl_object_t *oa = *(const ucl_object_t **)a,
|
||||||
|
*ob = *(const ucl_object_t **)b;
|
||||||
|
|
||||||
|
if (oa->keylen == ob->keylen) {
|
||||||
|
return memcmp (oa->key, ob->key, oa->keylen);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((int)(oa->keylen)) - ob->keylen;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (fl & UCL_SORT_KEYS_ICASE) {
|
||||||
|
qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *),
|
||||||
|
ucl_hash_cmp_icase);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *),
|
||||||
|
ucl_hash_cmp_case_sens);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fl & UCL_SORT_KEYS_RECURSIVE) {
|
||||||
|
for (size_t i = 0; i < hashlin->ar.n; i ++) {
|
||||||
|
if (ucl_object_type (hashlin->ar.a[i]) == UCL_OBJECT) {
|
||||||
|
ucl_hash_sort (hashlin->ar.a[i]->value.ov, fl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,9 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Inserts an element in the the hashtable.
|
* Inserts an element in the the hashtable.
|
||||||
|
* @return true on success, false on failure (i.e. ENOMEM)
|
||||||
*/
|
*/
|
||||||
void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
|
bool ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
|
||||||
unsigned keylen);
|
unsigned keylen);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -81,13 +82,28 @@ const ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key,
|
|||||||
* Iterate over hash table
|
* Iterate over hash table
|
||||||
* @param hashlin hash
|
* @param hashlin hash
|
||||||
* @param iter iterator (must be NULL on first iteration)
|
* @param iter iterator (must be NULL on first iteration)
|
||||||
|
* @param ep pointer record exception (such as ENOMEM), could be NULL
|
||||||
* @return the next object
|
* @return the next object
|
||||||
*/
|
*/
|
||||||
const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
|
const void* ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper macro to support older code
|
||||||
|
*/
|
||||||
|
#define ucl_hash_iterate(hl, ip) ucl_hash_iterate2((hl), (ip), NULL)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether an iterator has next element
|
* Check whether an iterator has next element
|
||||||
*/
|
*/
|
||||||
bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);
|
bool ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reserves space in hash
|
||||||
|
* @return true on sucess, false on failure (e.g. ENOMEM)
|
||||||
|
* @param hashlin
|
||||||
|
*/
|
||||||
|
bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz);
|
||||||
|
|
||||||
|
void ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -63,7 +63,9 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYS_PARAM_H
|
#ifdef HAVE_SYS_PARAM_H
|
||||||
#include <sys/param.h>
|
# ifndef _WIN32
|
||||||
|
# include <sys/param.h>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIMITS_H
|
#ifdef HAVE_LIMITS_H
|
||||||
@ -76,7 +78,9 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
# ifndef _WIN32
|
||||||
|
# include <unistd.h>
|
||||||
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_CTYPE_H
|
#ifdef HAVE_CTYPE_H
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -91,6 +95,32 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
/* Windows hacks */
|
||||||
|
#include <BaseTsd.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#define strdup _strdup
|
||||||
|
#define snprintf _snprintf
|
||||||
|
#define vsnprintf _vsnprintf
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#define strncasecmp _strnicmp
|
||||||
|
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
|
||||||
|
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||||
|
#if _MSC_VER >= 1900
|
||||||
|
#include <../ucrt/stdlib.h>
|
||||||
|
#else
|
||||||
|
#include <../include/stdlib.h>
|
||||||
|
#endif
|
||||||
|
#ifndef PATH_MAX
|
||||||
|
#define PATH_MAX _MAX_PATH
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Dirname, basename implementations */
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "utlist.h"
|
#include "utlist.h"
|
||||||
#include "utstring.h"
|
#include "utstring.h"
|
||||||
#include "uthash.h"
|
#include "uthash.h"
|
||||||
@ -119,6 +149,7 @@ enum ucl_parser_state {
|
|||||||
UCL_STATE_OBJECT,
|
UCL_STATE_OBJECT,
|
||||||
UCL_STATE_ARRAY,
|
UCL_STATE_ARRAY,
|
||||||
UCL_STATE_KEY,
|
UCL_STATE_KEY,
|
||||||
|
UCL_STATE_KEY_OBRACE,
|
||||||
UCL_STATE_VALUE,
|
UCL_STATE_VALUE,
|
||||||
UCL_STATE_AFTER_VALUE,
|
UCL_STATE_AFTER_VALUE,
|
||||||
UCL_STATE_ARRAY_VALUE,
|
UCL_STATE_ARRAY_VALUE,
|
||||||
@ -147,7 +178,7 @@ enum ucl_character_type {
|
|||||||
|
|
||||||
struct ucl_macro {
|
struct ucl_macro {
|
||||||
char *name;
|
char *name;
|
||||||
union {
|
union _ucl_macro {
|
||||||
ucl_macro_handler handler;
|
ucl_macro_handler handler;
|
||||||
ucl_context_macro_handler context_handler;
|
ucl_context_macro_handler context_handler;
|
||||||
} h;
|
} h;
|
||||||
@ -156,22 +187,44 @@ struct ucl_macro {
|
|||||||
UT_hash_handle hh;
|
UT_hash_handle hh;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ucl_stack_flags {
|
||||||
|
UCL_STACK_HAS_OBRACE = (1u << 0),
|
||||||
|
UCL_STACK_MAX = (1u << 1),
|
||||||
|
};
|
||||||
|
|
||||||
struct ucl_stack {
|
struct ucl_stack {
|
||||||
ucl_object_t *obj;
|
ucl_object_t *obj;
|
||||||
struct ucl_stack *next;
|
struct ucl_stack *next;
|
||||||
uint64_t level;
|
union {
|
||||||
|
struct {
|
||||||
|
uint16_t level;
|
||||||
|
uint16_t flags;
|
||||||
|
uint32_t line;
|
||||||
|
} params;
|
||||||
|
uint64_t len;
|
||||||
|
} e;
|
||||||
|
struct ucl_chunk *chunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ucl_parser_special_handler_chain {
|
||||||
|
unsigned char *begin;
|
||||||
|
size_t len;
|
||||||
|
struct ucl_parser_special_handler *special_handler;
|
||||||
|
struct ucl_parser_special_handler_chain *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ucl_chunk {
|
struct ucl_chunk {
|
||||||
const unsigned char *begin;
|
const unsigned char *begin;
|
||||||
const unsigned char *end;
|
const unsigned char *end;
|
||||||
const unsigned char *pos;
|
const unsigned char *pos;
|
||||||
|
char *fname;
|
||||||
size_t remain;
|
size_t remain;
|
||||||
unsigned int line;
|
unsigned int line;
|
||||||
unsigned int column;
|
unsigned int column;
|
||||||
unsigned priority;
|
unsigned priority;
|
||||||
enum ucl_duplicate_strategy strategy;
|
enum ucl_duplicate_strategy strategy;
|
||||||
enum ucl_parse_type parse_type;
|
enum ucl_parse_type parse_type;
|
||||||
|
struct ucl_parser_special_handler_chain *special_handlers;
|
||||||
struct ucl_chunk *next;
|
struct ucl_chunk *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -210,6 +263,9 @@ struct ucl_parser {
|
|||||||
struct ucl_stack *stack;
|
struct ucl_stack *stack;
|
||||||
struct ucl_chunk *chunks;
|
struct ucl_chunk *chunks;
|
||||||
struct ucl_pubkey *keys;
|
struct ucl_pubkey *keys;
|
||||||
|
struct ucl_parser_special_handler *special_handlers;
|
||||||
|
ucl_include_trace_func_t *include_trace_func;
|
||||||
|
void *include_trace_ud;
|
||||||
struct ucl_variable *variables;
|
struct ucl_variable *variables;
|
||||||
ucl_variable_handler var_handler;
|
ucl_variable_handler var_handler;
|
||||||
void *var_data;
|
void *var_data;
|
||||||
@ -230,6 +286,13 @@ struct ucl_object_userdata {
|
|||||||
*/
|
*/
|
||||||
size_t ucl_unescape_json_string (char *str, size_t len);
|
size_t ucl_unescape_json_string (char *str, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unescape single quoted string inplace
|
||||||
|
* @param str
|
||||||
|
*/
|
||||||
|
size_t ucl_unescape_squoted_string (char *str, size_t len);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle include macro
|
* Handle include macro
|
||||||
* @param data include data
|
* @param data include data
|
||||||
@ -410,12 +473,24 @@ ucl_hash_insert_object (ucl_hash_t *hashlin,
|
|||||||
const ucl_object_t *obj,
|
const ucl_object_t *obj,
|
||||||
bool ignore_case)
|
bool ignore_case)
|
||||||
{
|
{
|
||||||
if (hashlin == NULL) {
|
ucl_hash_t *nhp;
|
||||||
hashlin = ucl_hash_create (ignore_case);
|
|
||||||
}
|
|
||||||
ucl_hash_insert (hashlin, obj, obj->key, obj->keylen);
|
|
||||||
|
|
||||||
return hashlin;
|
if (hashlin == NULL) {
|
||||||
|
nhp = ucl_hash_create (ignore_case);
|
||||||
|
if (nhp == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nhp = hashlin;
|
||||||
|
}
|
||||||
|
if (!ucl_hash_insert (nhp, obj, obj->key, obj->keylen)) {
|
||||||
|
if (nhp != hashlin) {
|
||||||
|
ucl_hash_destroy(nhp, NULL);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nhp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -434,6 +509,16 @@ ucl_emit_get_standard_context (enum ucl_emitter emit_type);
|
|||||||
void ucl_elt_string_write_json (const char *str, size_t size,
|
void ucl_elt_string_write_json (const char *str, size_t size,
|
||||||
struct ucl_emitter_context *ctx);
|
struct ucl_emitter_context *ctx);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize string as single quoted string
|
||||||
|
* @param str string to emit
|
||||||
|
* @param buf target buffer
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ucl_elt_string_write_squoted (const char *str, size_t size,
|
||||||
|
struct ucl_emitter_context *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write multiline string using `EOD` as string terminator
|
* Write multiline string using `EOD` as string terminator
|
||||||
* @param str
|
* @param str
|
||||||
@ -573,4 +658,10 @@ bool ucl_parse_msgpack (struct ucl_parser *parser);
|
|||||||
|
|
||||||
bool ucl_parse_csexp (struct ucl_parser *parser);
|
bool ucl_parse_csexp (struct ucl_parser *parser);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free ucl chunk
|
||||||
|
* @param chunk
|
||||||
|
*/
|
||||||
|
void ucl_chunk_free (struct ucl_chunk *chunk);
|
||||||
|
|
||||||
#endif /* UCL_INTERNAL_H_ */
|
#endif /* UCL_INTERNAL_H_ */
|
||||||
|
@ -434,7 +434,6 @@ static ssize_t ucl_msgpack_parse_ignore (struct ucl_parser *parser,
|
|||||||
#define MSGPACK_FLAG_EXT (1 << 3)
|
#define MSGPACK_FLAG_EXT (1 << 3)
|
||||||
#define MSGPACK_FLAG_ASSOC (1 << 4)
|
#define MSGPACK_FLAG_ASSOC (1 << 4)
|
||||||
#define MSGPACK_FLAG_KEY (1 << 5)
|
#define MSGPACK_FLAG_KEY (1 << 5)
|
||||||
#define MSGPACK_CONTAINER_BIT (1ULL << 62)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search tree packed in array
|
* Search tree packed in array
|
||||||
@ -768,7 +767,6 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
|
|||||||
assert (obj_parser != NULL);
|
assert (obj_parser != NULL);
|
||||||
|
|
||||||
if (obj_parser->flags & MSGPACK_FLAG_CONTAINER) {
|
if (obj_parser->flags & MSGPACK_FLAG_CONTAINER) {
|
||||||
assert ((len & MSGPACK_CONTAINER_BIT) == 0);
|
|
||||||
/*
|
/*
|
||||||
* Insert new container to the stack
|
* Insert new container to the stack
|
||||||
*/
|
*/
|
||||||
@ -779,6 +777,8 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
|
|||||||
ucl_create_err (&parser->err, "no memory");
|
ucl_create_err (&parser->err, "no memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parser->stack->chunk = parser->chunks;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
stack = calloc (1, sizeof (struct ucl_stack));
|
stack = calloc (1, sizeof (struct ucl_stack));
|
||||||
@ -788,11 +788,12 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stack->chunk = parser->chunks;
|
||||||
stack->next = parser->stack;
|
stack->next = parser->stack;
|
||||||
parser->stack = stack;
|
parser->stack = stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->stack->level = len | MSGPACK_CONTAINER_BIT;
|
parser->stack->e.len = len;
|
||||||
|
|
||||||
#ifdef MSGPACK_DEBUG_PARSER
|
#ifdef MSGPACK_DEBUG_PARSER
|
||||||
stack = parser->stack;
|
stack = parser->stack;
|
||||||
@ -823,16 +824,11 @@ ucl_msgpack_get_container (struct ucl_parser *parser,
|
|||||||
static bool
|
static bool
|
||||||
ucl_msgpack_is_container_finished (struct ucl_stack *container)
|
ucl_msgpack_is_container_finished (struct ucl_stack *container)
|
||||||
{
|
{
|
||||||
uint64_t level;
|
|
||||||
|
|
||||||
assert (container != NULL);
|
assert (container != NULL);
|
||||||
|
|
||||||
if (container->level & MSGPACK_CONTAINER_BIT) {
|
|
||||||
level = container->level & ~MSGPACK_CONTAINER_BIT;
|
|
||||||
|
|
||||||
if (level == 0) {
|
if (container->e.len == 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -843,12 +839,11 @@ ucl_msgpack_insert_object (struct ucl_parser *parser,
|
|||||||
const unsigned char *key,
|
const unsigned char *key,
|
||||||
size_t keylen, ucl_object_t *obj)
|
size_t keylen, ucl_object_t *obj)
|
||||||
{
|
{
|
||||||
uint64_t level;
|
|
||||||
struct ucl_stack *container;
|
struct ucl_stack *container;
|
||||||
|
|
||||||
container = parser->stack;
|
container = parser->stack;
|
||||||
assert (container != NULL);
|
assert (container != NULL);
|
||||||
assert (container->level > 0);
|
assert (container->e.len > 0);
|
||||||
assert (obj != NULL);
|
assert (obj != NULL);
|
||||||
assert (container->obj != NULL);
|
assert (container->obj != NULL);
|
||||||
|
|
||||||
@ -875,10 +870,7 @@ ucl_msgpack_insert_object (struct ucl_parser *parser,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (container->level & MSGPACK_CONTAINER_BIT) {
|
container->e.len--;
|
||||||
level = container->level & ~MSGPACK_CONTAINER_BIT;
|
|
||||||
container->level = (level - 1) | MSGPACK_CONTAINER_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -887,7 +879,7 @@ static struct ucl_stack *
|
|||||||
ucl_msgpack_get_next_container (struct ucl_parser *parser)
|
ucl_msgpack_get_next_container (struct ucl_parser *parser)
|
||||||
{
|
{
|
||||||
struct ucl_stack *cur = NULL;
|
struct ucl_stack *cur = NULL;
|
||||||
uint64_t level;
|
uint64_t len;
|
||||||
|
|
||||||
cur = parser->stack;
|
cur = parser->stack;
|
||||||
|
|
||||||
@ -895,17 +887,16 @@ ucl_msgpack_get_next_container (struct ucl_parser *parser)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur->level & MSGPACK_CONTAINER_BIT) {
|
len = cur->e.len;
|
||||||
level = cur->level & ~MSGPACK_CONTAINER_BIT;
|
|
||||||
|
|
||||||
if (level == 0) {
|
if (len == 0) {
|
||||||
/* We need to switch to the previous container */
|
/* We need to switch to the previous container */
|
||||||
parser->stack = cur->next;
|
parser->stack = cur->next;
|
||||||
parser->cur_obj = cur->obj;
|
parser->cur_obj = cur->obj;
|
||||||
free (cur);
|
free (cur);
|
||||||
|
|
||||||
#ifdef MSGPACK_DEBUG_PARSER
|
#ifdef MSGPACK_DEBUG_PARSER
|
||||||
cur = parser->stack;
|
cur = parser->stack;
|
||||||
while (cur) {
|
while (cur) {
|
||||||
fprintf(stderr, "-");
|
fprintf(stderr, "-");
|
||||||
cur = cur->next;
|
cur = cur->next;
|
||||||
@ -913,8 +904,7 @@ ucl_msgpack_get_next_container (struct ucl_parser *parser)
|
|||||||
fprintf(stderr, "-%s -> %d\n", parser->cur_obj->type == UCL_OBJECT ? "object" : "array", (int)parser->cur_obj->len);
|
fprintf(stderr, "-%s -> %d\n", parser->cur_obj->type == UCL_OBJECT ? "object" : "array", (int)parser->cur_obj->len);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return ucl_msgpack_get_next_container (parser);
|
return ucl_msgpack_get_next_container (parser);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1029,6 +1019,8 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* Length is not embedded */
|
/* Length is not embedded */
|
||||||
|
remain --;
|
||||||
|
|
||||||
if (remain < obj_parser->len) {
|
if (remain < obj_parser->len) {
|
||||||
ucl_create_err (&parser->err, "not enough data remain to "
|
ucl_create_err (&parser->err, "not enough data remain to "
|
||||||
"read object's length: %u remain, %u needed",
|
"read object's length: %u remain, %u needed",
|
||||||
@ -1038,7 +1030,6 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
|
|
||||||
p ++;
|
p ++;
|
||||||
remain --;
|
|
||||||
|
|
||||||
switch (obj_parser->len) {
|
switch (obj_parser->len) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -1054,8 +1045,10 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
len = FROM_BE64 (*(uint64_t *)p);
|
len = FROM_BE64 (*(uint64_t *)p);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert (0);
|
ucl_create_err (&parser->err, "invalid length of the length field: %u",
|
||||||
break;
|
(unsigned)obj_parser->len);
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += obj_parser->len;
|
p += obj_parser->len;
|
||||||
@ -1141,7 +1134,9 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
*/
|
*/
|
||||||
container = parser->stack;
|
container = parser->stack;
|
||||||
|
|
||||||
if (container == NULL) {
|
if (parser->stack == NULL) {
|
||||||
|
ucl_create_err (&parser->err,
|
||||||
|
"read assoc value when no container represented");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1201,6 +1196,8 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
container = parser->stack;
|
container = parser->stack;
|
||||||
|
|
||||||
if (container == NULL) {
|
if (container == NULL) {
|
||||||
|
ucl_create_err (&parser->err,
|
||||||
|
"read assoc value when no container represented");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1212,6 +1209,7 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
|
|
||||||
if (!ucl_msgpack_insert_object (parser, key, keylen,
|
if (!ucl_msgpack_insert_object (parser, key, keylen,
|
||||||
parser->cur_obj)) {
|
parser->cur_obj)) {
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1247,7 +1245,9 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
case start_assoc:
|
case start_assoc:
|
||||||
/* Empty container at the end */
|
/* Empty container at the end */
|
||||||
if (len != 0) {
|
if (len != 0) {
|
||||||
ucl_create_err (&parser->err, "invalid non-empty container at the end");
|
ucl_create_err (&parser->err,
|
||||||
|
"invalid non-empty container at the end; len=%zu",
|
||||||
|
(uintmax_t)len);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1255,6 +1255,12 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
parser->cur_obj = ucl_object_new_full (
|
parser->cur_obj = ucl_object_new_full (
|
||||||
state == start_array ? UCL_ARRAY : UCL_OBJECT,
|
state == start_array ? UCL_ARRAY : UCL_OBJECT,
|
||||||
parser->chunks->priority);
|
parser->chunks->priority);
|
||||||
|
|
||||||
|
if (parser->stack == NULL) {
|
||||||
|
ucl_create_err (&parser->err,
|
||||||
|
"read assoc value when no container represented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/* Insert to the previous level container */
|
/* Insert to the previous level container */
|
||||||
if (!ucl_msgpack_insert_object (parser,
|
if (!ucl_msgpack_insert_object (parser,
|
||||||
key, keylen, parser->cur_obj)) {
|
key, keylen, parser->cur_obj)) {
|
||||||
@ -1281,7 +1287,9 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
|
|
||||||
container = parser->stack;
|
container = parser->stack;
|
||||||
|
|
||||||
if (container == NULL) {
|
if (parser->stack == NULL) {
|
||||||
|
ucl_create_err (&parser->err,
|
||||||
|
"read assoc value when no container represented");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1311,8 +1319,12 @@ ucl_msgpack_consume (struct ucl_parser *parser)
|
|||||||
|
|
||||||
/* Rewind to the top level container */
|
/* Rewind to the top level container */
|
||||||
ucl_msgpack_get_next_container (parser);
|
ucl_msgpack_get_next_container (parser);
|
||||||
assert (parser->stack == NULL ||
|
|
||||||
(parser->stack->level & MSGPACK_CONTAINER_BIT) == 0);
|
if (parser->stack != NULL) {
|
||||||
|
ucl_create_err (&parser->err, "incomplete container");
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
556
src/ucl_parser.c
556
src/ucl_parser.c
@ -21,6 +21,7 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
#include "ucl.h"
|
#include "ucl.h"
|
||||||
#include "ucl_internal.h"
|
#include "ucl_internal.h"
|
||||||
#include "ucl_chartable.h"
|
#include "ucl_chartable.h"
|
||||||
@ -44,16 +45,17 @@ struct ucl_parser_saved_state {
|
|||||||
* @param len
|
* @param len
|
||||||
* @return new position in chunk
|
* @return new position in chunk
|
||||||
*/
|
*/
|
||||||
#define ucl_chunk_skipc(chunk, p) do{ \
|
#define ucl_chunk_skipc(chunk, p) \
|
||||||
if (*(p) == '\n') { \
|
do { \
|
||||||
(chunk)->line ++; \
|
if (*(p) == '\n') { \
|
||||||
(chunk)->column = 0; \
|
(chunk)->line ++; \
|
||||||
} \
|
(chunk)->column = 0; \
|
||||||
else (chunk)->column ++; \
|
} \
|
||||||
(p++); \
|
else (chunk)->column ++; \
|
||||||
(chunk)->pos ++; \
|
(p++); \
|
||||||
(chunk)->remain --; \
|
(chunk)->pos ++; \
|
||||||
} while (0)
|
(chunk)->remain --; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
|
ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **err)
|
||||||
@ -87,6 +89,7 @@ ucl_set_err (struct ucl_parser *parser, int code, const char *str, UT_string **e
|
|||||||
}
|
}
|
||||||
|
|
||||||
parser->err_code = code;
|
parser->err_code = code;
|
||||||
|
parser->state = UCL_STATE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -342,7 +345,7 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
|
|||||||
/* Call generic handler */
|
/* Call generic handler */
|
||||||
if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
|
if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
|
||||||
parser->var_data)) {
|
parser->var_data)) {
|
||||||
*out_len += dstlen;
|
*out_len = dstlen;
|
||||||
*found = true;
|
*found = true;
|
||||||
if (need_free) {
|
if (need_free) {
|
||||||
free (dst);
|
free (dst);
|
||||||
@ -459,19 +462,15 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
|
|||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
if (strict && parser->var_handler != NULL) {
|
if (strict && parser->var_handler != NULL) {
|
||||||
size_t var_len = 0;
|
if (parser->var_handler (p, remain, &dst, &dstlen, &need_free,
|
||||||
while (var_len < remain && p[var_len] != '}')
|
|
||||||
var_len ++;
|
|
||||||
|
|
||||||
if (parser->var_handler (p, var_len, &dst, &dstlen, &need_free,
|
|
||||||
parser->var_data)) {
|
parser->var_data)) {
|
||||||
memcpy (d, dst, dstlen);
|
memcpy (d, dst, dstlen);
|
||||||
ret += var_len;
|
ret += remain;
|
||||||
d += dstlen;
|
d += dstlen;
|
||||||
|
found = true;
|
||||||
if (need_free) {
|
if (need_free) {
|
||||||
free (dst);
|
free (dst);
|
||||||
}
|
}
|
||||||
found = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,13 +563,15 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,
|
|||||||
* @param need_unescape need to unescape source (and copy it)
|
* @param need_unescape need to unescape source (and copy it)
|
||||||
* @param need_lowercase need to lowercase value (and copy)
|
* @param need_lowercase need to lowercase value (and copy)
|
||||||
* @param need_expand need to expand variables (and copy as well)
|
* @param need_expand need to expand variables (and copy as well)
|
||||||
|
* @param unescape_squote unescape single quoted string
|
||||||
* @return output length (excluding \0 symbol)
|
* @return output length (excluding \0 symbol)
|
||||||
*/
|
*/
|
||||||
static inline ssize_t
|
static inline ssize_t
|
||||||
ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
||||||
const unsigned char *src, unsigned char **dst,
|
const unsigned char *src, unsigned char **dst,
|
||||||
const char **dst_const, size_t in_len,
|
const char **dst_const, size_t in_len,
|
||||||
bool need_unescape, bool need_lowercase, bool need_expand)
|
bool need_unescape, bool need_lowercase, bool need_expand,
|
||||||
|
bool unescape_squote)
|
||||||
{
|
{
|
||||||
ssize_t ret = -1, tret;
|
ssize_t ret = -1, tret;
|
||||||
unsigned char *tmp;
|
unsigned char *tmp;
|
||||||
@ -593,8 +594,14 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (need_unescape) {
|
if (need_unescape) {
|
||||||
ret = ucl_unescape_json_string (*dst, ret);
|
if (!unescape_squote) {
|
||||||
|
ret = ucl_unescape_json_string (*dst, ret);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ret = ucl_unescape_squoted_string (*dst, ret);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (need_expand) {
|
if (need_expand) {
|
||||||
tmp = *dst;
|
tmp = *dst;
|
||||||
tret = ret;
|
tret = ret;
|
||||||
@ -628,47 +635,83 @@ ucl_copy_or_store_ptr (struct ucl_parser *parser,
|
|||||||
*/
|
*/
|
||||||
static inline ucl_object_t *
|
static inline ucl_object_t *
|
||||||
ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
|
ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,
|
||||||
bool is_array, int level)
|
bool is_array, uint32_t level, bool has_obrace)
|
||||||
{
|
{
|
||||||
struct ucl_stack *st;
|
struct ucl_stack *st;
|
||||||
|
ucl_object_t *nobj;
|
||||||
|
|
||||||
|
if (obj == NULL) {
|
||||||
|
nobj = ucl_object_new_full (is_array ? UCL_ARRAY : UCL_OBJECT, parser->chunks->priority);
|
||||||
|
if (nobj == NULL) {
|
||||||
|
goto enomem0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (obj->type == (is_array ? UCL_OBJECT : UCL_ARRAY)) {
|
||||||
|
/* Bad combination for merge: array and object */
|
||||||
|
ucl_set_err (parser, UCL_EMERGE,
|
||||||
|
"cannot merge an object with an array",
|
||||||
|
&parser->err);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
nobj = obj;
|
||||||
|
nobj->type = is_array ? UCL_ARRAY : UCL_OBJECT;
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_array) {
|
if (!is_array) {
|
||||||
if (obj == NULL) {
|
if (nobj->value.ov == NULL) {
|
||||||
obj = ucl_object_new_full (UCL_OBJECT, parser->chunks->priority);
|
nobj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
|
||||||
}
|
if (nobj->value.ov == NULL) {
|
||||||
else {
|
goto enomem1;
|
||||||
obj->type = UCL_OBJECT;
|
}
|
||||||
}
|
|
||||||
if (obj->value.ov == NULL) {
|
|
||||||
obj->value.ov = ucl_hash_create (parser->flags & UCL_PARSER_KEY_LOWERCASE);
|
|
||||||
}
|
}
|
||||||
parser->state = UCL_STATE_KEY;
|
parser->state = UCL_STATE_KEY;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (obj == NULL) {
|
|
||||||
obj = ucl_object_new_full (UCL_ARRAY, parser->chunks->priority);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
obj->type = UCL_ARRAY;
|
|
||||||
}
|
|
||||||
parser->state = UCL_STATE_VALUE;
|
parser->state = UCL_STATE_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
st = UCL_ALLOC (sizeof (struct ucl_stack));
|
st = UCL_ALLOC (sizeof (struct ucl_stack));
|
||||||
|
|
||||||
if (st == NULL) {
|
if (st == NULL) {
|
||||||
ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
|
goto enomem1;
|
||||||
|
}
|
||||||
|
|
||||||
|
st->obj = nobj;
|
||||||
|
|
||||||
|
if (level >= UINT16_MAX) {
|
||||||
|
ucl_set_err (parser, UCL_ENESTED,
|
||||||
|
"objects are nesting too deep (over 65535 limit)",
|
||||||
&parser->err);
|
&parser->err);
|
||||||
ucl_object_unref (obj);
|
if (nobj != obj) {
|
||||||
|
ucl_object_unref (obj);
|
||||||
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
st->obj = obj;
|
|
||||||
st->level = level;
|
|
||||||
LL_PREPEND (parser->stack, st);
|
|
||||||
parser->cur_obj = obj;
|
|
||||||
|
|
||||||
return obj;
|
st->e.params.level = level;
|
||||||
|
st->e.params.line = parser->chunks->line;
|
||||||
|
st->chunk = parser->chunks;
|
||||||
|
|
||||||
|
if (has_obrace) {
|
||||||
|
st->e.params.flags = UCL_STACK_HAS_OBRACE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
st->e.params.flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
LL_PREPEND (parser->stack, st);
|
||||||
|
parser->cur_obj = nobj;
|
||||||
|
|
||||||
|
return nobj;
|
||||||
|
enomem1:
|
||||||
|
if (nobj != obj)
|
||||||
|
ucl_object_unref (nobj);
|
||||||
|
enomem0:
|
||||||
|
ucl_set_err (parser, UCL_EINTERNAL, "cannot allocate memory for an object",
|
||||||
|
&parser->err);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -969,7 +1012,10 @@ ucl_lex_number (struct ucl_parser *parser,
|
|||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
ucl_lex_json_string (struct ucl_parser *parser,
|
ucl_lex_json_string (struct ucl_parser *parser,
|
||||||
struct ucl_chunk *chunk, bool *need_unescape, bool *ucl_escape, bool *var_expand)
|
struct ucl_chunk *chunk,
|
||||||
|
bool *need_unescape,
|
||||||
|
bool *ucl_escape,
|
||||||
|
bool *var_expand)
|
||||||
{
|
{
|
||||||
const unsigned char *p = chunk->pos;
|
const unsigned char *p = chunk->pos;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
@ -1009,7 +1055,8 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
if (p >= chunk->end) {
|
if (p >= chunk->end) {
|
||||||
ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"unfinished escape character",
|
||||||
&parser->err);
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1035,7 +1082,54 @@ ucl_lex_json_string (struct ucl_parser *parser,
|
|||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
ucl_set_err (parser, UCL_ESYNTAX, "no quote at the end of json string",
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"no quote at the end of json string",
|
||||||
|
&parser->err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process single quoted string
|
||||||
|
* @param parser
|
||||||
|
* @param chunk
|
||||||
|
* @param need_unescape
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
ucl_lex_squoted_string (struct ucl_parser *parser,
|
||||||
|
struct ucl_chunk *chunk, bool *need_unescape)
|
||||||
|
{
|
||||||
|
const unsigned char *p = chunk->pos;
|
||||||
|
unsigned char c;
|
||||||
|
|
||||||
|
while (p < chunk->end) {
|
||||||
|
c = *p;
|
||||||
|
if (c == '\\') {
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
|
||||||
|
if (p >= chunk->end) {
|
||||||
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"unfinished escape character",
|
||||||
|
&parser->err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
*need_unescape = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (c == '\'') {
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_set_err (parser, UCL_ESYNTAX,
|
||||||
|
"no quote at the end of single quoted string",
|
||||||
&parser->err);
|
&parser->err);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1075,15 +1169,26 @@ bool
|
|||||||
ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
|
ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj)
|
||||||
{
|
{
|
||||||
ucl_hash_t *container;
|
ucl_hash_t *container;
|
||||||
ucl_object_t *tobj;
|
ucl_object_t *tobj = NULL, *cur;
|
||||||
char errmsg[256];
|
char errmsg[256];
|
||||||
|
|
||||||
container = parser->stack->obj->value.ov;
|
container = parser->stack->obj->value.ov;
|
||||||
|
|
||||||
tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
|
DL_FOREACH (parser->stack->obj, cur) {
|
||||||
|
tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (cur->value.ov, nobj));
|
||||||
|
|
||||||
|
if (tobj != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (tobj == NULL) {
|
if (tobj == NULL) {
|
||||||
container = ucl_hash_insert_object (container, nobj,
|
container = ucl_hash_insert_object (container, nobj,
|
||||||
parser->flags & UCL_PARSER_KEY_LOWERCASE);
|
parser->flags & UCL_PARSER_KEY_LOWERCASE);
|
||||||
|
if (container == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
nobj->prev = nobj;
|
nobj->prev = nobj;
|
||||||
nobj->next = NULL;
|
nobj->next = NULL;
|
||||||
parser->stack->obj->len ++;
|
parser->stack->obj->len ++;
|
||||||
@ -1102,8 +1207,6 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj
|
|||||||
* - if a new object has bigger priority, then we overwrite an old one
|
* - if a new object has bigger priority, then we overwrite an old one
|
||||||
* - if a new object has lower priority, then we ignore it
|
* - if a new object has lower priority, then we ignore it
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/* Special case for inherited objects */
|
/* Special case for inherited objects */
|
||||||
if (tobj->flags & UCL_OBJECT_INHERITED) {
|
if (tobj->flags & UCL_OBJECT_INHERITED) {
|
||||||
prinew = priold + 1;
|
prinew = priold + 1;
|
||||||
@ -1369,8 +1472,12 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,
|
|||||||
|
|
||||||
/* Create a new object */
|
/* Create a new object */
|
||||||
nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
|
nobj = ucl_object_new_full (UCL_NULL, parser->chunks->priority);
|
||||||
|
if (nobj == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
|
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);
|
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE,
|
||||||
|
false, false);
|
||||||
if (keylen == -1) {
|
if (keylen == -1) {
|
||||||
ucl_object_unref (nobj);
|
ucl_object_unref (nobj);
|
||||||
return false;
|
return false;
|
||||||
@ -1566,7 +1673,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
const unsigned char *p, *c;
|
const unsigned char *p, *c;
|
||||||
ucl_object_t *obj = NULL;
|
ucl_object_t *obj = NULL;
|
||||||
unsigned int stripped_spaces;
|
unsigned int stripped_spaces;
|
||||||
int str_len;
|
ssize_t str_len;
|
||||||
bool need_unescape = false, ucl_escape = false, var_expand = false;
|
bool need_unescape = false, ucl_escape = false, var_expand = false;
|
||||||
|
|
||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
@ -1604,20 +1711,57 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
|
if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
|
||||||
&obj->trash_stack[UCL_TRASH_VALUE],
|
&obj->trash_stack[UCL_TRASH_VALUE],
|
||||||
&obj->value.sv, str_len, need_unescape, false,
|
&obj->value.sv, str_len, need_unescape, false,
|
||||||
var_expand)) == -1) {
|
var_expand, false)) == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
obj->len = str_len;
|
||||||
|
parser->state = UCL_STATE_AFTER_VALUE;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
|
||||||
|
if (!ucl_lex_squoted_string (parser, chunk, &need_unescape)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = ucl_parser_get_container (parser);
|
||||||
|
if (!obj) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_len = chunk->pos - c - 2;
|
||||||
|
obj->type = UCL_STRING;
|
||||||
|
obj->flags |= UCL_OBJECT_SQUOTED;
|
||||||
|
|
||||||
|
if ((str_len = ucl_copy_or_store_ptr (parser, c + 1,
|
||||||
|
&obj->trash_stack[UCL_TRASH_VALUE],
|
||||||
|
&obj->value.sv, str_len, need_unescape, false,
|
||||||
|
var_expand, true)) == -1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
obj->len = str_len;
|
obj->len = str_len;
|
||||||
|
|
||||||
parser->state = UCL_STATE_AFTER_VALUE;
|
parser->state = UCL_STATE_AFTER_VALUE;
|
||||||
p = chunk->pos;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
case '{':
|
case '{':
|
||||||
obj = ucl_parser_get_container (parser);
|
obj = ucl_parser_get_container (parser);
|
||||||
|
if (obj == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/* We have a new object */
|
/* We have a new object */
|
||||||
obj = ucl_parser_add_container (obj, parser, false, parser->stack->level);
|
if (parser->stack) {
|
||||||
|
obj = ucl_parser_add_container (obj, parser, false,
|
||||||
|
parser->stack->e.params.level, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1628,8 +1772,18 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
break;
|
break;
|
||||||
case '[':
|
case '[':
|
||||||
obj = ucl_parser_get_container (parser);
|
obj = ucl_parser_get_container (parser);
|
||||||
|
if (obj == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
/* We have a new array */
|
/* We have a new array */
|
||||||
obj = ucl_parser_add_container (obj, parser, true, parser->stack->level);
|
if (parser->stack) {
|
||||||
|
obj = ucl_parser_add_container (obj, parser, true,
|
||||||
|
parser->stack->e.params.level, true);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1660,8 +1814,8 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
}
|
}
|
||||||
if (*p =='\n') {
|
if (*p =='\n') {
|
||||||
/* Set chunk positions and start multiline parsing */
|
/* Set chunk positions and start multiline parsing */
|
||||||
|
chunk->remain -= p - c + 1;
|
||||||
c += 2;
|
c += 2;
|
||||||
chunk->remain -= p - c;
|
|
||||||
chunk->pos = p + 1;
|
chunk->pos = p + 1;
|
||||||
chunk->column = 0;
|
chunk->column = 0;
|
||||||
chunk->line ++;
|
chunk->line ++;
|
||||||
@ -1677,7 +1831,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
if ((str_len = ucl_copy_or_store_ptr (parser, c,
|
if ((str_len = ucl_copy_or_store_ptr (parser, c,
|
||||||
&obj->trash_stack[UCL_TRASH_VALUE],
|
&obj->trash_stack[UCL_TRASH_VALUE],
|
||||||
&obj->value.sv, str_len - 1, false,
|
&obj->value.sv, str_len - 1, false,
|
||||||
false, var_expand)) == -1) {
|
false, var_expand, false)) == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
obj->len = str_len;
|
obj->len = str_len;
|
||||||
@ -1689,6 +1843,7 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Fallback to ordinary strings */
|
/* Fallback to ordinary strings */
|
||||||
|
/* FALLTHRU */
|
||||||
default:
|
default:
|
||||||
parse_string:
|
parse_string:
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
@ -1729,18 +1884,28 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
obj->len = 0;
|
obj->len = 0;
|
||||||
obj->type = UCL_NULL;
|
obj->type = UCL_NULL;
|
||||||
}
|
}
|
||||||
|
else if (str_len == 3 && memcmp (c, "nan", 3) == 0) {
|
||||||
|
obj->len = 0;
|
||||||
|
obj->type = UCL_FLOAT;
|
||||||
|
obj->value.dv = NAN;
|
||||||
|
}
|
||||||
|
else if (str_len == 3 && memcmp (c, "inf", 3) == 0) {
|
||||||
|
obj->len = 0;
|
||||||
|
obj->type = UCL_FLOAT;
|
||||||
|
obj->value.dv = INFINITY;
|
||||||
|
}
|
||||||
else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
|
else if (!ucl_maybe_parse_boolean (obj, c, str_len)) {
|
||||||
obj->type = UCL_STRING;
|
obj->type = UCL_STRING;
|
||||||
if ((str_len = ucl_copy_or_store_ptr (parser, c,
|
if ((str_len = ucl_copy_or_store_ptr (parser, c,
|
||||||
&obj->trash_stack[UCL_TRASH_VALUE],
|
&obj->trash_stack[UCL_TRASH_VALUE],
|
||||||
&obj->value.sv, str_len, need_unescape,
|
&obj->value.sv, str_len, need_unescape,
|
||||||
false, var_expand)) == -1) {
|
false, var_expand, false)) == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
obj->len = str_len;
|
obj->len = str_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser->state = UCL_STATE_AFTER_VALUE;
|
parser->state = UCL_STATE_AFTER_VALUE;
|
||||||
p = chunk->pos;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
break;
|
break;
|
||||||
@ -1792,6 +1957,17 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
|
|
||||||
/* Pop all nested objects from a stack */
|
/* Pop all nested objects from a stack */
|
||||||
st = parser->stack;
|
st = parser->stack;
|
||||||
|
|
||||||
|
if (!(st->e.params.flags & UCL_STACK_HAS_OBRACE)) {
|
||||||
|
parser->err_code = UCL_EUNPAIRED;
|
||||||
|
ucl_create_err (&parser->err,
|
||||||
|
"%s:%d object closed with } is not opened with { at line %d",
|
||||||
|
chunk->fname ? chunk->fname : "memory",
|
||||||
|
parser->chunks->line, st->e.params.line);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
parser->stack = st->next;
|
parser->stack = st->next;
|
||||||
UCL_FREE (sizeof (struct ucl_stack), st);
|
UCL_FREE (sizeof (struct ucl_stack), st);
|
||||||
|
|
||||||
@ -1802,9 +1978,13 @@ ucl_parse_after_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
|||||||
while (parser->stack != NULL) {
|
while (parser->stack != NULL) {
|
||||||
st = parser->stack;
|
st = parser->stack;
|
||||||
|
|
||||||
if (st->next == NULL || st->next->level == st->level) {
|
if (st->next == NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
else if (st->next->e.params.level == st->e.params.level) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
parser->stack = st->next;
|
parser->stack = st->next;
|
||||||
parser->cur_obj = st->obj;
|
parser->cur_obj = st->obj;
|
||||||
@ -2180,6 +2360,8 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
bool seen_obrace = false;
|
||||||
|
|
||||||
/* Skip any spaces */
|
/* Skip any spaces */
|
||||||
while (p < chunk->end && ucl_test_character (*p,
|
while (p < chunk->end && ucl_test_character (*p,
|
||||||
UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
||||||
@ -2188,23 +2370,33 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
|
|
||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
|
|
||||||
if (*p == '[') {
|
if (p < chunk->end) {
|
||||||
parser->state = UCL_STATE_VALUE;
|
if (*p == '[') {
|
||||||
ucl_chunk_skipc (chunk, p);
|
parser->state = UCL_STATE_VALUE;
|
||||||
}
|
|
||||||
else {
|
|
||||||
parser->state = UCL_STATE_KEY;
|
|
||||||
if (*p == '{') {
|
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
seen_obrace = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
if (*p == '{') {
|
||||||
|
ucl_chunk_skipc (chunk, p);
|
||||||
|
parser->state = UCL_STATE_KEY_OBRACE;
|
||||||
|
seen_obrace = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
parser->state = UCL_STATE_KEY;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parser->top_obj == NULL) {
|
if (parser->top_obj == NULL) {
|
||||||
if (parser->state == UCL_STATE_VALUE) {
|
if (parser->state == UCL_STATE_VALUE) {
|
||||||
obj = ucl_parser_add_container (NULL, parser, true, 0);
|
obj = ucl_parser_add_container (NULL, parser, true, 0,
|
||||||
|
seen_obrace);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
obj = ucl_parser_add_container (NULL, parser, false, 0);
|
obj = ucl_parser_add_container (NULL, parser, false, 0,
|
||||||
|
seen_obrace);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
@ -2218,6 +2410,7 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case UCL_STATE_KEY:
|
case UCL_STATE_KEY:
|
||||||
|
case UCL_STATE_KEY_OBRACE:
|
||||||
/* Skip any spaces */
|
/* Skip any spaces */
|
||||||
while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
while (p < chunk->end && ucl_test_character (*p, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
||||||
ucl_chunk_skipc (chunk, p);
|
ucl_chunk_skipc (chunk, p);
|
||||||
@ -2240,6 +2433,7 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_of_object) {
|
if (end_of_object) {
|
||||||
p = chunk->pos;
|
p = chunk->pos;
|
||||||
parser->state = UCL_STATE_AFTER_VALUE;
|
parser->state = UCL_STATE_AFTER_VALUE;
|
||||||
@ -2248,8 +2442,11 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
else if (parser->state != UCL_STATE_MACRO_NAME) {
|
else if (parser->state != UCL_STATE_MACRO_NAME) {
|
||||||
if (next_key && parser->stack->obj->type == UCL_OBJECT) {
|
if (next_key && parser->stack->obj->type == UCL_OBJECT) {
|
||||||
/* Parse more keys and nest objects accordingly */
|
/* Parse more keys and nest objects accordingly */
|
||||||
obj = ucl_parser_add_container (parser->cur_obj, parser, false,
|
obj = ucl_parser_add_container (parser->cur_obj,
|
||||||
parser->stack->level + 1);
|
parser,
|
||||||
|
false,
|
||||||
|
parser->stack->e.params.level + 1,
|
||||||
|
parser->state == UCL_STATE_KEY_OBRACE);
|
||||||
if (obj == NULL) {
|
if (obj == NULL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2301,7 +2498,8 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
if (!ucl_skip_macro_as_comment (parser, chunk)) {
|
if (!ucl_skip_macro_as_comment (parser, chunk)) {
|
||||||
/* We have invalid macro */
|
/* We have invalid macro */
|
||||||
ucl_create_err (&parser->err,
|
ucl_create_err (&parser->err,
|
||||||
"error on line %d at column %d: invalid macro",
|
"error at %s:%d at column %d: invalid macro",
|
||||||
|
chunk->fname ? chunk->fname : "memory",
|
||||||
chunk->line,
|
chunk->line,
|
||||||
chunk->column);
|
chunk->column);
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
@ -2324,8 +2522,9 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
HASH_FIND (hh, parser->macroes, c, macro_len, macro);
|
HASH_FIND (hh, parser->macroes, c, macro_len, macro);
|
||||||
if (macro == NULL) {
|
if (macro == NULL) {
|
||||||
ucl_create_err (&parser->err,
|
ucl_create_err (&parser->err,
|
||||||
"error on line %d at column %d: "
|
"error at %s:%d at column %d: "
|
||||||
"unknown macro: '%.*s', character: '%c'",
|
"unknown macro: '%.*s', character: '%c'",
|
||||||
|
chunk->fname ? chunk->fname : "memory",
|
||||||
chunk->line,
|
chunk->line,
|
||||||
chunk->column,
|
chunk->column,
|
||||||
(int) (p - c),
|
(int) (p - c),
|
||||||
@ -2341,7 +2540,8 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
else {
|
else {
|
||||||
/* We have invalid macro name */
|
/* We have invalid macro name */
|
||||||
ucl_create_err (&parser->err,
|
ucl_create_err (&parser->err,
|
||||||
"error on line %d at column %d: invalid macro name",
|
"error at %s:%d at column %d: invalid macro name",
|
||||||
|
chunk->fname ? chunk->fname : "memory",
|
||||||
chunk->line,
|
chunk->line,
|
||||||
chunk->column);
|
chunk->column);
|
||||||
parser->state = UCL_STATE_ERROR;
|
parser->state = UCL_STATE_ERROR;
|
||||||
@ -2440,9 +2640,43 @@ ucl_state_machine (struct ucl_parser *parser)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parser->stack != NULL && parser->state != UCL_STATE_ERROR) {
|
||||||
|
struct ucl_stack *st;
|
||||||
|
bool has_error = false;
|
||||||
|
|
||||||
|
LL_FOREACH (parser->stack, st) {
|
||||||
|
if (st->chunk != parser->chunks) {
|
||||||
|
break; /* Not our chunk, give up */
|
||||||
|
}
|
||||||
|
if (st->e.params.flags & UCL_STACK_HAS_OBRACE) {
|
||||||
|
if (parser->err == NULL) {
|
||||||
|
utstring_new (parser->err);
|
||||||
|
}
|
||||||
|
|
||||||
|
utstring_printf (parser->err, "%s:%d unmatched open brace at %d; ",
|
||||||
|
chunk->fname ? chunk->fname : "memory",
|
||||||
|
parser->chunks->line,
|
||||||
|
st->e.params.line);
|
||||||
|
|
||||||
|
has_error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_error) {
|
||||||
|
parser->err_code = UCL_EUNPAIRED;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UPRM_SAFE(fn, a, b, c, el) do { \
|
||||||
|
if (!fn(a, b, c, a)) \
|
||||||
|
goto el; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
struct ucl_parser*
|
struct ucl_parser*
|
||||||
ucl_parser_new (int flags)
|
ucl_parser_new (int flags)
|
||||||
{
|
{
|
||||||
@ -2455,12 +2689,12 @@ ucl_parser_new (int flags)
|
|||||||
|
|
||||||
memset (parser, 0, sizeof (struct ucl_parser));
|
memset (parser, 0, sizeof (struct ucl_parser));
|
||||||
|
|
||||||
ucl_parser_register_macro (parser, "include", ucl_include_handler, parser);
|
UPRM_SAFE(ucl_parser_register_macro, parser, "include", ucl_include_handler, e0);
|
||||||
ucl_parser_register_macro (parser, "try_include", ucl_try_include_handler, parser);
|
UPRM_SAFE(ucl_parser_register_macro, parser, "try_include", ucl_try_include_handler, e0);
|
||||||
ucl_parser_register_macro (parser, "includes", ucl_includes_handler, parser);
|
UPRM_SAFE(ucl_parser_register_macro, parser, "includes", ucl_includes_handler, e0);
|
||||||
ucl_parser_register_macro (parser, "priority", ucl_priority_handler, parser);
|
UPRM_SAFE(ucl_parser_register_macro, parser, "priority", ucl_priority_handler, e0);
|
||||||
ucl_parser_register_macro (parser, "load", ucl_load_handler, parser);
|
UPRM_SAFE(ucl_parser_register_macro, parser, "load", ucl_load_handler, e0);
|
||||||
ucl_parser_register_context_macro (parser, "inherit", ucl_inherit_handler, parser);
|
UPRM_SAFE(ucl_parser_register_context_macro, parser, "inherit", ucl_inherit_handler, e0);
|
||||||
|
|
||||||
parser->flags = flags;
|
parser->flags = flags;
|
||||||
parser->includepaths = NULL;
|
parser->includepaths = NULL;
|
||||||
@ -2475,6 +2709,9 @@ ucl_parser_new (int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
return parser;
|
return parser;
|
||||||
|
e0:
|
||||||
|
ucl_parser_free(parser);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -2489,49 +2726,69 @@ ucl_parser_set_default_priority (struct ucl_parser *parser, unsigned prio)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
|
ucl_parser_get_default_priority (struct ucl_parser *parser)
|
||||||
|
{
|
||||||
|
if (parser == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return parser->default_priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
|
ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
|
||||||
ucl_macro_handler handler, void* ud)
|
ucl_macro_handler handler, void* ud)
|
||||||
{
|
{
|
||||||
struct ucl_macro *new;
|
struct ucl_macro *new;
|
||||||
|
|
||||||
if (macro == NULL || handler == NULL) {
|
if (macro == NULL || handler == NULL) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = UCL_ALLOC (sizeof (struct ucl_macro));
|
new = UCL_ALLOC (sizeof (struct ucl_macro));
|
||||||
if (new == NULL) {
|
if (new == NULL) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (new, 0, sizeof (struct ucl_macro));
|
memset (new, 0, sizeof (struct ucl_macro));
|
||||||
new->h.handler = handler;
|
new->h.handler = handler;
|
||||||
new->name = strdup (macro);
|
new->name = strdup (macro);
|
||||||
|
if (new->name == NULL) {
|
||||||
|
UCL_FREE (sizeof (struct ucl_macro), new);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
new->ud = ud;
|
new->ud = ud;
|
||||||
HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
|
HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
bool
|
||||||
ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
|
ucl_parser_register_context_macro (struct ucl_parser *parser, const char *macro,
|
||||||
ucl_context_macro_handler handler, void* ud)
|
ucl_context_macro_handler handler, void* ud)
|
||||||
{
|
{
|
||||||
struct ucl_macro *new;
|
struct ucl_macro *new;
|
||||||
|
|
||||||
if (macro == NULL || handler == NULL) {
|
if (macro == NULL || handler == NULL) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = UCL_ALLOC (sizeof (struct ucl_macro));
|
new = UCL_ALLOC (sizeof (struct ucl_macro));
|
||||||
if (new == NULL) {
|
if (new == NULL) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset (new, 0, sizeof (struct ucl_macro));
|
memset (new, 0, sizeof (struct ucl_macro));
|
||||||
new->h.context_handler = handler;
|
new->h.context_handler = handler;
|
||||||
new->name = strdup (macro);
|
new->name = strdup (macro);
|
||||||
|
if (new->name == NULL) {
|
||||||
|
UCL_FREE (sizeof (struct ucl_macro), new);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
new->ud = ud;
|
new->ud = ud;
|
||||||
new->is_context = true;
|
new->is_context = true;
|
||||||
HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
|
HASH_ADD_KEYPTR (hh, parser->macroes, new->name, strlen (new->name), new);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -2602,6 +2859,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
enum ucl_parse_type parse_type)
|
enum ucl_parse_type parse_type)
|
||||||
{
|
{
|
||||||
struct ucl_chunk *chunk;
|
struct ucl_chunk *chunk;
|
||||||
|
struct ucl_parser_special_handler *special_handler;
|
||||||
|
|
||||||
if (parser == NULL) {
|
if (parser == NULL) {
|
||||||
return false;
|
return false;
|
||||||
@ -2619,6 +2877,36 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memset (chunk, 0, sizeof (*chunk));
|
||||||
|
|
||||||
|
/* Apply all matching handlers from the first to the last */
|
||||||
|
LL_FOREACH (parser->special_handlers, special_handler) {
|
||||||
|
if ((special_handler->flags & UCL_SPECIAL_HANDLER_PREPROCESS_ALL) ||
|
||||||
|
(len >= special_handler->magic_len &&
|
||||||
|
memcmp (data, special_handler->magic, special_handler->magic_len) == 0)) {
|
||||||
|
unsigned char *ndata = NULL;
|
||||||
|
size_t nlen = 0;
|
||||||
|
|
||||||
|
if (!special_handler->handler (parser, data, len, &ndata, &nlen,
|
||||||
|
special_handler->user_data)) {
|
||||||
|
ucl_create_err (&parser->err, "call for external handler failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_parser_special_handler_chain *nchain;
|
||||||
|
nchain = UCL_ALLOC (sizeof (*nchain));
|
||||||
|
nchain->begin = ndata;
|
||||||
|
nchain->len = nlen;
|
||||||
|
nchain->special_handler = special_handler;
|
||||||
|
|
||||||
|
/* Free order is reversed */
|
||||||
|
LL_PREPEND (chunk->special_handlers, nchain);
|
||||||
|
|
||||||
|
data = ndata;
|
||||||
|
len = nlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (parse_type == UCL_PARSE_AUTO && len > 0) {
|
if (parse_type == UCL_PARSE_AUTO && len > 0) {
|
||||||
/* We need to detect parse type by the first symbol */
|
/* We need to detect parse type by the first symbol */
|
||||||
if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
|
if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) {
|
||||||
@ -2641,6 +2929,11 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
chunk->priority = priority;
|
chunk->priority = priority;
|
||||||
chunk->strategy = strat;
|
chunk->strategy = strat;
|
||||||
chunk->parse_type = parse_type;
|
chunk->parse_type = parse_type;
|
||||||
|
|
||||||
|
if (parser->cur_file) {
|
||||||
|
chunk->fname = strdup (parser->cur_file);
|
||||||
|
}
|
||||||
|
|
||||||
LL_PREPEND (parser->chunks, chunk);
|
LL_PREPEND (parser->chunks, chunk);
|
||||||
parser->recursion ++;
|
parser->recursion ++;
|
||||||
|
|
||||||
@ -2706,6 +2999,41 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
|||||||
parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
|
parser->default_priority, UCL_DUPLICATE_APPEND, UCL_PARSE_UCL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
ucl_parser_insert_chunk (struct ucl_parser *parser, const unsigned char *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (parser == NULL || parser->top_obj == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool res;
|
||||||
|
struct ucl_chunk *chunk;
|
||||||
|
|
||||||
|
int state = parser->state;
|
||||||
|
parser->state = UCL_STATE_INIT;
|
||||||
|
|
||||||
|
/* Prevent inserted chunks from unintentionally closing the current object */
|
||||||
|
if (parser->stack != NULL && parser->stack->next != NULL) {
|
||||||
|
parser->stack->e.params.level = parser->stack->next->e.params.level;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ucl_parser_add_chunk_full (parser, data, len, parser->chunks->priority,
|
||||||
|
parser->chunks->strategy, parser->chunks->parse_type);
|
||||||
|
|
||||||
|
/* Remove chunk from the stack */
|
||||||
|
chunk = parser->chunks;
|
||||||
|
if (chunk != NULL) {
|
||||||
|
parser->chunks = chunk->next;
|
||||||
|
ucl_chunk_free (chunk);
|
||||||
|
parser->recursion --;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->state = state;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
|
ucl_parser_add_string_priority (struct ucl_parser *parser, const char *data,
|
||||||
size_t len, unsigned priority)
|
size_t len, unsigned priority)
|
||||||
@ -2755,3 +3083,55 @@ ucl_set_include_path (struct ucl_parser *parser, ucl_object_t *paths)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char ucl_parser_chunk_peek (struct ucl_parser *parser)
|
||||||
|
{
|
||||||
|
if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
|
||||||
|
parser->chunks->pos == parser->chunks->end) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return( *parser->chunks->pos );
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ucl_parser_chunk_skip (struct ucl_parser *parser)
|
||||||
|
{
|
||||||
|
if (parser == NULL || parser->chunks == NULL || parser->chunks->pos == NULL || parser->chunks->end == NULL ||
|
||||||
|
parser->chunks->pos == parser->chunks->end) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const unsigned char *p = parser->chunks->pos;
|
||||||
|
ucl_chunk_skipc( parser->chunks, p );
|
||||||
|
if( parser->chunks->pos != NULL ) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_object_t*
|
||||||
|
ucl_parser_get_current_stack_object (struct ucl_parser *parser, unsigned int depth)
|
||||||
|
{
|
||||||
|
ucl_object_t *obj;
|
||||||
|
|
||||||
|
if (parser == NULL || parser->stack == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_stack *stack = parser->stack;
|
||||||
|
if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( unsigned int i = 0; i < depth; ++i )
|
||||||
|
{
|
||||||
|
stack = stack->next;
|
||||||
|
if(stack == NULL || stack->obj == NULL || ucl_object_type (stack->obj) != UCL_OBJECT)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj = ucl_object_ref (stack->obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,16 @@ static bool ucl_schema_validate (const ucl_object_t *schema,
|
|||||||
/*
|
/*
|
||||||
* Create validation error
|
* Create validation error
|
||||||
*/
|
*/
|
||||||
static void
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
static inline void
|
||||||
|
ucl_schema_create_error (struct ucl_schema_error *err,
|
||||||
|
enum ucl_schema_error_code code, const ucl_object_t *obj,
|
||||||
|
const char *fmt, ...)
|
||||||
|
__attribute__ (( format( printf, 4, 5) ));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void
|
||||||
ucl_schema_create_error (struct ucl_schema_error *err,
|
ucl_schema_create_error (struct ucl_schema_error *err,
|
||||||
enum ucl_schema_error_code code, const ucl_object_t *obj,
|
enum ucl_schema_error_code code, const ucl_object_t *obj,
|
||||||
const char *fmt, ...)
|
const char *fmt, ...)
|
||||||
@ -235,20 +244,22 @@ ucl_schema_validate_object (const ucl_object_t *schema,
|
|||||||
/* Additional properties */
|
/* Additional properties */
|
||||||
if (!allow_additional || additional_schema != NULL) {
|
if (!allow_additional || additional_schema != NULL) {
|
||||||
/* Check if we have exactly the same properties in schema and object */
|
/* Check if we have exactly the same properties in schema and object */
|
||||||
iter = NULL;
|
iter = ucl_object_iterate_new (obj);
|
||||||
prop = ucl_object_lookup (schema, "properties");
|
prop = ucl_object_lookup (schema, "properties");
|
||||||
while ((elt = ucl_object_iterate (obj, &iter, true)) != NULL) {
|
while ((elt = ucl_object_iterate_safe (iter, true)) != NULL) {
|
||||||
found = ucl_object_lookup (prop, ucl_object_key (elt));
|
found = ucl_object_lookup (prop, ucl_object_key (elt));
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
/* Try patternProperties */
|
/* Try patternProperties */
|
||||||
piter = NULL;
|
|
||||||
pat = ucl_object_lookup (schema, "patternProperties");
|
pat = ucl_object_lookup (schema, "patternProperties");
|
||||||
while ((pelt = ucl_object_iterate (pat, &piter, true)) != NULL) {
|
piter = ucl_object_iterate_new (pat);
|
||||||
|
while ((pelt = ucl_object_iterate_safe (piter, true)) != NULL) {
|
||||||
found = ucl_schema_test_pattern (obj, ucl_object_key (pelt), true);
|
found = ucl_schema_test_pattern (obj, ucl_object_key (pelt), true);
|
||||||
if (found != NULL) {
|
if (found != NULL) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ucl_object_iterate_free (piter);
|
||||||
|
piter = NULL;
|
||||||
}
|
}
|
||||||
if (found == NULL) {
|
if (found == NULL) {
|
||||||
if (!allow_additional) {
|
if (!allow_additional) {
|
||||||
@ -267,6 +278,8 @@ ucl_schema_validate_object (const ucl_object_t *schema,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ucl_object_iterate_free (iter);
|
||||||
|
iter = NULL;
|
||||||
}
|
}
|
||||||
/* Required properties */
|
/* Required properties */
|
||||||
if (required != NULL) {
|
if (required != NULL) {
|
||||||
@ -311,7 +324,7 @@ ucl_schema_validate_number (const ucl_object_t *schema,
|
|||||||
if (fabs (remainder (val, constraint)) > alpha) {
|
if (fabs (remainder (val, constraint)) > alpha) {
|
||||||
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
||||||
"number %.4f is not multiple of %.4f, remainder is %.7f",
|
"number %.4f is not multiple of %.4f, remainder is %.7f",
|
||||||
val, constraint);
|
val, constraint, remainder (val, constraint));
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -371,7 +384,7 @@ ucl_schema_validate_string (const ucl_object_t *schema,
|
|||||||
constraint = ucl_object_toint (elt);
|
constraint = ucl_object_toint (elt);
|
||||||
if (obj->len > constraint) {
|
if (obj->len > constraint) {
|
||||||
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
||||||
"string is too big: %.3f, maximum is: %.3f",
|
"string is too big: %u, maximum is: %" PRId64,
|
||||||
obj->len, constraint);
|
obj->len, constraint);
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
@ -382,7 +395,7 @@ ucl_schema_validate_string (const ucl_object_t *schema,
|
|||||||
constraint = ucl_object_toint (elt);
|
constraint = ucl_object_toint (elt);
|
||||||
if (obj->len < constraint) {
|
if (obj->len < constraint) {
|
||||||
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
ucl_schema_create_error (err, UCL_SCHEMA_CONSTRAINT, obj,
|
||||||
"string is too short: %.3f, minimum is: %.3f",
|
"string is too short: %u, minimum is: %" PRId64,
|
||||||
obj->len, constraint);
|
obj->len, constraint);
|
||||||
ret = false;
|
ret = false;
|
||||||
break;
|
break;
|
||||||
|
786
src/ucl_util.c
786
src/ucl_util.c
File diff suppressed because it is too large
Load Diff
2
tests/.gitignore
vendored
2
tests/.gitignore
vendored
@ -4,5 +4,7 @@
|
|||||||
|
|
||||||
test_basic
|
test_basic
|
||||||
test_generate
|
test_generate
|
||||||
|
test_msgpack
|
||||||
test_schema
|
test_schema
|
||||||
test_speed
|
test_speed
|
||||||
|
test_streamline
|
||||||
|
@ -16,7 +16,7 @@ for _tin in ${TEST_DIR}/basic/*.in ; do
|
|||||||
diff -s $_out $_t.res -u 2>/dev/null
|
diff -s $_out $_t.res -u 2>/dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
rm $_out
|
rm $_out
|
||||||
echo "Test: $_t output missmatch"
|
echo "Test: $_t output mismatch"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
@ -6,4 +6,4 @@ key = value_orig;
|
|||||||
.include(priority=1) "${CURDIR}/include_dir/pri1.conf"
|
.include(priority=1) "${CURDIR}/include_dir/pri1.conf"
|
||||||
.include(priority=2) "${CURDIR}/include_dir/pri2.conf"
|
.include(priority=2) "${CURDIR}/include_dir/pri2.conf"
|
||||||
|
|
||||||
.include(try=true) "${CURDIR}/include_dir/invalid.conf"
|
# No longer valid! .include(try=true) "${CURDIR}/include_dir/invalid.conf"
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
# issue 112
|
|
||||||
[[0
|
|
@ -1,5 +0,0 @@
|
|||||||
[
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
]
|
|
||||||
]
|
|
@ -1,2 +0,0 @@
|
|||||||
[9
|
|
||||||
{0 [[0
|
|
@ -1,10 +0,0 @@
|
|||||||
[
|
|
||||||
9,
|
|
||||||
{
|
|
||||||
0 [
|
|
||||||
[
|
|
||||||
0,
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
@ -16,8 +16,8 @@ array = [10]
|
|||||||
array1 = [10]
|
array1 = [10]
|
||||||
.include(prefix=true; key="prefix") "$CURDIR/9.inc"
|
.include(prefix=true; key="prefix") "$CURDIR/9.inc"
|
||||||
.include(prefix=true; key="prefix2"; target="array"; glob=true) "$CURDIR/9.inc"
|
.include(prefix=true; key="prefix2"; target="array"; glob=true) "$CURDIR/9.inc"
|
||||||
|
.include(prefix=true; key="prefix3"; target="array"; glob=true) "$CURDIR/9.inc"
|
||||||
.include(prefix=true; key="prefix1"; target="array"; glob=true) "$CURDIR/9.inc"
|
.include(prefix=true; key="prefix1"; target="array"; glob=true) "$CURDIR/9.inc"
|
||||||
.include(prefix=true; key="array"; target="array"; glob=true) "$CURDIR/9.inc"
|
.include(prefix=true; key="array"; target="array"; glob=true) "$CURDIR/9.inc"
|
||||||
.include(prefix=true; key="array1"; glob=true) "$CURDIR/9.inc"
|
|
||||||
.include(prefix=true; key="prefix"; glob=true) "$CURDIR/9.inc"
|
.include(prefix=true; key="prefix"; glob=true) "$CURDIR/9.inc"
|
||||||
.try_include "/non/existent"
|
.try_include "/non/existent"
|
||||||
|
@ -18,9 +18,6 @@ array [
|
|||||||
]
|
]
|
||||||
array1 [
|
array1 [
|
||||||
10,
|
10,
|
||||||
{
|
|
||||||
key1 = "value";
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
prefix {
|
prefix {
|
||||||
key1 = "value";
|
key1 = "value";
|
||||||
@ -31,4 +28,9 @@ prefix2 [
|
|||||||
key1 = "value";
|
key1 = "value";
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
prefix3 [
|
||||||
|
{
|
||||||
|
key1 = "value";
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
8
tests/basic/squote.in
Normal file
8
tests/basic/squote.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
a = 'b';
|
||||||
|
b = 'b\n\'a'
|
||||||
|
c = ''
|
||||||
|
d = '\
|
||||||
|
aaa';
|
||||||
|
e = '"';
|
||||||
|
f = '\0\e\\\\\\\\\
|
||||||
|
\'';
|
7
tests/basic/squote.res
Normal file
7
tests/basic/squote.res
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
a = 'b';
|
||||||
|
b = 'b\n\'a';
|
||||||
|
c = '';
|
||||||
|
d = 'aaa';
|
||||||
|
e = '"';
|
||||||
|
f = '\0\e\\\\\\\\\'';
|
||||||
|
|
25
tests/fuzzers/ucl_add_string_fuzzer.c
Normal file
25
tests/fuzzers/ucl_add_string_fuzzer.c
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "ucl.h"
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
// If size is 0 we need a null-terminated string.
|
||||||
|
// We dont null-terminate the string and by the design
|
||||||
|
// of the API passing 0 as size with non null-terminated string
|
||||||
|
// gives undefined behavior.
|
||||||
|
if(size==0){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
parser = ucl_parser_new(0);
|
||||||
|
|
||||||
|
ucl_parser_add_string(parser, (char *)data, size);
|
||||||
|
|
||||||
|
if (ucl_parser_get_error(parser) != NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ucl_parser_free (parser);
|
||||||
|
return 0;
|
||||||
|
}
|
29
tests/fuzzers/ucl_msgpack_fuzzer.c
Normal file
29
tests/fuzzers/ucl_msgpack_fuzzer.c
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "ucl.h"
|
||||||
|
#include "ucl_internal.h"
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
typedef ucl_object_t* (*ucl_msgpack_test)(void);
|
||||||
|
|
||||||
|
|
||||||
|
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
||||||
|
|
||||||
|
if(size<3){
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ucl_parser *parser;
|
||||||
|
|
||||||
|
ucl_object_t *obj = ucl_object_new_full (UCL_OBJECT, 2);
|
||||||
|
obj->type = UCL_OBJECT;
|
||||||
|
|
||||||
|
parser = ucl_parser_new(UCL_PARSER_KEY_LOWERCASE);
|
||||||
|
parser->stack = NULL;
|
||||||
|
|
||||||
|
bool res = ucl_parser_add_chunk_full(parser, (const unsigned char*)data, size, 0, UCL_DUPLICATE_APPEND, UCL_PARSE_MSGPACK);
|
||||||
|
|
||||||
|
ucl_parser_free (parser);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -6,7 +6,7 @@ $PROG ${TEST_OUT_DIR}/generate.out
|
|||||||
diff -s ${TEST_OUT_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
|
diff -s ${TEST_OUT_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
rm ${TEST_OUT_DIR}/generate.out
|
rm ${TEST_OUT_DIR}/generate.out
|
||||||
echo "Test: generate.res output missmatch"
|
echo "Test: generate.res output mismatch"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
rm ${TEST_OUT_DIR}/generate.out
|
rm ${TEST_OUT_DIR}/generate.out
|
||||||
|
@ -19,7 +19,7 @@ for _tin in ${TEST_DIR}/*.in ; do
|
|||||||
diff -s $_t.out $_t.res -u 2>/dev/null
|
diff -s $_t.out $_t.res -u 2>/dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
rm $_t.out
|
rm $_t.out
|
||||||
echo "Test: $_t output missmatch"
|
echo "Test: $_t output mismatch"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -31,7 +31,7 @@ if [ $# -gt 2 ] ; then
|
|||||||
diff -s ${TEST_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
|
diff -s ${TEST_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
rm ${TEST_DIR}/generate.out
|
rm ${TEST_DIR}/generate.out
|
||||||
echo "Test: generate.res output missmatch"
|
echo "Test: generate.res output mismatch"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
rm ${TEST_DIR}/generate.out
|
rm ${TEST_DIR}/generate.out
|
||||||
|
@ -6,7 +6,7 @@ $PROG ${TEST_OUT_DIR}/streamline.out
|
|||||||
diff -s ${TEST_OUT_DIR}/streamline.out ${TEST_DIR}/streamline.res -u 2>/dev/null
|
diff -s ${TEST_OUT_DIR}/streamline.out ${TEST_DIR}/streamline.res -u 2>/dev/null
|
||||||
if [ $? -ne 0 ] ; then
|
if [ $? -ne 0 ] ; then
|
||||||
rm ${TEST_OUT_DIR}/streamline.out
|
rm ${TEST_OUT_DIR}/streamline.out
|
||||||
echo "Test: streamline.res output missmatch"
|
echo "Test: streamline.res output mismatch"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
rm ${TEST_OUT_DIR}/streamline.out
|
rm ${TEST_OUT_DIR}/streamline.out
|
@ -40,10 +40,10 @@ main (int argc, char **argv)
|
|||||||
const char *fname_in = NULL, *fname_out = NULL;
|
const char *fname_in = NULL, *fname_out = NULL;
|
||||||
int ret = 0, opt, json = 0, compact = 0, yaml = 0,
|
int ret = 0, opt, json = 0, compact = 0, yaml = 0,
|
||||||
save_comments = 0, skip_macro = 0,
|
save_comments = 0, skip_macro = 0,
|
||||||
flags, fd_out, fd_in, use_fd = 0;
|
flags, fd_out, fd_in, use_fd = 0, msgpack_input = 0;
|
||||||
struct ucl_emitter_functions *func;
|
struct ucl_emitter_functions *func;
|
||||||
|
|
||||||
while ((opt = getopt(argc, argv, "fjcyCM")) != -1) {
|
while ((opt = getopt(argc, argv, "fjcyCMm")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'j':
|
case 'j':
|
||||||
json = 1;
|
json = 1;
|
||||||
@ -60,6 +60,9 @@ main (int argc, char **argv)
|
|||||||
case 'M':
|
case 'M':
|
||||||
skip_macro = true;
|
skip_macro = true;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
msgpack_input = 1;
|
||||||
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
use_fd = true;
|
use_fd = true;
|
||||||
break;
|
break;
|
||||||
@ -145,7 +148,9 @@ main (int argc, char **argv)
|
|||||||
exit (EXIT_FAILURE);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ucl_parser_add_chunk (parser, (const unsigned char *)inbuf, r);
|
ucl_parser_add_chunk_full (parser, (const unsigned char *)inbuf, r,
|
||||||
|
0, UCL_DUPLICATE_APPEND,
|
||||||
|
msgpack_input ? UCL_PARSE_MSGPACK : UCL_PARSE_UCL);
|
||||||
fclose (in);
|
fclose (in);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -106,7 +106,7 @@ main (int argc, char **argv)
|
|||||||
cur = ucl_object_fromstring ("Ебв"); /* UTF8 */
|
cur = ucl_object_fromstring ("Ебв"); /* UTF8 */
|
||||||
ucl_array_prepend (ar1, cur);
|
ucl_array_prepend (ar1, cur);
|
||||||
/*
|
/*
|
||||||
* This is ususally broken or fragile as utf collate is far from perfect
|
* This is usually broken or fragile as utf collate is far from perfect
|
||||||
cur = ucl_object_fromstring ("ёбв");
|
cur = ucl_object_fromstring ("ёбв");
|
||||||
ucl_array_prepend (ar1, cur);
|
ucl_array_prepend (ar1, cur);
|
||||||
cur = ucl_object_fromstring ("Ёбв"); // hello to @bapt
|
cur = ucl_object_fromstring ("Ёбв"); // hello to @bapt
|
||||||
@ -240,31 +240,40 @@ main (int argc, char **argv)
|
|||||||
/* Test iteration */
|
/* Test iteration */
|
||||||
it = ucl_object_iterate_new (obj);
|
it = ucl_object_iterate_new (obj);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
/* key0 = 0.1 */
|
/* key0 = 0.1 */
|
||||||
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
/* key1 = "" */
|
/* key1 = "" */
|
||||||
assert (ucl_object_type (it_obj) == UCL_STRING);
|
assert (ucl_object_type (it_obj) == UCL_STRING);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
/* key2 = "" */
|
/* key2 = "" */
|
||||||
assert (ucl_object_type (it_obj) == UCL_STRING);
|
assert (ucl_object_type (it_obj) == UCL_STRING);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
/* key3 = "" */
|
/* key3 = "" */
|
||||||
assert (ucl_object_type (it_obj) == UCL_STRING);
|
assert (ucl_object_type (it_obj) == UCL_STRING);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
/* key4 = ([float, int, float], boolean) */
|
/* key4 = ([float, int, float], boolean) */
|
||||||
ucl_object_iterate_reset (it, it_obj);
|
ucl_object_iterate_reset (it, it_obj);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
assert (ucl_object_type (it_obj) == UCL_INT);
|
assert (ucl_object_type (it_obj) == UCL_INT);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
assert (ucl_object_type (it_obj) == UCL_FLOAT);
|
||||||
it_obj = ucl_object_iterate_safe (it, true);
|
it_obj = ucl_object_iterate_safe (it, true);
|
||||||
|
assert (!ucl_object_iter_chk_excpn (it));
|
||||||
assert (ucl_object_type (it_obj) == UCL_BOOLEAN);
|
assert (ucl_object_type (it_obj) == UCL_BOOLEAN);
|
||||||
ucl_object_iterate_free (it);
|
ucl_object_iterate_free (it);
|
||||||
|
|
||||||
fn = ucl_object_emit_memory_funcs (&emitted);
|
fn = ucl_object_emit_memory_funcs ((void **)&emitted);
|
||||||
assert (ucl_object_emit_full (obj, UCL_EMIT_CONFIG, fn, comments));
|
assert (ucl_object_emit_full (obj, UCL_EMIT_CONFIG, fn, comments));
|
||||||
fprintf (out, "%s\n", emitted);
|
fprintf (out, "%s\n", emitted);
|
||||||
ucl_object_emit_funcs_free (fn);
|
ucl_object_emit_funcs_free (fn);
|
||||||
@ -293,7 +302,7 @@ main (int argc, char **argv)
|
|||||||
assert (ucl_parser_get_error_code (parser) == 0);
|
assert (ucl_parser_get_error_code (parser) == 0);
|
||||||
obj = ucl_parser_get_object (parser);
|
obj = ucl_parser_get_object (parser);
|
||||||
ucl_parser_free (parser);
|
ucl_parser_free (parser);
|
||||||
ucl_object_free (obj);
|
ucl_object_unref (obj);
|
||||||
|
|
||||||
if (emitted != NULL) {
|
if (emitted != NULL) {
|
||||||
free (emitted);
|
free (emitted);
|
||||||
|
@ -456,6 +456,7 @@ ucl_test_large_string (void)
|
|||||||
res = ucl_object_fromstring_common (str, cur_len % 100000,
|
res = ucl_object_fromstring_common (str, cur_len % 100000,
|
||||||
UCL_STRING_RAW);
|
UCL_STRING_RAW);
|
||||||
res->flags |= UCL_OBJECT_BINARY;
|
res->flags |= UCL_OBJECT_BINARY;
|
||||||
|
free (str);
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
12
utils/CMakeLists.txt
Normal file
12
utils/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
|
||||||
|
PROJECT(libucl-utils C)
|
||||||
|
|
||||||
|
FUNCTION(MAKE_UTIL UTIL_NAME UTIL_SRCS)
|
||||||
|
ADD_EXECUTABLE(${UTIL_NAME} ${UTIL_SRCS})
|
||||||
|
TARGET_LINK_LIBRARIES(${UTIL_NAME} ucl)
|
||||||
|
INSTALL(TARGETS ${UTIL_NAME} DESTINATION bin)
|
||||||
|
ENDFUNCTION()
|
||||||
|
|
||||||
|
MAKE_UTIL(ucl_chargen chargen.c)
|
||||||
|
MAKE_UTIL(ucl_objdump objdump.c)
|
||||||
|
MAKE_UTIL(ucl_tool ucl-tool.c)
|
@ -22,8 +22,11 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#if defined(_MSC_VER)
|
||||||
#include <errno.h>
|
#include <BaseTsd.h>
|
||||||
|
|
||||||
|
typedef SSIZE_T ssize_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ucl.h"
|
#include "ucl.h"
|
||||||
|
|
||||||
@ -101,8 +104,8 @@ main(int argc, char **argv)
|
|||||||
const char *fn = NULL;
|
const char *fn = NULL;
|
||||||
unsigned char *inbuf;
|
unsigned char *inbuf;
|
||||||
struct ucl_parser *parser;
|
struct ucl_parser *parser;
|
||||||
int k, ret = 0, r = 0;
|
int k, ret = 0;
|
||||||
ssize_t bufsize;
|
ssize_t bufsize, r = 0;
|
||||||
ucl_object_t *obj = NULL;
|
ucl_object_t *obj = NULL;
|
||||||
const ucl_object_t *par;
|
const ucl_object_t *par;
|
||||||
FILE *in;
|
FILE *in;
|
||||||
@ -114,7 +117,7 @@ main(int argc, char **argv)
|
|||||||
if (fn != NULL) {
|
if (fn != NULL) {
|
||||||
in = fopen (fn, "r");
|
in = fopen (fn, "r");
|
||||||
if (in == NULL) {
|
if (in == NULL) {
|
||||||
exit (-errno);
|
exit (EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -146,14 +149,14 @@ main(int argc, char **argv)
|
|||||||
ucl_parser_add_chunk (parser, inbuf, r);
|
ucl_parser_add_chunk (parser, inbuf, r);
|
||||||
fclose (in);
|
fclose (in);
|
||||||
if (ucl_parser_get_error(parser)) {
|
if (ucl_parser_get_error(parser)) {
|
||||||
printf ("Error occured: %s\n", ucl_parser_get_error(parser));
|
printf ("Error occurred: %s\n", ucl_parser_get_error(parser));
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
obj = ucl_parser_get_object (parser);
|
obj = ucl_parser_get_object (parser);
|
||||||
if (ucl_parser_get_error (parser)) {
|
if (ucl_parser_get_error (parser)) {
|
||||||
printf ("Error occured: %s\n", ucl_parser_get_error(parser));
|
printf ("Error occurred: %s\n", ucl_parser_get_error(parser));
|
||||||
ret = 1;
|
ret = 1;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
100
utils/ucl-tool.c
100
utils/ucl-tool.c
@ -20,21 +20,8 @@
|
|||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "ucl.h"
|
#include "ucl.h"
|
||||||
|
|
||||||
static struct option opts[] = {
|
|
||||||
{"help", no_argument, NULL, 'h'},
|
|
||||||
{"in", required_argument, NULL, 'i' },
|
|
||||||
{"out", required_argument, NULL, 'o' },
|
|
||||||
{"schema", required_argument, NULL, 's'},
|
|
||||||
{"format", required_argument, NULL, 'f'},
|
|
||||||
{0, 0, 0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
void usage(const char *name, FILE *out) {
|
void usage(const char *name, FILE *out) {
|
||||||
fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name);
|
fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name);
|
||||||
fprintf(out, " [-s|--schema file] [-f|--format format]\n\n");
|
fprintf(out, " [-s|--schema file] [-f|--format format]\n\n");
|
||||||
@ -49,64 +36,75 @@ void usage(const char *name, FILE *out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
|
int i;
|
||||||
char ch;
|
char ch;
|
||||||
FILE *in = stdin, *out = stdout;
|
FILE *in = stdin, *out = stdout;
|
||||||
const char *schema = NULL;
|
const char *schema = NULL, *parm, *val;
|
||||||
unsigned char *buf = NULL;
|
unsigned char *buf = NULL;
|
||||||
size_t size = 0, r = 0;
|
size_t size = 0, r = 0;
|
||||||
struct ucl_parser *parser = NULL;
|
struct ucl_parser *parser = NULL;
|
||||||
ucl_object_t *obj = NULL;
|
ucl_object_t *obj = NULL;
|
||||||
ucl_emitter_t emitter = UCL_EMIT_CONFIG;
|
ucl_emitter_t emitter = UCL_EMIT_CONFIG;
|
||||||
|
|
||||||
while((ch = getopt_long(argc, argv, "hi:o:s:f:", opts, NULL)) != -1) {
|
for (i = 1; i < argc; ++i) {
|
||||||
switch (ch) {
|
parm = argv[i];
|
||||||
case 'i':
|
val = ((i + 1) < argc) ? argv[++i] : NULL;
|
||||||
in = fopen(optarg, "r");
|
|
||||||
|
if ((strcmp(parm, "--help") == 0) || (strcmp(parm, "-h") == 0)) {
|
||||||
|
usage(argv[0], stdout);
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
} else if ((strcmp(parm, "--in") == 0) || (strcmp(parm, "-i") == 0)) {
|
||||||
|
if (!val)
|
||||||
|
goto err_val;
|
||||||
|
|
||||||
|
in = fopen(val, "r");
|
||||||
if (in == NULL) {
|
if (in == NULL) {
|
||||||
perror("fopen on input file");
|
perror("fopen on input file");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
} else if ((strcmp(parm, "--out") == 0) || (strcmp(parm, "-o") == 0)) {
|
||||||
case 'o':
|
if (!val)
|
||||||
out = fopen(optarg, "w");
|
goto err_val;
|
||||||
|
|
||||||
|
out = fopen(val, "w");
|
||||||
if (out == NULL) {
|
if (out == NULL) {
|
||||||
perror("fopen on output file");
|
perror("fopen on output file");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
break;
|
} else if ((strcmp(parm, "--schema") == 0) || (strcmp(parm, "-s") == 0)) {
|
||||||
case 's':
|
if (!val)
|
||||||
schema = optarg;
|
goto err_val;
|
||||||
break;
|
schema = val;
|
||||||
case 'f':
|
|
||||||
if (strcmp(optarg, "ucl") == 0) {
|
} else if ((strcmp(parm, "--format") == 0) || (strcmp(parm, "-f") == 0)) {
|
||||||
emitter = UCL_EMIT_CONFIG;
|
if (!val)
|
||||||
} else if (strcmp(optarg, "json") == 0) {
|
goto err_val;
|
||||||
emitter = UCL_EMIT_JSON;
|
|
||||||
} else if (strcmp(optarg, "yaml") == 0) {
|
if (strcmp(val, "ucl") == 0) {
|
||||||
emitter = UCL_EMIT_YAML;
|
emitter = UCL_EMIT_CONFIG;
|
||||||
} else if (strcmp(optarg, "compact_json") == 0) {
|
} else if (strcmp(val, "json") == 0) {
|
||||||
emitter = UCL_EMIT_JSON_COMPACT;
|
emitter = UCL_EMIT_JSON;
|
||||||
} else if (strcmp(optarg, "msgpack") == 0) {
|
} else if (strcmp(val, "yaml") == 0) {
|
||||||
emitter = UCL_EMIT_MSGPACK;
|
emitter = UCL_EMIT_YAML;
|
||||||
} else {
|
} else if (strcmp(val, "compact_json") == 0) {
|
||||||
fprintf(stderr, "Unknown output format: %s\n", optarg);
|
emitter = UCL_EMIT_JSON_COMPACT;
|
||||||
exit(EXIT_FAILURE);
|
} else if (strcmp(val, "msgpack") == 0) {
|
||||||
}
|
emitter = UCL_EMIT_MSGPACK;
|
||||||
break;
|
} else {
|
||||||
case 'h':
|
fprintf(stderr, "Unknown output format: %s\n", val);
|
||||||
usage(argv[0], stdout);
|
exit(EXIT_FAILURE);
|
||||||
exit(0);
|
}
|
||||||
default:
|
} else {
|
||||||
usage(argv[0], stderr);
|
usage(argv[0], stderr);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
parser = ucl_parser_new(0);
|
parser = ucl_parser_new(0);
|
||||||
buf = malloc(BUFSIZ);
|
buf = malloc(BUFSIZ);
|
||||||
size = BUFSIZ;
|
size = BUFSIZ;
|
||||||
while(!feof(in) && !ferror(in)) {
|
while (!feof(in) && !ferror(in)) {
|
||||||
if (r == size) {
|
if (r == size) {
|
||||||
buf = realloc(buf, size*2);
|
buf = realloc(buf, size*2);
|
||||||
size *= 2;
|
size *= 2;
|
||||||
@ -155,8 +153,7 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
if (emitter != UCL_EMIT_MSGPACK) {
|
if (emitter != UCL_EMIT_MSGPACK) {
|
||||||
fprintf(out, "%s\n", ucl_object_emit(obj, emitter));
|
fprintf(out, "%s\n", ucl_object_emit(obj, emitter));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
size_t len;
|
size_t len;
|
||||||
unsigned char *res;
|
unsigned char *res;
|
||||||
|
|
||||||
@ -165,4 +162,9 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
err_val:
|
||||||
|
fprintf(stderr, "Parameter %s is missing mandatory value\n", parm);
|
||||||
|
usage(argv[0], stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user