Commit 4e2fa78e authored by Baptiste Daroussin's avatar Baptiste Daroussin
Browse files

Update libucl to git snapshot 20151027 (77d9d33)

parent 15b8b407
PROJECT(libucl C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
SET(LIBUCL_VERSION_MAJOR 0)
SET(LIBUCL_VERSION_MINOR 5)
SET(LIBUCL_VERSION_PATCH 0)
SET(LIBUCL_VERSION "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
SET(LIBUCL_VERSION
"${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}")
INCLUDE(CheckCCompilerFlag)
INCLUDE(FindOpenSSL)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
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(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF)
OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF)
OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF)
# Find lua installation
MACRO(FindLua)
# Find lua libraries
UNSET(LUA_INCLUDE_DIR CACHE)
UNSET(LUA_LIBRARY CACHE)
CMAKE_PARSE_ARGUMENTS(LUA "" "VERSION_MAJOR;VERSION_MINOR;ROOT" "" ${ARGN})
IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
MESSAGE(FATAL_ERROR "Invalid FindLua invocation: ${ARGN}")
ENDIF()
IF(ENABLE_LUAJIT MATCHES "ON")
MESSAGE(STATUS "Check for luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
FIND_PATH(LUA_INCLUDE_DIR luajit.h
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES "include/luajit-2.0"
"include/luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"include/luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"include/luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"include/luajit"
"include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
include/lua include
PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
)
FIND_LIBRARY(LUA_LIBRARY
NAMES luajit
"luajit-2.0"
"luajit2.0"
"luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
DOC "Lua library"
)
IF(NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR)
MESSAGE(STATUS "Fallback from luajit to plain lua")
SET(ENABLE_LUAJIT "OFF")
MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
FIND_PATH(LUA_INCLUDE_DIR lua.h
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
include/lua include
PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
)
FIND_LIBRARY(LUA_LIBRARY
NAMES lua
"lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
DOC "Lua library"
)
ENDIF()
ELSE(ENABLE_LUAJIT MATCHES "ON")
MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
FIND_PATH(LUA_INCLUDE_DIR lua.h
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
include/lua include
PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS}
)
FIND_LIBRARY(LUA_LIBRARY
NAMES lua
"lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}"
"lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
"lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}"
HINTS
"${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}"
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS}
DOC "Lua library"
)
ENDIF(ENABLE_LUAJIT MATCHES "ON")
IF(LUA_LIBRARY AND LUA_INCLUDE_DIR)
SET(LUA_FOUND 1)
IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
SET(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR})
SET(LUA_VERSION_MINOR ${LUA_VERSION_MINOR})
ENDIF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR)
IF(ENABLE_LUAJIT MATCHES "ON")
MESSAGE(STATUS "Found luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
ELSE(ENABLE_LUAJIT MATCHES "ON")
MESSAGE(STATUS "Found lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}")
ENDIF(ENABLE_LUAJIT MATCHES "ON")
ENDIF(LUA_LIBRARY AND LUA_INCLUDE_DIR)
ENDMACRO()
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt)
......@@ -79,19 +192,21 @@ IF(ENABLE_URL_SIGN MATCHES "ON")
ENDIF(OPENSSL_FOUND)
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../src")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../include")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../uthash")
INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../klib")
INCLUDE_DIRECTORIES("src")
INCLUDE_DIRECTORIES("include")
INCLUDE_DIRECTORIES("uthash")
INCLUDE_DIRECTORIES("klib")
SET(UCLSRC ../src/ucl_util.c
../src/ucl_parser.c
../src/ucl_emitter.c
../src/ucl_emitter_streamline.c
../src/ucl_emitter_utils.c
../src/ucl_hash.c
../src/ucl_schema.c
../src/xxhash.c)
SET(UCLSRC src/ucl_util.c
src/ucl_parser.c
src/ucl_emitter.c
src/ucl_emitter_streamline.c
src/ucl_emitter_utils.c
src/ucl_hash.c
src/ucl_schema.c
src/ucl_msgpack.c
src/ucl_sexp.c
src/xxhash.c)
SET (LIB_TYPE STATIC)
......@@ -101,8 +216,26 @@ ENDIF (BUILD_SHARED_LIBS)
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
IF(WITH_LUA)
SET(UCL_LUA_SRC ../lua/lua_ucl.c)
IF(ENABLE_LUA MATCHES "ON")
IF(ENABLE_LUAJIT MATCHES "ON")
FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}")
IF(NOT LUA_FOUND)
MESSAGE(FATAL_ERROR "Lua not found, lua support is required")
ELSE(NOT LUA_FOUND)
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
ENDIF(NOT LUA_FOUND)
ELSE(ENABLE_LUAJIT MATCHES "ON")
FindLua(VERSION_MAJOR "5" VERSION_MINOR "2" ROOT "${LUA_ROOT}")
IF(NOT LUA_FOUND)
FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}")
ENDIF(NOT LUA_FOUND)
IF(NOT LUA_FOUND)
MESSAGE(FATAL_ERROR "Lua not found, lua support is required")
ELSE(NOT LUA_FOUND)
INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}")
ENDIF(NOT LUA_FOUND)
ENDIF(ENABLE_LUAJIT MATCHES "ON")
SET(UCL_LUA_SRC lua/lua_ucl.c)
ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC})
IF(ENABLE_LUAJIT MATCHES "ON")
TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}")
......@@ -111,7 +244,7 @@ IF(WITH_LUA)
ENDIF(ENABLE_LUAJIT MATCHES "ON")
TARGET_LINK_LIBRARIES(lua-ucl ucl)
SET_TARGET_PROPERTIES(lua-ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
ENDIF(WITH_LUA)
ENDIF()
IF(HAVE_FETCH_H)
TARGET_LINK_LIBRARIES(ucl fetch)
......
......@@ -32,3 +32,8 @@
### Libucl 0.7.2
- Fixed serious bugs in schema and arrays iteration
### Libucl 0.7.3
- Fixed a bug with macroes that come after an empty object
- Fixed a bug in include processing when an incorrect variable has been destroyed (use-after-free)
......@@ -21,7 +21,7 @@
- [Performance](#performance)
- [Conclusion](#conclusion)
## Introduction
## Introduction
This document describes the main features and principles of the configuration
language called `UCL` - universal configuration language.
......@@ -262,7 +262,20 @@ parser is created but before any configurations are parsed.
all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page
for your operating system). This option is meaningless for URL includes.
* `url` (default: **true**) - allow URL includes.
* `path` (default: empty) - A UCL_ARRAY of directories to search for the include file.
Search ends after the first patch, unless `glob` is true, then all matches are included.
* `prefix` (default false) - Put included contents inside an object, instead
of loading them into the root. If no `key` is provided, one is automatically generated based on each files basename()
* `key` (default: <empty string>) - Key to load contents of include into. If
the key already exists, it must be the correct type
* `target` (default: object) - Specify if the `prefix` `key` should be an
object or an array.
* `priority` (default: 0) - specify priority for the include (see below).
* `duplicate` (default: 'append') - specify policy of duplicates resolving:
- `append` - default strategy, if we have new object of higher priority then it replaces old one, if we have new object with less priority it is ignored completely, and if we have two duplicate objects with the same priority then we have a multi-value key (implicit array)
- `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardeless of priorities)
- `error` - create error on duplicate keys and stop parsing
- `rewrite` - always rewrite an old value with new one (ignoring priorities)
Priorities are used by UCL parser to manage the policy of objects rewriting during including other files
as following:
......
m4_define([maj_ver], [0])
m4_define([med_ver], [7])
m4_define([min_ver], [2])
m4_define([so_version], [5:0:1])
m4_define([min_ver], [3])
m4_define([so_version], [5:0:2])
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
......@@ -47,6 +47,7 @@ AC_CHECK_HEADERS_ONCE([libgen.h])
AC_CHECK_HEADERS_ONCE([stdio.h])
AC_CHECK_HEADERS_ONCE([float.h])
AC_CHECK_HEADERS_ONCE([math.h])
AC_CHECK_HEADERS_ONCE([endian.h sys/endian.h machine/endian.h])
dnl Example of default-disabled feature
AC_ARG_ENABLE([urls], AS_HELP_STRING([--enable-urls],
......
......@@ -4,6 +4,6 @@ dist_man_MANS = libucl.3
gen-man: @PANDOC@
tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \
cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \
cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \
-e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \
@PANDOC@ -s -f markdown -t man -o libucl.3
\ No newline at end of file
@PANDOC@ -s -f markdown -t man -o libucl.3
......@@ -16,7 +16,7 @@ if not res then
else
local obj = parser:get_object()
local got = ucl.to_format(obj, 'json')
endif
end
local table = {
str = 'value',
......@@ -25,6 +25,7 @@ local table = {
func = function ()
return 'huh'
end
}
print(ucl.to_format(table, 'ucl'))
......@@ -115,6 +116,7 @@ local table = {
func = function ()
return 'huh'
end
}
print(ucl.to_format(table, 'ucl'))
......
#include <iostream>
#include <string>
#include "ucl++.h"
int main(int argc, char **argv)
{
std::string input, err;
input.assign((std::istreambuf_iterator<char>(std::cin)),
std::istreambuf_iterator<char>());
auto obj = ucl::Ucl::parse(input, err);
if (obj) {
std::cout << obj.dump(UCL_EMIT_CONFIG) << std::endl;
for (const auto &o : obj) {
std::cout << o.dump(UCL_EMIT_CONFIG) << std::endl;
}
}
else {
std::cerr << "Error: " << err << std::endl;
return 1;
}
}
/*
* Copyright (c) 2015, Vsevolod Stakhov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <string>
#include <memory>
#include <iostream>
#include <strstream>
#include "ucl.h"
// C++11 API inspired by json11: https://github.com/dropbox/json11/
namespace ucl {
struct ucl_map_construct_t { };
constexpr ucl_map_construct_t ucl_map_construct = ucl_map_construct_t();
struct ucl_array_construct_t { };
constexpr ucl_array_construct_t ucl_array_construct = ucl_array_construct_t();
class Ucl final {
private:
struct ucl_deleter {
void operator() (ucl_object_t *obj) {
ucl_object_unref (obj);
}
};
static int
append_char (unsigned char c, size_t nchars, void *ud)
{
std::string *out = reinterpret_cast<std::string *>(ud);
out->append (nchars, (char)c);
return nchars;
}
static int
append_len (unsigned const char *str, size_t len, void *ud)
{
std::string *out = reinterpret_cast<std::string *>(ud);
out->append ((const char *)str, len);
return len;
}
static int
append_int (int64_t elt, void *ud)
{
std::string *out = reinterpret_cast<std::string *>(ud);
auto nstr = std::to_string (elt);
out->append (nstr);
return nstr.size ();
}
static int
append_double (double elt, void *ud)
{
std::string *out = reinterpret_cast<std::string *>(ud);
auto nstr = std::to_string (elt);
out->append (nstr);
return nstr.size ();
}
static struct ucl_emitter_functions default_emit_funcs()
{
struct ucl_emitter_functions func = {
Ucl::append_char,
Ucl::append_len,
Ucl::append_int,
Ucl::append_double,
nullptr,
nullptr
};
return func;
};
std::unique_ptr<ucl_object_t, ucl_deleter> obj;
public:
class const_iterator {
private:
struct ucl_iter_deleter {
void operator() (ucl_object_iter_t it) {
ucl_object_iterate_free (it);
}
};
std::shared_ptr<void> it;
std::unique_ptr<Ucl> cur;
public:
typedef std::forward_iterator_tag iterator_category;
const_iterator(const Ucl &obj) {
it = std::shared_ptr<void>(ucl_object_iterate_new (obj.obj.get()),
ucl_iter_deleter());
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
}
const_iterator() {}
const_iterator(const const_iterator &other) {
it = other.it;
}
~const_iterator() {}
const_iterator& operator=(const const_iterator &other) {
it = other.it;
return *this;
}
bool operator==(const const_iterator &other) const
{
if (cur && other.cur) {
return cur->obj.get() == other.cur->obj.get();
}
return !cur && !other.cur;
}
bool operator!=(const const_iterator &other) const
{
return !(*this == other);
}
const_iterator& operator++()
{
if (it) {
cur.reset (new Ucl(ucl_object_iterate_safe (it.get(), true)));
}
if (!*cur) {
it.reset ();
cur.reset ();
}
return *this;
}
const Ucl& operator*() const
{
return *cur;
}
const Ucl* operator->() const
{
return cur.get();
}
};
// We grab ownership if get non-const ucl_object_t
Ucl(ucl_object_t *other) {
obj.reset (other);
}
// Shared ownership
Ucl(const ucl_object_t *other) {
obj.reset (ucl_object_ref (other));
}
Ucl(const Ucl &other) {
obj.reset (ucl_object_ref (other.obj.get()));
}
Ucl(Ucl &&other) {
obj.swap (other.obj);
}
Ucl() noexcept {
obj.reset (ucl_object_typed_new (UCL_NULL));
}
Ucl(std::nullptr_t) noexcept {
obj.reset (ucl_object_typed_new (UCL_NULL));
}
Ucl(double value) {
obj.reset (ucl_object_typed_new (UCL_FLOAT));
obj->value.dv = value;
}
Ucl(int64_t value) {
obj.reset (ucl_object_typed_new (UCL_INT));
obj->value.iv = value;
}
Ucl(bool value) {
obj.reset (ucl_object_typed_new (UCL_BOOLEAN));
obj->value.iv = static_cast<int64_t>(value);
}
Ucl(const std::string &value) {
obj.reset (ucl_object_fromstring_common (value.data (), value.size (),
UCL_STRING_RAW));
}
Ucl(const char * value) {
obj.reset (ucl_object_fromstring_common (value, 0, UCL_STRING_RAW));
}
// Implicit constructor: anything with a to_json() function.
template <class T, class = decltype(&T::to_ucl)>
Ucl(const T & t) : Ucl(t.to_ucl()) {}
// Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
template <class M, typename std::enable_if<
std::is_constructible<std::string, typename M::key_type>::value
&& std::is_constructible<Ucl, typename M::mapped_type>::value,
int>::type = 0>
Ucl(const M & m) {
obj.reset (ucl_object_typed_new (UCL_OBJECT));
auto cobj = obj.get ();
for (const auto &e : m) {
ucl_object_insert_key (cobj, ucl_object_ref (e.second.obj.get()),
e.first.data (), e.first.size (), true);
}
}
// Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
template <class V, typename std::enable_if<
std::is_constructible<Ucl, typename V::value_type>::value,
int>::type = 0>
Ucl(const V & v) {
obj.reset (ucl_object_typed_new (UCL_ARRAY));
auto cobj = obj.get ();
for (const auto &e : v) {
ucl_array_append (cobj, ucl_object_ref (e.obj.get()));
}
}
ucl_type_t type () const {
if (obj) {
return ucl_object_type (obj.get ());
}
return UCL_NULL;
}
const std::string key () const {
std::string res;
if (obj->key) {
res.assign (obj->key, obj->keylen);
}
return res;
}
double number_value () const
{
if (obj) {
return ucl_object_todouble (obj.get());
}
return 0.0;
}
int64_t int_value () const
{
if (obj) {
return ucl_object_toint (obj.get());
}
return 0;
}
bool bool_value () const
{
if (obj) {
return ucl_object_toboolean (obj.get());
}
return false;
}
const std::string string_value () const
{
std::string res;
if (obj) {
res.assign (ucl_object_tostring (obj.get()));
}