MFC: r263648, r264789, r266636
This brings: - schema validation - xpath-like interface for ucl objects Adapt pkg(7) to the new libucl API
This commit is contained in:
parent
6095428430
commit
6f718e3669
3
contrib/libucl/.gitignore
vendored
3
contrib/libucl/.gitignore
vendored
@ -1,3 +0,0 @@
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
7
contrib/libucl/Makefile.am
Normal file
7
contrib/libucl/Makefile.am
Normal file
@ -0,0 +1,7 @@
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
EXTRA_DIST = uthash README.md
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libucl.pc
|
||||
|
||||
SUBDIRS = src tests utils doc
|
@ -4,7 +4,7 @@ LD ?= gcc
|
||||
C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 2
|
||||
PATCH_VERSION = 8
|
||||
PATCH_VERSION = 9
|
||||
VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)"
|
||||
SONAME = libucl.so
|
||||
SONAME_FULL = $(SONAME).$(MAJOR_VERSION)
|
||||
@ -21,8 +21,17 @@ LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm
|
||||
LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl
|
||||
LD_ADD ?= -lrt
|
||||
COPT_FLAGS ?= -O2
|
||||
HDEPS = $(SRCDIR)/ucl_hash.h $(SRCDIR)/ucl_chartable.h $(SRCDIR)/ucl_internal.h $(INCLUDEDIR)/ucl.h $(SRCDIR)/xxhash.h
|
||||
OBJECTS = $(OBJDIR)/ucl_hash.o $(OBJDIR)/ucl_util.o $(OBJDIR)/ucl_parser.o $(OBJDIR)/ucl_emitter.o $(OBJDIR)/xxhash.o
|
||||
HDEPS = $(SRCDIR)/ucl_hash.h \
|
||||
$(SRCDIR)/ucl_chartable.h \
|
||||
$(SRCDIR)/ucl_internal.h \
|
||||
$(INCLUDEDIR)/ucl.h \
|
||||
$(SRCDIR)/xxhash.h
|
||||
OBJECTS = $(OBJDIR)/ucl_hash.o \
|
||||
$(OBJDIR)/ucl_util.o \
|
||||
$(OBJDIR)/ucl_parser.o \
|
||||
$(OBJDIR)/ucl_emitter.o \
|
||||
$(OBJDIR)/ucl_schema.o \
|
||||
$(OBJDIR)/xxhash.o
|
||||
|
||||
all: $(OBJDIR) $(OBJDIR)/$(SONAME)
|
||||
|
||||
@ -44,11 +53,13 @@ $(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
|
||||
$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
|
||||
$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c
|
||||
$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME_FULL) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate
|
||||
$(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME_FULL) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate $(OBJDIR)/test_schema || true
|
||||
$(RMDIR) $(OBJDIR)
|
||||
|
||||
# Utils
|
||||
@ -60,13 +71,15 @@ objdump: utils/objdump.c $(OBJDIR)/$(SONAME)
|
||||
|
||||
# Tests
|
||||
|
||||
test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
|
||||
test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema
|
||||
|
||||
run-test: test
|
||||
TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate
|
||||
TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema
|
||||
|
||||
$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME)
|
||||
$(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS)
|
||||
$(OBJDIR)/test_schema: $(TESTDIR)/test_schema.c $(OBJDIR)/$(SONAME)
|
||||
$(CC) -o $(OBJDIR)/test_schema $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_schema.c $(LD_UCL_FLAGS)
|
||||
$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME)
|
||||
$(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD)
|
||||
$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME)
|
||||
|
@ -4,7 +4,7 @@ LD ?= gcc
|
||||
C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src
|
||||
MAJOR_VERSION = 0
|
||||
MINOR_VERSION = 2
|
||||
PATCH_VERSION = 8
|
||||
PATCH_VERSION = 9
|
||||
VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)"
|
||||
SONAME = libucl.dll
|
||||
OBJDIR ?= .obj
|
||||
@ -24,8 +24,17 @@ LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm
|
||||
LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl
|
||||
LD_ADD ?= -lrt
|
||||
COPT_FLAGS ?= -O2
|
||||
HDEPS = $(SRCDIR)/ucl_hash.h $(SRCDIR)/ucl_chartable.h $(SRCDIR)/ucl_internal.h $(INCLUDEDIR)/ucl.h $(SRCDIR)/xxhash.h
|
||||
OBJECTS = $(OBJDIR)/ucl_hash.o $(OBJDIR)/ucl_util.o $(OBJDIR)/ucl_parser.o $(OBJDIR)/ucl_emitter.o $(OBJDIR)/xxhash.o
|
||||
HDEPS = $(SRCDIR)/ucl_hash.h \
|
||||
$(SRCDIR)/ucl_chartable.h \
|
||||
$(SRCDIR)/ucl_internal.h \
|
||||
$(INCLUDEDIR)/ucl.h \
|
||||
$(SRCDIR)/xxhash.h
|
||||
OBJECTS = $(OBJDIR)/ucl_hash.o \
|
||||
$(OBJDIR)/ucl_util.o \
|
||||
$(OBJDIR)/ucl_parser.o \
|
||||
$(OBJDIR)/ucl_emitter.o \
|
||||
$(OBJDIR)/ucl_schema.o \
|
||||
$(OBJDIR)/xxhash.o
|
||||
|
||||
all: $(OBJDIR) $(OBJDIR)/$(SONAME)
|
||||
|
||||
@ -44,6 +53,8 @@ $(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c
|
||||
$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c
|
||||
$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c
|
||||
$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS)
|
||||
$(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c
|
||||
|
||||
|
@ -1,3 +1,26 @@
|
||||
# LIBUCL
|
||||
|
||||
[](https://travis-ci.org/vstakhov/libucl)
|
||||
|
||||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
|
||||
|
||||
- [Introduction](#introduction)
|
||||
- [Basic structure](#basic-structure)
|
||||
- [Improvements to the json notation](#improvements-to-the-json-notation)
|
||||
- [General syntax sugar](#general-syntax-sugar)
|
||||
- [Automatic arrays creation](#automatic-arrays-creation)
|
||||
- [Named keys hierarchy](#named-keys-hierarchy)
|
||||
- [Convenient numbers and booleans](#convenient-numbers-and-booleans)
|
||||
- [General improvements](#general-improvements)
|
||||
- [Commments](#commments)
|
||||
- [Macros support](#macros-support)
|
||||
- [Variables support](#variables-support)
|
||||
- [Multiline strings](#multiline-strings)
|
||||
- [Emitter](#emitter)
|
||||
- [Validation](#validation)
|
||||
- [Performance](#performance)
|
||||
- [Conclusion](#conclusion)
|
||||
|
||||
## Introduction
|
||||
|
||||
This document describes the main features and principles of the configuration
|
||||
@ -262,6 +285,10 @@ Each UCL object can be serialized to one of the three supported formats:
|
||||
* `Configuration` - nginx like notation;
|
||||
* `YAML` - yaml inlined notation.
|
||||
|
||||
## Validation
|
||||
|
||||
UCL allows validation of objects. It uses the same schema that is used for json: [json schema v4](http://json-schema.org). UCL supports the full set of json schema with the exception of remote references. This feature is unlikely useful for configuration objects. Of course, a schema definition can be in UCL format instead of JSON that simplifies schemas writing. Moreover, since UCL supports multiple values for keys in an object it is possible to specify generic integer constraints `maxValues` and `minValues` to define the limits of values count in a single key. UCL currently is not absolutely strict about validation schemas themselves, therefore UCL users should supply valid schemas (as it is defined in json-schema draft v4) to ensure that the input objects are validated properly.
|
||||
|
||||
## Performance
|
||||
|
||||
Are UCL parser and emitter fast enough? Well, there are some numbers.
|
||||
|
2
contrib/libucl/autogen.sh
Executable file
2
contrib/libucl/autogen.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
autoreconf -i
|
112
contrib/libucl/cmake/CMakeLists.txt
Normal file
112
contrib/libucl/cmake/CMakeLists.txt
Normal file
@ -0,0 +1,112 @@
|
||||
PROJECT(libucl C)
|
||||
|
||||
SET(LIBUCL_VERSION_MAJOR 0)
|
||||
SET(LIBUCL_VERSION_MINOR 2)
|
||||
SET(LIBUCL_VERSION_PATCH 9)
|
||||
|
||||
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)
|
||||
|
||||
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt)
|
||||
ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
|
||||
IF(ENABLE_URL_INCLUDE MATCHES "ON")
|
||||
FIND_LIBRARY(LIBFETCH_LIBRARY NAMES fetch PATHS PATH_SUFFIXES lib64 lib
|
||||
PATHS
|
||||
~/Library/Frameworks
|
||||
/Library/Frameworks
|
||||
/usr/local
|
||||
/usr
|
||||
/sw
|
||||
/opt/local
|
||||
/opt/csw
|
||||
/opt
|
||||
DOC "Path where the libfetch library can be found")
|
||||
IF(LIBFETCH_LIBRARY)
|
||||
FIND_FILE(HAVE_FETCH_H NAMES fetch.h PATHS /usr/include
|
||||
/opt/include
|
||||
/usr/local/include
|
||||
DOC "Path to libfetch header")
|
||||
ELSE(LIBFETCH_LIBRARY)
|
||||
# Try to find libcurl
|
||||
ProcessPackage(CURL libcurl)
|
||||
IF(NOT CURL_FOUND)
|
||||
MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration")
|
||||
ENDIF(NOT CURL_FOUND)
|
||||
ENDIF(LIBFETCH_LIBRARY)
|
||||
ENDIF(ENABLE_URL_INCLUDE MATCHES "ON")
|
||||
|
||||
SET(CMAKE_C_WARN_FLAGS "")
|
||||
CHECK_C_COMPILER_FLAG(-Wall SUPPORT_WALL)
|
||||
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(-Wstrict-prototypes SUPPORT_WSTRICT_PROTOTYPES)
|
||||
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)
|
||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -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)
|
||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign")
|
||||
ENDIF(SUPPORT_WPOINTER_SIGN)
|
||||
IF(SUPPORT_WSTRICT_PROTOTYPES)
|
||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wstrict-prototypes")
|
||||
ENDIF(SUPPORT_WSTRICT_PROTOTYPES)
|
||||
IF(SUPPORT_STD_FLAG)
|
||||
SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -std=c99")
|
||||
ENDIF(SUPPORT_STD_FLAG)
|
||||
|
||||
IF(ENABLE_URL_SIGN MATCHES "ON")
|
||||
IF(OPENSSL_FOUND)
|
||||
SET(HAVE_OPENSSL 1)
|
||||
INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}")
|
||||
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")
|
||||
|
||||
SET(UCLSRC ../src/ucl_util.c
|
||||
../src/ucl_parser.c
|
||||
../src/ucl_emitter.c
|
||||
../src/ucl_hash.c
|
||||
../src/ucl_schema.c
|
||||
../src/xxhash.c)
|
||||
|
||||
|
||||
SET (LIB_TYPE STATIC)
|
||||
IF (BUILD_SHARED_LIBS)
|
||||
SET (LIB_TYPE SHARED)
|
||||
ENDIF (BUILD_SHARED_LIBS)
|
||||
ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})
|
||||
SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})
|
||||
|
||||
IF(HAVE_FETCH_H)
|
||||
TARGET_LINK_LIBRARIES(ucl fetch)
|
||||
ELSE(HAVE_FETCH_H)
|
||||
IF(CURL_FOUND)
|
||||
TARGET_LINK_LIBRARIES(ucl ${CURL_LIBRARIES})
|
||||
ENDIF(CURL_FOUND)
|
||||
ENDIF(HAVE_FETCH_H)
|
||||
IF(ENABLE_URL_SIGN MATCHES "ON")
|
||||
IF(OPENSSL_FOUND)
|
||||
TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES})
|
||||
ENDIF(OPENSSL_FOUND)
|
||||
ENDIF(ENABLE_URL_SIGN MATCHES "ON")
|
163
contrib/libucl/configure.ac
Normal file
163
contrib/libucl/configure.ac
Normal file
@ -0,0 +1,163 @@
|
||||
m4_define([maj_ver], [0])
|
||||
m4_define([med_ver], [4])
|
||||
m4_define([min_ver], [1])
|
||||
m4_define([so_version], [1:0:0])
|
||||
m4_define([ucl_version], [maj_ver.med_ver.min_ver])
|
||||
|
||||
AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl])
|
||||
AC_CONFIG_SRCDIR([configure.ac])
|
||||
AM_INIT_AUTOMAKE([1.11 foreign silent-rules -Wall -Wportability no-dist-gzip dist-xz])
|
||||
|
||||
UCL_VERSION=ucl_version
|
||||
SO_VERSION=so_version
|
||||
|
||||
AC_SUBST(UCL_VERSION)
|
||||
AC_SUBST(SO_VERSION)
|
||||
|
||||
AC_PROG_CC_C99
|
||||
AM_PROG_CC_C_O
|
||||
AM_PROG_AR
|
||||
LT_INIT
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
AC_C_CONST
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
AC_CHECK_HEADERS_ONCE([fcntl.h unistd.h])
|
||||
AC_TYPE_OFF_T
|
||||
AC_FUNC_MMAP
|
||||
AC_CHECK_HEADERS_ONCE([fcntl.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/types.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/stat.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/param.h])
|
||||
AC_CHECK_HEADERS_ONCE([sys/mman.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdlib.h])
|
||||
AC_CHECK_HEADERS_ONCE([stddef.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdarg.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdbool.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdint.h])
|
||||
AC_CHECK_HEADERS_ONCE([string.h])
|
||||
AC_CHECK_HEADERS_ONCE([unistd.h])
|
||||
AC_CHECK_HEADERS_ONCE([ctype.h])
|
||||
AC_CHECK_HEADERS_ONCE([errno.h])
|
||||
AC_CHECK_HEADERS_ONCE([limits.h])
|
||||
AC_CHECK_HEADERS_ONCE([libgen.h])
|
||||
AC_CHECK_HEADERS_ONCE([stdio.h])
|
||||
AC_CHECK_HEADERS_ONCE([float.h])
|
||||
AC_CHECK_HEADERS_ONCE([math.h])
|
||||
|
||||
dnl Example of default-disabled feature
|
||||
AC_ARG_ENABLE([urls], AS_HELP_STRING([--enable-urls],
|
||||
[Enable URLs fetch (requires libfetch or libcurl) @<:@default=no@:>@]), [],
|
||||
[enable_urls=no])
|
||||
AC_ARG_ENABLE([regex], AS_HELP_STRING([--enable-regex],
|
||||
[Enable regex checking for schema @<:@default=yes@:>@]), [],
|
||||
[enable_regex=yes])
|
||||
AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures],
|
||||
[Enable signatures check (requires openssl) @<:@default=no@:>@]), [],
|
||||
[enable_signatures=no])
|
||||
AC_ARG_ENABLE([utils],
|
||||
AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]),
|
||||
[case "${enableval}" in
|
||||
yes) utils=true ;;
|
||||
no) utils=false ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-utils]) ;;
|
||||
esac],[utils=false])
|
||||
AM_CONDITIONAL([UTILS], [test x$utils = xtrue])
|
||||
|
||||
AS_IF([test "x$enable_signatures" = "xyes"], [
|
||||
AC_SEARCH_LIBS([EVP_MD_CTX_create], [crypto], [
|
||||
AC_DEFINE(HAVE_OPENSSL, 1, [Define to 1 if you have the 'crypto' library (-lcrypto).])
|
||||
LIBCRYPTO_LIB="-lcrypto"
|
||||
LIBS_EXTRA="${LIBS_EXTRA} -lcrypto"
|
||||
], [AC_MSG_ERROR([unable to find the EVP_MD_CTX_create() function])])
|
||||
])
|
||||
AC_SUBST(LIBCRYPTO_LIB)
|
||||
AC_PATH_PROG(PANDOC, pandoc, [/non/existent])
|
||||
|
||||
AC_SEARCH_LIBS([clock_gettime], [rt], [], [
|
||||
AC_CHECK_HEADER([mach/mach_time.h], [
|
||||
AC_DEFINE(HAVE_MACH_MACH_TIME_H, 1, [Define to 1 on Darwin])
|
||||
], [AC_MSG_ERROR([unable to find clock_gettime or mach_absolute_time])])
|
||||
])
|
||||
AC_SEARCH_LIBS([remainder], [m], [], [AC_MSG_ERROR([unable to find remainder() function])])
|
||||
|
||||
AS_IF([test "x$enable_regex" = "xyes"], [
|
||||
AC_CHECK_HEADER([regex.h], [
|
||||
AC_DEFINE(HAVE_REGEX_H, 1, [Define to 1 if you have the <regex.h> header file.])
|
||||
AC_SEARCH_LIBS([regexec], [regex], [
|
||||
AS_IF([test "x$ac_cv_search_regexec" = "x-lregex"], [
|
||||
LIBREGEX_LIB="-lregex"
|
||||
LIBS_EXTRA="${LIBS_EXTRA} -lregex"
|
||||
]
|
||||
)],
|
||||
[AC_MSG_ERROR([unable to find the regexec() function])])],
|
||||
[AC_MSG_ERROR([unable to find the regex.h header])
|
||||
],
|
||||
[#include <sys/types.h>])
|
||||
])
|
||||
AC_SUBST(LIBREGEX_LIB)
|
||||
|
||||
AS_IF([test "x$enable_urls" = "xyes"], [
|
||||
AC_CHECK_HEADER([fetch.h], [
|
||||
AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.])
|
||||
AC_CHECK_LIB(fetch, fetchXGet, [
|
||||
AC_DEFINE(HAVE_LIBFETCH, 1, [Define to 1 if you have the 'fetch' library (-lfetch).])
|
||||
LIBFETCH_LIBS="-lfetch"
|
||||
have_libfetch="yes"
|
||||
LIBS_EXTRA="${LIBS_EXTRA} -lfetch"
|
||||
])
|
||||
], [],[
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
])
|
||||
AC_SUBST(LIBFETCH_LIBS)
|
||||
|
||||
AS_IF([ test "x$have_libfetch" != "xyes"], [
|
||||
dnl Fallback to libcurl
|
||||
PKG_CHECK_MODULES([CURL], [libcurl], [
|
||||
AC_DEFINE(CURL_FOUND, 1, [Use libcurl])
|
||||
LIBS_EXTRA="${LIBS_EXTRA} -lcurl"],
|
||||
[AC_MSG_ERROR([unable to find neither libfetch nor libcurl])])
|
||||
])
|
||||
AC_SUBST(CURL_FOUND)
|
||||
AC_SUBST(CURL_LIBS)
|
||||
AC_SUBST(CURL_CFLAGS)
|
||||
])
|
||||
|
||||
AC_SUBST(LIBS_EXTRA)
|
||||
|
||||
AC_MSG_CHECKING(for GCC atomic builtins)
|
||||
AC_LINK_IFELSE([
|
||||
AC_LANG_SOURCE([[
|
||||
int main() {
|
||||
volatile unsigned long val = 1;
|
||||
__sync_synchronize();
|
||||
__sync_val_compare_and_swap(&val, 1, 0);
|
||||
__sync_add_and_fetch(&val, 1);
|
||||
__sync_sub_and_fetch(&val, 1);
|
||||
return 0;
|
||||
}
|
||||
]])
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([yes])
|
||||
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], [Has gcc/MSVC atomic intrinsics])
|
||||
],
|
||||
[
|
||||
AC_MSG_RESULT([no])
|
||||
AC_DEFINE([HAVE_ATOMIC_BUILTINS], [0], [Has gcc/MSVC atomic intrinsics])
|
||||
AC_MSG_WARN([Libucl references could be thread-unsafe because atomic builtins are missing])
|
||||
])
|
||||
|
||||
AC_CONFIG_FILES(Makefile \
|
||||
src/Makefile \
|
||||
tests/Makefile \
|
||||
utils/Makefile \
|
||||
doc/Makefile \
|
||||
libucl.pc)
|
||||
AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h])
|
||||
AC_OUTPUT
|
8
contrib/libucl/doc/Makefile.am
Normal file
8
contrib/libucl/doc/Makefile.am
Normal file
@ -0,0 +1,8 @@
|
||||
EXTRA_DIST = api.md
|
||||
|
||||
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/' | \
|
||||
@PANDOC@ -s -f markdown -t man -o libucl.3
|
@ -1,30 +1,75 @@
|
||||
Synopsis
|
||||
========
|
||||
# API documentation
|
||||
|
||||
**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*
|
||||
|
||||
- [Synopsis](#synopsis)
|
||||
- [Description](#description)
|
||||
- [Parser functions](#parser-functions)
|
||||
- [Emitting functions](#emitting-functions)
|
||||
- [Conversion functions](#conversion-functions)
|
||||
- [Generation functions](#generation-functions)
|
||||
- [Iteration functions](#iteration-functions)
|
||||
- [Validation functions](#validation-functions)
|
||||
- [Utility functions](#utility-functions)
|
||||
- [Parser functions](#parser-functions-1)
|
||||
- [ucl_parser_new](#ucl_parser_new)
|
||||
- [ucl_parser_register_macro](#ucl_parser_register_macro)
|
||||
- [ucl_parser_register_variable](#ucl_parser_register_variable)
|
||||
- [ucl_parser_add_chunk](#ucl_parser_add_chunk)
|
||||
- [ucl_parser_add_string](#ucl_parser_add_string)
|
||||
- [ucl_parser_add_file](#ucl_parser_add_file)
|
||||
- [ucl_parser_get_object](#ucl_parser_get_object)
|
||||
- [ucl_parser_get_error](#ucl_parser_get_error)
|
||||
- [ucl_parser_free](#ucl_parser_free)
|
||||
- [ucl_pubkey_add](#ucl_pubkey_add)
|
||||
- [ucl_parser_set_filevars](#ucl_parser_set_filevars)
|
||||
- [Parser usage example](#parser-usage-example)
|
||||
- [Emitting functions](#emitting-functions-1)
|
||||
- [ucl_object_emit](#ucl_object_emit)
|
||||
- [ucl_object_emit_full](#ucl_object_emit_full)
|
||||
- [Conversion functions](#conversion-functions-1)
|
||||
- [Generation functions](#generation-functions-1)
|
||||
- [ucl_object_new](#ucl_object_new)
|
||||
- [ucl_object_typed_new](#ucl_object_typed_new)
|
||||
- [Primitive objects generation](#primitive-objects-generation)
|
||||
- [ucl_object_fromstring_common](#ucl_object_fromstring_common)
|
||||
- [Iteration functions](#iteration-functions-1)
|
||||
- [ucl_iterate_object](#ucl_iterate_object)
|
||||
- [Validation functions](#validation-functions-1)
|
||||
- [ucl_object_validate](#ucl_object_validate)
|
||||
|
||||
# Synopsis
|
||||
|
||||
`#include <ucl.h>`
|
||||
|
||||
Description
|
||||
===========
|
||||
# Description
|
||||
|
||||
Libucl is a parser and `C` API to parse and generate `ucl` objects. Libucl consist of several groups of functions:
|
||||
|
||||
### Parser functions
|
||||
Used to parse `ucl` files and provide interface to extract `ucl` object
|
||||
Used to parse `ucl` files and provide interface to extract `ucl` object. Currently, `libucl` can parse only full `ucl` documents, for instance, it is impossible to parse a part of document and therefore it is impossible to use `libucl` as a streaming parser. In future, this limitation can be removed.
|
||||
|
||||
### Emitting functions
|
||||
Convert `ucl` objects to some textual or binary representation.
|
||||
Convert `ucl` objects to some textual or binary representation. Currently, libucl supports the following exports:
|
||||
|
||||
- `JSON` - valid json format (can possibly loose some original data, such as implicit arrays)
|
||||
- `Config` - human-readable configuration format (losseless)
|
||||
- `YAML` - embedded yaml format (has the same limitations as `json` output)
|
||||
|
||||
### Conversion functions
|
||||
Help to convert `ucl` objects to C types
|
||||
Help to convert `ucl` objects to C types. These functions are used to convert `ucl_object_t` to C primitive types, such as numbers, strings or boolean values.
|
||||
|
||||
### Generation functions
|
||||
Allow creating of `ucl` objects from C types
|
||||
Allow creating of `ucl` objects from C types and creating of complex `ucl` objects, such as hashes or arrays from primitive `ucl` objects, such as numbers or strings.
|
||||
|
||||
### Iteration functions
|
||||
Iterate over `ucl` objects
|
||||
Iterate over `ucl` complex objects or over a chain of values, for example when a key in an object has multiple values (that can be treated as implicit array or implicit consolidation).
|
||||
|
||||
### Validation functions
|
||||
Validation functions are used to validate some object `obj` using json-schema compatible object `schema`. Both input and schema must be UCL objects to perform validation.
|
||||
|
||||
### Utility functions
|
||||
Provide basic utilities to manage `ucl` objects
|
||||
Provide basic utilities to manage `ucl` objects: creating, removing, retaining and releasing reference count and so on.
|
||||
|
||||
# Parser functions
|
||||
|
||||
@ -40,6 +85,7 @@ Creates new parser with the specified flags:
|
||||
|
||||
- `UCL_PARSER_KEY_LOWERCASE` - lowercase keys parsed
|
||||
- `UCL_PARSER_ZEROCOPY` - try to use zero-copy mode when reading files (in zero-copy mode text chunk being parsed without copying strings so it should exist till any object parsed is used)
|
||||
- `UCL_PARSER_NO_TIME` - treat time values as strings without parsing them as floats
|
||||
|
||||
### ucl_parser_register_macro
|
||||
|
||||
@ -87,6 +133,14 @@ while this one won't be parsed correctly:
|
||||
|
||||
This limitation may possible be removed in future.
|
||||
|
||||
### ucl_parser_add_string
|
||||
~~~C
|
||||
bool ucl_parser_add_string (struct ucl_parser *parser,
|
||||
const char *data, size_t len);
|
||||
~~~
|
||||
|
||||
This function acts exactly like `ucl_parser_add_chunk` does but if `len` argument is zero, then the string `data` must be zero-terminated and the actual length is calculated up to `\0` character.
|
||||
|
||||
### ucl_parser_add_file
|
||||
|
||||
~~~C
|
||||
@ -228,7 +282,7 @@ Libucl provides the following functions for emitting UCL objects:
|
||||
### ucl_object_emit
|
||||
|
||||
~~~C
|
||||
unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
|
||||
unsigned char *ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type);
|
||||
~~~
|
||||
|
||||
Allocate a string that is suitable to fit the underlying UCL object `obj` and fill it with the textual representation of the object `obj` according to style `emit_type`. The caller should free the returned string after using.
|
||||
@ -236,7 +290,7 @@ Allocate a string that is suitable to fit the underlying UCL object `obj` and fi
|
||||
### ucl_object_emit_full
|
||||
|
||||
~~~C
|
||||
bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
bool ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
struct ucl_emitter_functions *emitter);
|
||||
~~~
|
||||
|
||||
@ -314,19 +368,20 @@ This function is used to convert a string `str` of size `len` to an UCL objects
|
||||
- `UCL_STRING_PARSE_BOOLEAN` - parse passed string and detect boolean
|
||||
- `UCL_STRING_PARSE_INT` - parse passed string and detect integer number
|
||||
- `UCL_STRING_PARSE_DOUBLE` - parse passed string and detect integer or float number
|
||||
- `UCL_STRING_PARSE_NUMBER` - parse passed string and detect number (both float or integer types)
|
||||
- `UCL_STRING_PARSE` - parse passed string (and detect booleans and numbers)
|
||||
- `UCL_STRING_PARSE_TIME` - parse time values as floating point numbers
|
||||
- `UCL_STRING_PARSE_NUMBER` - parse passed string and detect number (both float, integer and time types)
|
||||
- `UCL_STRING_PARSE` - parse passed string (and detect booleans, numbers and time values)
|
||||
- `UCL_STRING_PARSE_BYTES` - assume that numeric multipliers are in bytes notation, for example `10k` means `10*1024` and not `10*1000` as assumed without this flag
|
||||
|
||||
If parsing operations fail then the resulting UCL object will be a `UCL_STRING`. A caller should always check the type of the returned object and release it after using.
|
||||
|
||||
# Iteration function
|
||||
# Iteration functions
|
||||
|
||||
Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). To iterate over an object, an array or a key with multiple values there is a function `ucl_iterate_object`.
|
||||
|
||||
## ucl_iterate_object
|
||||
~~~C
|
||||
ucl_object_t* ucl_iterate_object (ucl_object_t *obj,
|
||||
const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
|
||||
ucl_object_iter_t *iter, bool expand_values);
|
||||
~~~
|
||||
|
||||
@ -334,7 +389,7 @@ This function accept opaque iterator pointer `iter`. In the first call this iter
|
||||
|
||||
~~~C
|
||||
ucl_object_iter_t it = NULL, it_obj = NULL;
|
||||
ucl_object_t *cur, *tmp;
|
||||
const ucl_object_t *cur, *tmp;
|
||||
|
||||
/* Iterate over the object */
|
||||
while ((obj = ucl_iterate_object (top, &it, true))) {
|
||||
@ -345,4 +400,40 @@ while ((obj = ucl_iterate_object (top, &it, true))) {
|
||||
ucl_object_tostring_forced (cur));
|
||||
}
|
||||
}
|
||||
~~~
|
||||
~~~
|
||||
|
||||
# Validation functions
|
||||
|
||||
Currently, there is only one validation function called `ucl_object_validate`. It performs validation of object using the specified schema. This function is defined as following:
|
||||
|
||||
## ucl_object_validate
|
||||
~~~C
|
||||
bool ucl_object_validate (const ucl_object_t *schema,
|
||||
const ucl_object_t *obj, struct ucl_schema_error *err);
|
||||
~~~
|
||||
|
||||
This function uses ucl object `schema`, that must be valid in terms of `json-schema` draft v4, to validate input object `obj`. If this function returns `true` then validation procedure has been succeed. Otherwise, `false` is returned and `err` is set to a specific value. If caller set `err` to NULL then this function does not set any error just returning `false`. Error is the structure defined as following:
|
||||
|
||||
~~~C
|
||||
struct ucl_schema_error {
|
||||
enum ucl_schema_error_code code; /* error code */
|
||||
char msg[128]; /* error message */
|
||||
ucl_object_t *obj; /* object where error occured */
|
||||
};
|
||||
~~~
|
||||
|
||||
Caller may use `code` field to get a numeric error code:
|
||||
|
||||
~~~C
|
||||
enum ucl_schema_error_code {
|
||||
UCL_SCHEMA_OK = 0, /* no error */
|
||||
UCL_SCHEMA_TYPE_MISMATCH, /* type of object is incorrect */
|
||||
UCL_SCHEMA_INVALID_SCHEMA, /* schema is invalid */
|
||||
UCL_SCHEMA_MISSING_PROPERTY,/* missing properties */
|
||||
UCL_SCHEMA_CONSTRAINT, /* constraint found */
|
||||
UCL_SCHEMA_MISSING_DEPENDENCY, /* missing dependency */
|
||||
UCL_SCHEMA_UNKNOWN /* generic error */
|
||||
};
|
||||
~~~
|
||||
|
||||
`msg` is a stiring description of an error and `obj` is an object where error has been occurred. Error object is not allocated by libucl, so there is no need to free it after validation (a static object should thus be used).
|
637
contrib/libucl/doc/libucl.3
Normal file
637
contrib/libucl/doc/libucl.3
Normal file
@ -0,0 +1,637 @@
|
||||
.TH LIBUCL 5 "March 20, 2014" "Libucl manual"
|
||||
.SH NAME
|
||||
.PP
|
||||
\f[B]ucl_parser_new\f[], \f[B]ucl_parser_register_macro\f[],
|
||||
\f[B]ucl_parser_register_variable\f[], \f[B]ucl_parser_add_chunk\f[],
|
||||
\f[B]ucl_parser_add_string\f[], \f[B]ucl_parser_add_file\f[],
|
||||
\f[B]ucl_parser_get_object\f[], \f[B]ucl_parser_get_error\f[],
|
||||
\f[B]ucl_parser_free\f[], \f[B]ucl_pubkey_add\f[],
|
||||
\f[B]ucl_parser_set_filevars\f[] \- universal configuration library
|
||||
parser and utility functions
|
||||
.SH LIBRARY
|
||||
.PP
|
||||
UCL library (libucl, \-lucl)
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
\f[C]#include\ <ucl.h>\f[]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Libucl is a parser and \f[C]C\f[] API to parse and generate \f[C]ucl\f[]
|
||||
objects.
|
||||
Libucl consist of several groups of functions:
|
||||
.SS Parser functions
|
||||
.PP
|
||||
Used to parse \f[C]ucl\f[] files and provide interface to extract
|
||||
\f[C]ucl\f[] object.
|
||||
Currently, \f[C]libucl\f[] can parse only full \f[C]ucl\f[] documents,
|
||||
for instance, it is impossible to parse a part of document and therefore
|
||||
it is impossible to use \f[C]libucl\f[] as a streaming parser.
|
||||
In future, this limitation can be removed.
|
||||
.SS Emitting functions
|
||||
.PP
|
||||
Convert \f[C]ucl\f[] objects to some textual or binary representation.
|
||||
Currently, libucl supports the following exports:
|
||||
.IP \[bu] 2
|
||||
\f[C]JSON\f[] \- valid json format (can possibly loose some original
|
||||
data, such as implicit arrays)
|
||||
.IP \[bu] 2
|
||||
\f[C]Config\f[] \- human\-readable configuration format (losseless)
|
||||
.IP \[bu] 2
|
||||
\f[C]YAML\f[] \- embedded yaml format (has the same limitations as
|
||||
\f[C]json\f[] output)
|
||||
.SS Conversion functions
|
||||
.PP
|
||||
Help to convert \f[C]ucl\f[] objects to C types.
|
||||
These functions are used to convert \f[C]ucl_object_t\f[] to C primitive
|
||||
types, such as numbers, strings or boolean values.
|
||||
.SS Generation functions
|
||||
.PP
|
||||
Allow creating of \f[C]ucl\f[] objects from C types and creating of
|
||||
complex \f[C]ucl\f[] objects, such as hashes or arrays from primitive
|
||||
\f[C]ucl\f[] objects, such as numbers or strings.
|
||||
.SS Iteration functions
|
||||
.PP
|
||||
Iterate over \f[C]ucl\f[] complex objects or over a chain of values, for
|
||||
example when a key in an object has multiple values (that can be treated
|
||||
as implicit array or implicit consolidation).
|
||||
.SS Validation functions
|
||||
.PP
|
||||
Validation functions are used to validate some object \f[C]obj\f[] using
|
||||
json\-schema compatible object \f[C]schema\f[].
|
||||
Both input and schema must be UCL objects to perform validation.
|
||||
.SS Utility functions
|
||||
.PP
|
||||
Provide basic utilities to manage \f[C]ucl\f[] objects: creating,
|
||||
removing, retaining and releasing reference count and so on.
|
||||
.SH PARSER FUNCTIONS
|
||||
.PP
|
||||
Parser functions operates with \f[C]struct\ ucl_parser\f[].
|
||||
.SS ucl_parser_new
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
struct\ ucl_parser*\ ucl_parser_new\ (int\ flags);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Creates new parser with the specified flags:
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_PARSER_KEY_LOWERCASE\f[] \- lowercase keys parsed
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_PARSER_ZEROCOPY\f[] \- try to use zero\-copy mode when reading
|
||||
files (in zero\-copy mode text chunk being parsed without copying
|
||||
strings so it should exist till any object parsed is used)
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_PARSER_NO_TIME\f[] \- treat time values as strings without
|
||||
parsing them as floats
|
||||
.SS ucl_parser_register_macro
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
void\ ucl_parser_register_macro\ (struct\ ucl_parser\ *parser,
|
||||
\ \ \ \ const\ char\ *macro,\ ucl_macro_handler\ handler,\ void*\ ud);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Register new macro with name .\f[C]macro\f[] parsed by handler
|
||||
\f[C]handler\f[] that accepts opaque data pointer \f[C]ud\f[].
|
||||
Macro handler should be of the following type:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ (*ucl_macro_handler)\ (const\ unsigned\ char\ *data,
|
||||
\ \ \ \ size_t\ len,\ void*\ ud);`
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Handler function accepts macro text \f[C]data\f[] of length \f[C]len\f[]
|
||||
and the opaque pointer \f[C]ud\f[].
|
||||
If macro is parsed successfully the handler should return \f[C]true\f[].
|
||||
\f[C]false\f[] indicates parsing failure and the parser can be
|
||||
terminated.
|
||||
.SS ucl_parser_register_variable
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
void\ ucl_parser_register_variable\ (struct\ ucl_parser\ *parser,
|
||||
\ \ \ \ const\ char\ *var,\ const\ char\ *value);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Register new variable $\f[C]var\f[] that should be replaced by the
|
||||
parser to the \f[C]value\f[] string.
|
||||
.SS ucl_parser_add_chunk
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_parser_add_chunk\ (struct\ ucl_parser\ *parser,\
|
||||
\ \ \ \ const\ unsigned\ char\ *data,\ size_t\ len);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Add new text chunk with \f[C]data\f[] of length \f[C]len\f[] to the
|
||||
parser.
|
||||
At the moment, \f[C]libucl\f[] parser is not a streamlined parser and
|
||||
chunk \f[I]must\f[] contain the \f[I]valid\f[] ucl object.
|
||||
For example, this object should be valid:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
{\ "var":\ "value"\ }
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
while this one won\[aq]t be parsed correctly:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
{\ "var":\
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This limitation may possible be removed in future.
|
||||
.SS ucl_parser_add_string
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_parser_add_string\ (struct\ ucl_parser\ *parser,\
|
||||
\ \ \ \ const\ char\ *data,\ size_t\ len);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function acts exactly like \f[C]ucl_parser_add_chunk\f[] does but
|
||||
if \f[C]len\f[] argument is zero, then the string \f[C]data\f[] must be
|
||||
zero\-terminated and the actual length is calculated up to \f[C]\\0\f[]
|
||||
character.
|
||||
.SS ucl_parser_add_file
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_parser_add_file\ (struct\ ucl_parser\ *parser,\
|
||||
\ \ \ \ const\ char\ *filename);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Load file \f[C]filename\f[] and parse it with the specified
|
||||
\f[C]parser\f[].
|
||||
This function uses \f[C]mmap\f[] call to load file, therefore, it should
|
||||
not be \f[C]shrinked\f[] during parsing.
|
||||
Otherwise, \f[C]libucl\f[] can cause memory corruption and terminate the
|
||||
calling application.
|
||||
This function is also used by the internal handler of \f[C]include\f[]
|
||||
macro, hence, this macro has the same limitation.
|
||||
.SS ucl_parser_get_object
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
ucl_object_t*\ ucl_parser_get_object\ (struct\ ucl_parser\ *parser);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
If the \f[C]ucl\f[] data has been parsed correctly this function returns
|
||||
the top object for the parser.
|
||||
Otherwise, this function returns the \f[C]NULL\f[] pointer.
|
||||
The reference count for \f[C]ucl\f[] object returned is increased by
|
||||
one, therefore, a caller should decrease reference by using
|
||||
\f[C]ucl_object_unref\f[] to free object after usage.
|
||||
.SS ucl_parser_get_error
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
const\ char\ *ucl_parser_get_error(struct\ ucl_parser\ *parser);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Returns the constant error string for the parser object.
|
||||
If no error occurred during parsing a \f[C]NULL\f[] object is returned.
|
||||
A caller should not try to free or modify this string.
|
||||
.SS ucl_parser_free
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
void\ ucl_parser_free\ (struct\ ucl_parser\ *parser);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Frees memory occupied by the parser object.
|
||||
The reference count for top object is decreased as well, however if the
|
||||
function \f[C]ucl_parser_get_object\f[] was called previously then the
|
||||
top object won\[aq]t be freed.
|
||||
.SS ucl_pubkey_add
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_pubkey_add\ (struct\ ucl_parser\ *parser,\
|
||||
\ \ \ \ const\ unsigned\ char\ *key,\ size_t\ len);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function adds a public key from text blob \f[C]key\f[] of length
|
||||
\f[C]len\f[] to the \f[C]parser\f[] object.
|
||||
This public key should be in the \f[C]PEM\f[] format and can be used by
|
||||
\f[C]\&.includes\f[] macro for checking signatures of files included.
|
||||
\f[C]Openssl\f[] support should be enabled to make this function
|
||||
working.
|
||||
If a key cannot be added (e.g.
|
||||
due to format error) or \f[C]openssl\f[] was not linked to
|
||||
\f[C]libucl\f[] then this function returns \f[C]false\f[].
|
||||
.SS ucl_parser_set_filevars
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_parser_set_filevars\ (struct\ ucl_parser\ *parser,\
|
||||
\ \ \ \ const\ char\ *filename,\ bool\ need_expand);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Add the standard file variables to the \f[C]parser\f[] based on the
|
||||
\f[C]filename\f[] specified:
|
||||
.IP \[bu] 2
|
||||
\f[C]$FILENAME\f[] \- a filename of \f[C]ucl\f[] input
|
||||
.IP \[bu] 2
|
||||
\f[C]$CURDIR\f[] \- a current directory of the input
|
||||
.PP
|
||||
For example, if a \f[C]filename\f[] param is
|
||||
\f[C]\&../something.conf\f[] then the variables will have the following
|
||||
values:
|
||||
.IP \[bu] 2
|
||||
\f[C]$FILENAME\f[] \- "../something.conf"
|
||||
.IP \[bu] 2
|
||||
\f[C]$CURDIR\f[] \- ".."
|
||||
.PP
|
||||
if \f[C]need_expand\f[] parameter is \f[C]true\f[] then all relative
|
||||
paths are expanded using \f[C]realpath\f[] call.
|
||||
In this example if \f[C]\&..\f[] is \f[C]/etc/dir\f[] then variables
|
||||
will have these values:
|
||||
.IP \[bu] 2
|
||||
\f[C]$FILENAME\f[] \- "/etc/something.conf"
|
||||
.IP \[bu] 2
|
||||
\f[C]$CURDIR\f[] \- "/etc"
|
||||
.SS Parser usage example
|
||||
.PP
|
||||
The following example loads, parses and extracts \f[C]ucl\f[] object
|
||||
from stdin using \f[C]libucl\f[] parser functions (the length of input
|
||||
is limited to 8K):
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
char\ inbuf[8192];
|
||||
struct\ ucl_parser\ *parser\ =\ NULL;
|
||||
int\ ret\ =\ 0,\ r\ =\ 0;
|
||||
ucl_object_t\ *obj\ =\ NULL;
|
||||
FILE\ *in;
|
||||
|
||||
in\ =\ stdin;
|
||||
parser\ =\ ucl_parser_new\ (0);
|
||||
while\ (!feof\ (in)\ &&\ r\ <\ (int)sizeof\ (inbuf))\ {
|
||||
\ \ \ \ r\ +=\ fread\ (inbuf\ +\ r,\ 1,\ sizeof\ (inbuf)\ \-\ r,\ in);
|
||||
}
|
||||
ucl_parser_add_chunk\ (parser,\ inbuf,\ r);
|
||||
fclose\ (in);
|
||||
|
||||
if\ (ucl_parser_get_error\ (parser))\ {
|
||||
\ \ \ \ printf\ ("Error\ occured:\ %s\\n",\ ucl_parser_get_error\ (parser));
|
||||
\ \ \ \ ret\ =\ 1;
|
||||
}
|
||||
else\ {
|
||||
\ \ \ \ obj\ =\ ucl_parser_get_object\ (parser);
|
||||
}
|
||||
|
||||
if\ (parser\ !=\ NULL)\ {
|
||||
\ \ \ \ ucl_parser_free\ (parser);
|
||||
}
|
||||
if\ (obj\ !=\ NULL)\ {
|
||||
\ \ \ \ ucl_object_unref\ (obj);
|
||||
}
|
||||
return\ ret;
|
||||
\f[]
|
||||
.fi
|
||||
.SH EMITTING FUNCTIONS
|
||||
.PP
|
||||
Libucl can transform UCL objects to a number of tectual formats:
|
||||
.IP \[bu] 2
|
||||
configuration (\f[C]UCL_EMIT_CONFIG\f[]) \- nginx like human readable
|
||||
configuration file where implicit arrays are transformed to the
|
||||
duplicate keys
|
||||
.IP \[bu] 2
|
||||
compact json: \f[C]UCL_EMIT_JSON_COMPACT\f[] \- single line valid json
|
||||
without spaces
|
||||
.IP \[bu] 2
|
||||
formatted json: \f[C]UCL_EMIT_JSON\f[] \- pretty formatted JSON with
|
||||
newlines and spaces
|
||||
.IP \[bu] 2
|
||||
compact yaml: \f[C]UCL_EMIT_YAML\f[] \- compact YAML output
|
||||
.PP
|
||||
Moreover, libucl API allows to select a custom set of emitting functions
|
||||
allowing efficent and zero\-copy output of libucl objects.
|
||||
Libucl uses the following structure to support this feature:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
struct\ ucl_emitter_functions\ {
|
||||
\ \ \ \ /**\ Append\ a\ single\ character\ */
|
||||
\ \ \ \ int\ (*ucl_emitter_append_character)\ (unsigned\ char\ c,\ size_t\ nchars,\ void\ *ud);
|
||||
\ \ \ \ /**\ Append\ a\ string\ of\ a\ specified\ length\ */
|
||||
\ \ \ \ int\ (*ucl_emitter_append_len)\ (unsigned\ const\ char\ *str,\ size_t\ len,\ void\ *ud);
|
||||
\ \ \ \ /**\ Append\ a\ 64\ bit\ integer\ */
|
||||
\ \ \ \ int\ (*ucl_emitter_append_int)\ (int64_t\ elt,\ void\ *ud);
|
||||
\ \ \ \ /**\ Append\ floating\ point\ element\ */
|
||||
\ \ \ \ int\ (*ucl_emitter_append_double)\ (double\ elt,\ void\ *ud);
|
||||
\ \ \ \ /**\ Opaque\ userdata\ pointer\ */
|
||||
\ \ \ \ void\ *ud;
|
||||
};
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This structure defines the following callbacks:
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_emitter_append_character\f[] \- a function that is called to
|
||||
append \f[C]nchars\f[] characters equal to \f[C]c\f[]
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_emitter_append_len\f[] \- used to append a string of length
|
||||
\f[C]len\f[] starting from pointer \f[C]str\f[]
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_emitter_append_int\f[] \- this function applies to integer
|
||||
numbers
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_emitter_append_double\f[] \- this function is intended to
|
||||
output floating point variable
|
||||
.PP
|
||||
The set of these functions could be used to output text formats of
|
||||
\f[C]UCL\f[] objects to different structures or streams.
|
||||
.PP
|
||||
Libucl provides the following functions for emitting UCL objects:
|
||||
.SS ucl_object_emit
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
unsigned\ char\ *ucl_object_emit\ (const\ ucl_object_t\ *obj,\ enum\ ucl_emitter\ emit_type);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Allocate a string that is suitable to fit the underlying UCL object
|
||||
\f[C]obj\f[] and fill it with the textual representation of the object
|
||||
\f[C]obj\f[] according to style \f[C]emit_type\f[].
|
||||
The caller should free the returned string after using.
|
||||
.SS ucl_object_emit_full
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_object_emit_full\ (const\ ucl_object_t\ *obj,\ enum\ ucl_emitter\ emit_type,
|
||||
\ \ \ \ \ \ \ \ struct\ ucl_emitter_functions\ *emitter);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function is similar to the previous with the exception that it
|
||||
accepts the additional argument \f[C]emitter\f[] that defines the
|
||||
concrete set of output functions.
|
||||
This emit function could be useful for custom structures or streams
|
||||
emitters (including C++ ones, for example).
|
||||
.SH CONVERSION FUNCTIONS
|
||||
.PP
|
||||
Conversion functions are used to convert UCL objects to primitive types,
|
||||
such as strings, numbers or boolean values.
|
||||
There are two types of conversion functions:
|
||||
.IP \[bu] 2
|
||||
safe: try to convert an ucl object to a primitive type and fail if such
|
||||
a conversion is not possible
|
||||
.IP \[bu] 2
|
||||
unsafe: return primitive type without additional checks, if the object
|
||||
cannot be converted then some reasonable default is returned (NULL for
|
||||
strings and 0 for numbers)
|
||||
.PP
|
||||
Also there is a single \f[C]ucl_object_tostring_forced\f[] function that
|
||||
converts any UCL object (including compound types \- arrays and objects)
|
||||
to a string representation.
|
||||
For compound and numeric types this function performs emitting to a
|
||||
compact json format actually.
|
||||
.PP
|
||||
Here is a list of all conversion functions:
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_toint\f[] \- returns \f[C]int64_t\f[] of UCL object
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_todouble\f[] \- returns \f[C]double\f[] of UCL object
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_toboolean\f[] \- returns \f[C]bool\f[] of UCL object
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_tostring\f[] \- returns \f[C]const\ char\ *\f[] of UCL
|
||||
object (this string is NULL terminated)
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_tolstring\f[] \- returns \f[C]const\ char\ *\f[] and
|
||||
\f[C]size_t\f[] len of UCL object (string can be not NULL terminated)
|
||||
.IP \[bu] 2
|
||||
\f[C]ucl_object_tostring_forced\f[] \- returns string representation of
|
||||
any UCL object
|
||||
.PP
|
||||
Strings returned by these pointers are associated with the UCL object
|
||||
and exist over its lifetime.
|
||||
A caller should not free this memory.
|
||||
.SH GENERATION FUNCTIONS
|
||||
.PP
|
||||
It is possible to generate UCL objects from C primitive types.
|
||||
Moreover, libucl permits to create and modify complex UCL objects, such
|
||||
as arrays or associative objects.
|
||||
.SS ucl_object_new
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
ucl_object_t\ *\ ucl_object_new\ (void)
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Creates new object of type \f[C]UCL_NULL\f[].
|
||||
This object should be released by caller.
|
||||
.SS ucl_object_typed_new
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
ucl_object_t\ *\ ucl_object_typed_new\ (unsigned\ int\ type)
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Create an object of a specified type: \- \f[C]UCL_OBJECT\f[] \- UCL
|
||||
object \- key/value pairs \- \f[C]UCL_ARRAY\f[] \- UCL array \-
|
||||
\f[C]UCL_INT\f[] \- integer number \- \f[C]UCL_FLOAT\f[] \- floating
|
||||
point number \- \f[C]UCL_STRING\f[] \- NULL terminated string \-
|
||||
\f[C]UCL_BOOLEAN\f[] \- boolean value \- \f[C]UCL_TIME\f[] \- time value
|
||||
(floating point number of seconds) \- \f[C]UCL_USERDATA\f[] \- opaque
|
||||
userdata pointer (may be used in macros) \- \f[C]UCL_NULL\f[] \- null
|
||||
value
|
||||
.PP
|
||||
This object should be released by caller.
|
||||
.SS Primitive objects generation
|
||||
.PP
|
||||
Libucl provides the functions similar to inverse conversion functions
|
||||
called with the specific C type: \- \f[C]ucl_object_fromint\f[] \-
|
||||
converts \f[C]int64_t\f[] to UCL object \-
|
||||
\f[C]ucl_object_fromdouble\f[] \- converts \f[C]double\f[] to UCL object
|
||||
\- \f[C]ucl_object_fromboolean\f[] \- converts \f[C]bool\f[] to UCL
|
||||
object \- \f[C]ucl_object_fromstring\f[] \- converts
|
||||
\f[C]const\ char\ *\f[] to UCL object (this string is NULL terminated)
|
||||
\- \f[C]ucl_object_fromlstring\f[] \- converts \f[C]const\ char\ *\f[]
|
||||
and \f[C]size_t\f[] len to UCL object (string can be not NULL
|
||||
terminated)
|
||||
.PP
|
||||
Also there is a function to generate UCL object from a string performing
|
||||
various parsing or conversion operations called
|
||||
\f[C]ucl_object_fromstring_common\f[].
|
||||
.SS ucl_object_fromstring_common
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
ucl_object_t\ *\ ucl_object_fromstring_common\ (const\ char\ *str,\
|
||||
\ \ \ \ size_t\ len,\ enum\ ucl_string_flags\ flags)
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function is used to convert a string \f[C]str\f[] of size
|
||||
\f[C]len\f[] to an UCL objects applying \f[C]flags\f[] conversions.
|
||||
If \f[C]len\f[] is equal to zero then a \f[C]str\f[] is assumed as
|
||||
NULL\-terminated.
|
||||
This function supports the following flags (a set of flags can be
|
||||
specified using logical \f[C]OR\f[] operation):
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_ESCAPE\f[] \- perform JSON escape
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_TRIM\f[] \- trim leading and trailing whitespaces
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_BOOLEAN\f[] \- parse passed string and detect
|
||||
boolean
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_INT\f[] \- parse passed string and detect integer
|
||||
number
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_DOUBLE\f[] \- parse passed string and detect
|
||||
integer or float number
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_TIME\f[] \- parse time values as floating point
|
||||
numbers
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_NUMBER\f[] \- parse passed string and detect
|
||||
number (both float, integer and time types)
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE\f[] \- parse passed string (and detect booleans,
|
||||
numbers and time values)
|
||||
.IP \[bu] 2
|
||||
\f[C]UCL_STRING_PARSE_BYTES\f[] \- assume that numeric multipliers are
|
||||
in bytes notation, for example \f[C]10k\f[] means \f[C]10*1024\f[] and
|
||||
not \f[C]10*1000\f[] as assumed without this flag
|
||||
.PP
|
||||
If parsing operations fail then the resulting UCL object will be a
|
||||
\f[C]UCL_STRING\f[].
|
||||
A caller should always check the type of the returned object and release
|
||||
it after using.
|
||||
.SH ITERATION FUNCTIONS
|
||||
.PP
|
||||
Iteration are used to iterate over UCL compound types: arrays and
|
||||
objects.
|
||||
Moreover, iterations could be performed over the keys with multiple
|
||||
values (implicit arrays).
|
||||
To iterate over an object, an array or a key with multiple values there
|
||||
is a function \f[C]ucl_iterate_object\f[].
|
||||
.SS ucl_iterate_object
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
const\ ucl_object_t*\ ucl_iterate_object\ (const\ ucl_object_t\ *obj,\
|
||||
\ \ \ \ ucl_object_iter_t\ *iter,\ bool\ expand_values);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function accept opaque iterator pointer \f[C]iter\f[].
|
||||
In the first call this iterator \f[I]must\f[] be initialized to
|
||||
\f[C]NULL\f[].
|
||||
Iterator is changed by this function call.
|
||||
\f[C]ucl_iterate_object\f[] returns the next UCL object in the compound
|
||||
object \f[C]obj\f[] or \f[C]NULL\f[] if all objects have been iterated.
|
||||
The reference count of the object returned is not increased, so a caller
|
||||
should not unref the object or modify its content (e.g.
|
||||
by inserting to another compound object).
|
||||
The object \f[C]obj\f[] should not be changed during the iteration
|
||||
process as well.
|
||||
\f[C]expand_values\f[] flag speicifies whether
|
||||
\f[C]ucl_iterate_object\f[] should expand keys with multiple values.
|
||||
The general rule is that if you need to iterate throught the
|
||||
\f[I]object\f[] or \f[I]explicit array\f[], then you always need to set
|
||||
this flag to \f[C]true\f[].
|
||||
However, if you get some key in the object and want to extract all its
|
||||
values then you should set \f[C]expand_values\f[] to \f[C]false\f[].
|
||||
Mixing of iteration types are not permitted since the iterator is set
|
||||
according to the iteration type and cannot be reused.
|
||||
Here is an example of iteration over the objects using libucl API
|
||||
(assuming that \f[C]top\f[] is \f[C]UCL_OBJECT\f[] in this example):
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
ucl_object_iter_t\ it\ =\ NULL,\ it_obj\ =\ NULL;
|
||||
const\ ucl_object_t\ *cur,\ *tmp;
|
||||
|
||||
/*\ Iterate\ over\ the\ object\ */
|
||||
while\ ((obj\ =\ ucl_iterate_object\ (top,\ &it,\ true)))\ {
|
||||
\ \ \ \ printf\ ("key:\ \\"%s\\"\\n",\ ucl_object_key\ (obj));
|
||||
\ \ \ \ /*\ Iterate\ over\ the\ values\ of\ a\ key\ */
|
||||
\ \ \ \ while\ ((cur\ =\ ucl_iterate_object\ (obj,\ &it_obj,\ false)))\ {
|
||||
\ \ \ \ \ \ \ \ printf\ ("value:\ \\"%s\\"\\n",\
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ ucl_object_tostring_forced\ (cur));
|
||||
\ \ \ \ }
|
||||
}
|
||||
\f[]
|
||||
.fi
|
||||
.SH VALIDATION FUNCTIONS
|
||||
.PP
|
||||
Currently, there is only one validation function called
|
||||
\f[C]ucl_object_validate\f[].
|
||||
It performs validation of object using the specified schema.
|
||||
This function is defined as following:
|
||||
.SS ucl_object_validate
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
bool\ ucl_object_validate\ (const\ ucl_object_t\ *schema,
|
||||
\ \ \ \ const\ ucl_object_t\ *obj,\ struct\ ucl_schema_error\ *err);
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
This function uses ucl object \f[C]schema\f[], that must be valid in
|
||||
terms of \f[C]json\-schema\f[] draft v4, to validate input object
|
||||
\f[C]obj\f[].
|
||||
If this function returns \f[C]true\f[] then validation procedure has
|
||||
been succeed.
|
||||
Otherwise, \f[C]false\f[] is returned and \f[C]err\f[] is set to a
|
||||
specific value.
|
||||
If caller set \f[C]err\f[] to NULL then this function does not set any
|
||||
error just returning \f[C]false\f[].
|
||||
Error is the structure defined as following:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
struct\ ucl_schema_error\ {
|
||||
\ \ \ \ enum\ ucl_schema_error_code\ code;\ \ \ \ /*\ error\ code\ */
|
||||
\ \ \ \ char\ msg[128];\ \ \ \ \ \ \ \ \ \ \ \ \ \ /*\ error\ message\ */
|
||||
\ \ \ \ ucl_object_t\ *obj;\ \ \ \ \ \ \ \ \ \ /*\ object\ where\ error\ occured\ */
|
||||
};
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
Caller may use \f[C]code\f[] field to get a numeric error code:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
enum\ ucl_schema_error_code\ {
|
||||
\ \ \ \ UCL_SCHEMA_OK\ =\ 0,\ \ \ \ \ \ \ \ \ \ /*\ no\ error\ */
|
||||
\ \ \ \ UCL_SCHEMA_TYPE_MISMATCH,\ \ \ /*\ type\ of\ object\ is\ incorrect\ */
|
||||
\ \ \ \ UCL_SCHEMA_INVALID_SCHEMA,\ \ /*\ schema\ is\ invalid\ */
|
||||
\ \ \ \ UCL_SCHEMA_MISSING_PROPERTY,/*\ missing\ properties\ */
|
||||
\ \ \ \ UCL_SCHEMA_CONSTRAINT,\ \ \ \ \ \ /*\ constraint\ found\ */
|
||||
\ \ \ \ UCL_SCHEMA_MISSING_DEPENDENCY,\ /*\ missing\ dependency\ */
|
||||
\ \ \ \ UCL_SCHEMA_UNKNOWN\ \ \ \ \ \ \ \ \ \ /*\ generic\ error\ */
|
||||
};
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
\f[C]msg\f[] is a stiring description of an error and \f[C]obj\f[] is an
|
||||
object where error has been occurred.
|
||||
Error object is not allocated by libucl, so there is no need to free it
|
||||
after validation (a static object should thus be used).
|
||||
.SH AUTHORS
|
||||
Vsevolod Stakhov <vsevolod@highsecure.ru>.
|
12
contrib/libucl/doc/pandoc.template
Normal file
12
contrib/libucl/doc/pandoc.template
Normal file
@ -0,0 +1,12 @@
|
||||
% LIBUCL(5) Libucl manual
|
||||
% Vsevolod Stakhov <vsevolod@highsecure.ru>
|
||||
% March 20, 2014
|
||||
|
||||
# Name
|
||||
|
||||
**ucl_parser_new**, **ucl_parser_register_macro**, **ucl_parser_register_variable**, **ucl_parser_add_chunk**, **ucl_parser_add_string**, **ucl_parser_add_file**, **ucl_parser_get_object**, **ucl_parser_get_error**, **ucl_parser_free**, **ucl_pubkey_add**, **ucl_parser_set_filevars** - universal configuration library parser and utility functions
|
||||
|
||||
# Library
|
||||
|
||||
UCL library (libucl, -lucl)
|
||||
|
@ -81,6 +81,14 @@ extern "C" {
|
||||
#define UCL_WARN_UNUSED_RESULT
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define UCL_DEPRECATED(func) func __attribute__ ((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define UCL_DEPRECATED(func) __declspec(deprecated) func
|
||||
#else
|
||||
#define UCL_DEPRECATED(func) func
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @defgroup structures Structures and types
|
||||
* UCL defines several enumeration types used for error reporting or specifying flags and attributes.
|
||||
@ -138,7 +146,8 @@ typedef enum ucl_emitter {
|
||||
*/
|
||||
typedef enum ucl_parser_flags {
|
||||
UCL_PARSER_KEY_LOWERCASE = 0x1, /**< Convert all keys to lower case */
|
||||
UCL_PARSER_ZEROCOPY = 0x2 /**< Parse input in zero-copy mode if possible */
|
||||
UCL_PARSER_ZEROCOPY = 0x2, /**< Parse input in zero-copy mode if possible */
|
||||
UCL_PARSER_NO_TIME = 0x4 /**< Do not parse time and treat time values as strings */
|
||||
} ucl_parser_flags_t;
|
||||
|
||||
/**
|
||||
@ -150,11 +159,12 @@ typedef enum ucl_string_flags {
|
||||
UCL_STRING_PARSE_BOOLEAN = 0x4, /**< Parse passed string and detect boolean */
|
||||
UCL_STRING_PARSE_INT = 0x8, /**< Parse passed string and detect integer number */
|
||||
UCL_STRING_PARSE_DOUBLE = 0x10, /**< Parse passed string and detect integer or float number */
|
||||
UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE , /**<
|
||||
UCL_STRING_PARSE_TIME = 0x20, /**< Parse time strings */
|
||||
UCL_STRING_PARSE_NUMBER = UCL_STRING_PARSE_INT|UCL_STRING_PARSE_DOUBLE|UCL_STRING_PARSE_TIME, /**<
|
||||
Parse passed string and detect number */
|
||||
UCL_STRING_PARSE = UCL_STRING_PARSE_BOOLEAN|UCL_STRING_PARSE_NUMBER, /**<
|
||||
Parse passed string (and detect booleans and numbers) */
|
||||
UCL_STRING_PARSE_BYTES = 0x20 /**< Treat numbers as bytes */
|
||||
UCL_STRING_PARSE_BYTES = 0x40 /**< Treat numbers as bytes */
|
||||
} ucl_string_flags_t;
|
||||
|
||||
/**
|
||||
@ -206,51 +216,33 @@ typedef struct ucl_object_s {
|
||||
* @param obj CL object
|
||||
* @return zero terminated key
|
||||
*/
|
||||
UCL_EXTERN char* ucl_copy_key_trash (ucl_object_t *obj);
|
||||
UCL_EXTERN char* ucl_copy_key_trash (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Copy and return a string value of an object, returned key is zero-terminated
|
||||
* @param obj CL object
|
||||
* @return zero terminated string representation of object value
|
||||
*/
|
||||
UCL_EXTERN char* ucl_copy_value_trash (ucl_object_t *obj);
|
||||
UCL_EXTERN char* ucl_copy_value_trash (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Creates a new object
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT;
|
||||
static inline ucl_object_t *
|
||||
ucl_object_new (void)
|
||||
{
|
||||
ucl_object_t *new;
|
||||
new = malloc (sizeof (ucl_object_t));
|
||||
if (new != NULL) {
|
||||
memset (new, 0, sizeof (ucl_object_t));
|
||||
new->ref = 1;
|
||||
new->type = UCL_NULL;
|
||||
}
|
||||
return new;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_new (void) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Create new object with type specified
|
||||
* @param type type of a new object
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t* ucl_object_typed_new (unsigned int type) UCL_WARN_UNUSED_RESULT;
|
||||
static inline ucl_object_t *
|
||||
ucl_object_typed_new (unsigned int type)
|
||||
{
|
||||
ucl_object_t *new;
|
||||
new = malloc (sizeof (ucl_object_t));
|
||||
if (new != NULL) {
|
||||
memset (new, 0, sizeof (ucl_object_t));
|
||||
new->ref = 1;
|
||||
new->type = (type <= UCL_NULL ? type : UCL_NULL);
|
||||
}
|
||||
return new;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_typed_new (ucl_type_t type) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Return the type of an object
|
||||
* @return the object type
|
||||
*/
|
||||
UCL_EXTERN ucl_type_t ucl_object_type (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Convert any string to an ucl object making the specified transformations
|
||||
@ -267,11 +259,7 @@ UCL_EXTERN ucl_object_t * ucl_object_fromstring_common (const char *str, size_t
|
||||
* @param str NULL terminated string, will be json escaped
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_fromstring (const char *str)
|
||||
{
|
||||
return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE);
|
||||
}
|
||||
UCL_EXTERN ucl_object_t *ucl_object_fromstring (const char *str) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Create a UCL object from the specified string
|
||||
@ -279,68 +267,29 @@ ucl_object_fromstring (const char *str)
|
||||
* @param len length of a string
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_fromlstring (const char *str, size_t len)
|
||||
{
|
||||
return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE);
|
||||
}
|
||||
UCL_EXTERN ucl_object_t *ucl_object_fromlstring (const char *str,
|
||||
size_t len) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Create an object from an integer number
|
||||
* @param iv number
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_fromint (int64_t iv)
|
||||
{
|
||||
ucl_object_t *obj;
|
||||
|
||||
obj = ucl_object_new ();
|
||||
if (obj != NULL) {
|
||||
obj->type = UCL_INT;
|
||||
obj->value.iv = iv;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_fromint (int64_t iv) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Create an object from a float number
|
||||
* @param dv number
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_fromdouble (double dv)
|
||||
{
|
||||
ucl_object_t *obj;
|
||||
|
||||
obj = ucl_object_new ();
|
||||
if (obj != NULL) {
|
||||
obj->type = UCL_FLOAT;
|
||||
obj->value.dv = dv;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_fromdouble (double dv) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Create an object from a boolean
|
||||
* @param bv bool value
|
||||
* @return new object
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_frombool (bool bv)
|
||||
{
|
||||
ucl_object_t *obj;
|
||||
|
||||
obj = ucl_object_new ();
|
||||
if (obj != NULL) {
|
||||
obj->type = UCL_BOOLEAN;
|
||||
obj->value.iv = bv;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_frombool (bool bv) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key'
|
||||
@ -349,10 +298,10 @@ ucl_object_frombool (bool bv)
|
||||
* @param key key to associate with this object (either const or preallocated)
|
||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||
* @param copy_key make an internal copy of key
|
||||
* @return new value of top object
|
||||
* @return true if key has been inserted
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
|
||||
const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;
|
||||
UCL_EXTERN bool ucl_object_insert_key (ucl_object_t *top, ucl_object_t *elt,
|
||||
const char *key, size_t keylen, bool copy_key);
|
||||
|
||||
/**
|
||||
* Replace a object 'elt' to the hash 'top' and associate it with key 'key', old object will be unrefed,
|
||||
@ -362,10 +311,10 @@ UCL_EXTERN ucl_object_t* ucl_object_insert_key (ucl_object_t *top, ucl_object_t
|
||||
* @param key key to associate with this object (either const or preallocated)
|
||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||
* @param copy_key make an internal copy of key
|
||||
* @return new value of top object
|
||||
* @return true if key has been inserted
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
|
||||
const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;
|
||||
UCL_EXTERN bool ucl_object_replace_key (ucl_object_t *top, ucl_object_t *elt,
|
||||
const char *key, size_t keylen, bool copy_key);
|
||||
|
||||
/**
|
||||
* Delete a object associated with key 'key', old object will be unrefered,
|
||||
@ -373,14 +322,38 @@ UCL_EXTERN ucl_object_t* ucl_object_replace_key (ucl_object_t *top, ucl_object_t
|
||||
* @param key key associated to the object to remove
|
||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||
*/
|
||||
UCL_EXTERN bool ucl_object_delete_keyl (ucl_object_t *top, const char *key, size_t keylen);
|
||||
UCL_EXTERN bool ucl_object_delete_keyl (ucl_object_t *top,
|
||||
const char *key, size_t keylen);
|
||||
|
||||
/**
|
||||
* Delete a object associated with key 'key', old object will be unrefered,
|
||||
* @param top object
|
||||
* @param key key associated to the object to remove
|
||||
*/
|
||||
UCL_EXTERN bool ucl_object_delete_key (ucl_object_t *top, const char *key);
|
||||
UCL_EXTERN bool ucl_object_delete_key (ucl_object_t *top,
|
||||
const char *key);
|
||||
|
||||
|
||||
/**
|
||||
* Delete key from `top` object returning the object deleted. This object is not
|
||||
* released
|
||||
* @param top object
|
||||
* @param key key to remove
|
||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||
* @return removed object or NULL if object has not been found
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_object_pop_keyl (ucl_object_t *top, const char *key,
|
||||
size_t keylen) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Delete key from `top` object returning the object deleted. This object is not
|
||||
* released
|
||||
* @param top object
|
||||
* @param key key to remove
|
||||
* @return removed object or NULL if object has not been found
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_object_pop_key (ucl_object_t *top, const char *key)
|
||||
UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Insert a object 'elt' to the hash 'top' and associate it with key 'key', if the specified key exist,
|
||||
@ -390,94 +363,28 @@ UCL_EXTERN bool ucl_object_delete_key (ucl_object_t *top, const char *key);
|
||||
* @param key key to associate with this object (either const or preallocated)
|
||||
* @param keylen length of the key (or 0 for NULL terminated keys)
|
||||
* @param copy_key make an internal copy of key
|
||||
* @return new value of top object
|
||||
* @return true if key has been inserted
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_object_insert_key_merged (ucl_object_t *top, ucl_object_t *elt,
|
||||
const char *key, size_t keylen, bool copy_key) UCL_WARN_UNUSED_RESULT;
|
||||
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);
|
||||
|
||||
/**
|
||||
* Append an element to the front of array object
|
||||
* @param top destination object (will be created automatically if top is NULL)
|
||||
* @param elt element to append (must NOT be NULL)
|
||||
* @return new value of top object
|
||||
* @return true if value has been inserted
|
||||
*/
|
||||
static inline ucl_object_t * ucl_array_append (ucl_object_t *top,
|
||||
ucl_object_t *elt) UCL_WARN_UNUSED_RESULT;
|
||||
static inline ucl_object_t *
|
||||
ucl_array_append (ucl_object_t *top, ucl_object_t *elt)
|
||||
{
|
||||
ucl_object_t *head;
|
||||
|
||||
if (elt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (top == NULL) {
|
||||
top = ucl_object_typed_new (UCL_ARRAY);
|
||||
top->value.av = elt;
|
||||
elt->next = NULL;
|
||||
elt->prev = elt;
|
||||
top->len = 1;
|
||||
}
|
||||
else {
|
||||
head = top->value.av;
|
||||
if (head == NULL) {
|
||||
top->value.av = elt;
|
||||
elt->prev = elt;
|
||||
}
|
||||
else {
|
||||
elt->prev = head->prev;
|
||||
head->prev->next = elt;
|
||||
head->prev = elt;
|
||||
}
|
||||
elt->next = NULL;
|
||||
top->len ++;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
UCL_EXTERN bool ucl_array_append (ucl_object_t *top,
|
||||
ucl_object_t *elt);
|
||||
|
||||
/**
|
||||
* Append an element to the start of array object
|
||||
* @param top destination object (will be created automatically if top is NULL)
|
||||
* @param elt element to append (must NOT be NULL)
|
||||
* @return new value of top object
|
||||
* @return true if value has been inserted
|
||||
*/
|
||||
static inline ucl_object_t * ucl_array_prepend (ucl_object_t *top,
|
||||
ucl_object_t *elt) UCL_WARN_UNUSED_RESULT;
|
||||
static inline ucl_object_t *
|
||||
ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
|
||||
{
|
||||
ucl_object_t *head;
|
||||
|
||||
if (elt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (top == NULL) {
|
||||
top = ucl_object_typed_new (UCL_ARRAY);
|
||||
top->value.av = elt;
|
||||
elt->next = NULL;
|
||||
elt->prev = elt;
|
||||
top->len = 1;
|
||||
}
|
||||
else {
|
||||
head = top->value.av;
|
||||
if (head == NULL) {
|
||||
top->value.av = elt;
|
||||
elt->prev = elt;
|
||||
}
|
||||
else {
|
||||
elt->prev = head->prev;
|
||||
head->prev = elt;
|
||||
}
|
||||
elt->next = head;
|
||||
top->value.av = elt;
|
||||
top->len ++;
|
||||
}
|
||||
|
||||
return top;
|
||||
}
|
||||
UCL_EXTERN bool ucl_array_prepend (ucl_object_t *top,
|
||||
ucl_object_t *elt);
|
||||
|
||||
/**
|
||||
* Removes an element `elt` from the array `top`. Caller must unref the returned object when it is not
|
||||
@ -486,66 +393,22 @@ ucl_array_prepend (ucl_object_t *top, ucl_object_t *elt)
|
||||
* @param elt element to remove
|
||||
* @return removed element or NULL if `top` is NULL or not an array
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_array_delete (ucl_object_t *top, ucl_object_t *elt)
|
||||
{
|
||||
ucl_object_t *head;
|
||||
|
||||
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
head = top->value.av;
|
||||
|
||||
if (elt->prev == elt) {
|
||||
top->value.av = NULL;
|
||||
}
|
||||
else if (elt == head) {
|
||||
elt->next->prev = elt->prev;
|
||||
top->value.av = elt->next;
|
||||
}
|
||||
else {
|
||||
elt->prev->next = elt->next;
|
||||
if (elt->next) {
|
||||
elt->next->prev = elt->prev;
|
||||
}
|
||||
else {
|
||||
head->prev = elt->prev;
|
||||
}
|
||||
}
|
||||
elt->next = NULL;
|
||||
elt->prev = elt;
|
||||
top->len --;
|
||||
|
||||
return elt;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_array_delete (ucl_object_t *top,
|
||||
ucl_object_t *elt);
|
||||
|
||||
/**
|
||||
* Returns the first element of the array `top`
|
||||
* @param top array ucl object
|
||||
* @return element or NULL if `top` is NULL or not an array
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_array_head (ucl_object_t *top)
|
||||
{
|
||||
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return top->value.av;
|
||||
}
|
||||
UCL_EXTERN const ucl_object_t* ucl_array_head (const ucl_object_t *top);
|
||||
|
||||
/**
|
||||
* Returns the last element of the array `top`
|
||||
* @param top array ucl object
|
||||
* @return element or NULL if `top` is NULL or not an array
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_array_tail (ucl_object_t *top)
|
||||
{
|
||||
if (top == NULL || top->type != UCL_ARRAY || top->value.av == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
return top->value.av->prev;
|
||||
}
|
||||
UCL_EXTERN const ucl_object_t* ucl_array_tail (const ucl_object_t *top);
|
||||
|
||||
/**
|
||||
* Removes the last element from the array `top`. Caller must unref the returned object when it is not
|
||||
@ -553,11 +416,16 @@ ucl_array_tail (ucl_object_t *top)
|
||||
* @param top array ucl object
|
||||
* @return removed element or NULL if `top` is NULL or not an array
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_array_pop_last (ucl_object_t *top)
|
||||
{
|
||||
return ucl_array_delete (top, ucl_array_tail (top));
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_array_pop_last (ucl_object_t *top);
|
||||
|
||||
/**
|
||||
* Return object identified by an index of the array `top`
|
||||
* @param obj object to get a key from (must be of type UCL_ARRAY)
|
||||
* @param index index to return
|
||||
* @return object at the specified index or NULL if index is not found
|
||||
*/
|
||||
UCL_EXTERN const ucl_object_t* ucl_array_find_index (const ucl_object_t *top,
|
||||
unsigned int index);
|
||||
|
||||
/**
|
||||
* Removes the first element from the array `top`. Caller must unref the returned object when it is not
|
||||
@ -565,38 +433,16 @@ ucl_array_pop_last (ucl_object_t *top)
|
||||
* @param top array ucl object
|
||||
* @return removed element or NULL if `top` is NULL or not an array
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_array_pop_first (ucl_object_t *top)
|
||||
{
|
||||
return ucl_array_delete (top, ucl_array_head (top));
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_array_pop_first (ucl_object_t *top);
|
||||
|
||||
/**
|
||||
* Append a element to another element forming an implicit array
|
||||
* @param head head to append (may be NULL)
|
||||
* @param elt new element
|
||||
* @return new head if applicable
|
||||
* @return true if element has been inserted
|
||||
*/
|
||||
static inline ucl_object_t * ucl_elt_append (ucl_object_t *head,
|
||||
ucl_object_t *elt) UCL_WARN_UNUSED_RESULT;
|
||||
static inline ucl_object_t *
|
||||
ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
|
||||
{
|
||||
|
||||
if (head == NULL) {
|
||||
elt->next = NULL;
|
||||
elt->prev = elt;
|
||||
head = elt;
|
||||
}
|
||||
else {
|
||||
elt->prev = head->prev;
|
||||
head->prev->next = elt;
|
||||
head->prev = elt;
|
||||
elt->next = NULL;
|
||||
}
|
||||
|
||||
return head;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t * ucl_elt_append (ucl_object_t *head,
|
||||
ucl_object_t *elt);
|
||||
|
||||
/**
|
||||
* Converts an object to double value
|
||||
@ -604,40 +450,14 @@ ucl_elt_append (ucl_object_t *head, ucl_object_t *elt)
|
||||
* @param target target double variable
|
||||
* @return true if conversion was successful
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_todouble_safe (ucl_object_t *obj, double *target)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
switch (obj->type) {
|
||||
case UCL_INT:
|
||||
*target = obj->value.iv; /* Probaly could cause overflow */
|
||||
break;
|
||||
case UCL_FLOAT:
|
||||
case UCL_TIME:
|
||||
*target = obj->value.dv;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_todouble_safe (const ucl_object_t *obj, double *target);
|
||||
|
||||
/**
|
||||
* Unsafe version of \ref ucl_obj_todouble_safe
|
||||
* @param obj CL object
|
||||
* @return double value
|
||||
*/
|
||||
static inline double
|
||||
ucl_object_todouble (ucl_object_t *obj)
|
||||
{
|
||||
double result = 0.;
|
||||
|
||||
ucl_object_todouble_safe (obj, &result);
|
||||
return result;
|
||||
}
|
||||
UCL_EXTERN double ucl_object_todouble (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Converts an object to integer value
|
||||
@ -645,40 +465,14 @@ ucl_object_todouble (ucl_object_t *obj)
|
||||
* @param target target integer variable
|
||||
* @return true if conversion was successful
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_toint_safe (ucl_object_t *obj, int64_t *target)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
switch (obj->type) {
|
||||
case UCL_INT:
|
||||
*target = obj->value.iv;
|
||||
break;
|
||||
case UCL_FLOAT:
|
||||
case UCL_TIME:
|
||||
*target = obj->value.dv; /* Loosing of decimal points */
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_toint_safe (const ucl_object_t *obj, int64_t *target);
|
||||
|
||||
/**
|
||||
* Unsafe version of \ref ucl_obj_toint_safe
|
||||
* @param obj CL object
|
||||
* @return int value
|
||||
*/
|
||||
static inline int64_t
|
||||
ucl_object_toint (ucl_object_t *obj)
|
||||
{
|
||||
int64_t result = 0;
|
||||
|
||||
ucl_object_toint_safe (obj, &result);
|
||||
return result;
|
||||
}
|
||||
UCL_EXTERN int64_t ucl_object_toint (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Converts an object to boolean value
|
||||
@ -686,36 +480,14 @@ ucl_object_toint (ucl_object_t *obj)
|
||||
* @param target target boolean variable
|
||||
* @return true if conversion was successful
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_toboolean_safe (ucl_object_t *obj, bool *target)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
switch (obj->type) {
|
||||
case UCL_BOOLEAN:
|
||||
*target = (obj->value.iv == true);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_toboolean_safe (const ucl_object_t *obj, bool *target);
|
||||
|
||||
/**
|
||||
* Unsafe version of \ref ucl_obj_toboolean_safe
|
||||
* @param obj CL object
|
||||
* @return boolean value
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_toboolean (ucl_object_t *obj)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
ucl_object_toboolean_safe (obj, &result);
|
||||
return result;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_toboolean (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Converts an object to string value
|
||||
@ -723,48 +495,21 @@ ucl_object_toboolean (ucl_object_t *obj)
|
||||
* @param target target string variable, no need to free value
|
||||
* @return true if conversion was successful
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_tostring_safe (ucl_object_t *obj, const char **target)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (obj->type) {
|
||||
case UCL_STRING:
|
||||
*target = ucl_copy_value_trash (obj);
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_tostring_safe (const ucl_object_t *obj, const char **target);
|
||||
|
||||
/**
|
||||
* Unsafe version of \ref ucl_obj_tostring_safe
|
||||
* @param obj CL object
|
||||
* @return string value
|
||||
*/
|
||||
static inline const char *
|
||||
ucl_object_tostring (ucl_object_t *obj)
|
||||
{
|
||||
const char *result = NULL;
|
||||
|
||||
ucl_object_tostring_safe (obj, &result);
|
||||
return result;
|
||||
}
|
||||
UCL_EXTERN const char* ucl_object_tostring (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Convert any object to a string in JSON notation if needed
|
||||
* @param obj CL object
|
||||
* @return string value
|
||||
*/
|
||||
static inline const char *
|
||||
ucl_object_tostring_forced (ucl_object_t *obj)
|
||||
{
|
||||
return ucl_copy_value_trash (obj);
|
||||
}
|
||||
UCL_EXTERN const char* ucl_object_tostring_forced (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Return string as char * and len, string may be not zero terminated, more efficient that \ref ucl_obj_tostring as it
|
||||
@ -774,37 +519,15 @@ ucl_object_tostring_forced (ucl_object_t *obj)
|
||||
* @param tlen target length
|
||||
* @return true if conversion was successful
|
||||
*/
|
||||
static inline bool
|
||||
ucl_object_tolstring_safe (ucl_object_t *obj, const char **target, size_t *tlen)
|
||||
{
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
switch (obj->type) {
|
||||
case UCL_STRING:
|
||||
*target = obj->value.sv;
|
||||
*tlen = obj->len;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
UCL_EXTERN bool ucl_object_tolstring_safe (const ucl_object_t *obj,
|
||||
const char **target, size_t *tlen);
|
||||
|
||||
/**
|
||||
* Unsafe version of \ref ucl_obj_tolstring_safe
|
||||
* @param obj CL object
|
||||
* @return string value
|
||||
*/
|
||||
static inline const char *
|
||||
ucl_object_tolstring (ucl_object_t *obj, size_t *tlen)
|
||||
{
|
||||
const char *result = NULL;
|
||||
|
||||
ucl_object_tolstring_safe (obj, &result, tlen);
|
||||
return result;
|
||||
}
|
||||
UCL_EXTERN const char* ucl_object_tolstring (const ucl_object_t *obj, size_t *tlen);
|
||||
|
||||
/**
|
||||
* Return object identified by a key in the specified object
|
||||
@ -812,7 +535,8 @@ ucl_object_tolstring (ucl_object_t *obj, size_t *tlen)
|
||||
* @param key key to search
|
||||
* @return object matched the specified key or NULL if key is not found
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t * ucl_object_find_key (ucl_object_t *obj, const char *key);
|
||||
UCL_EXTERN const ucl_object_t* ucl_object_find_key (const ucl_object_t *obj,
|
||||
const char *key);
|
||||
|
||||
/**
|
||||
* Return object identified by a fixed size key in the specified object
|
||||
@ -821,18 +545,24 @@ UCL_EXTERN ucl_object_t * ucl_object_find_key (ucl_object_t *obj, const char *ke
|
||||
* @param klen length of a key
|
||||
* @return object matched the specified key or NULL if key is not found
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t *ucl_object_find_keyl (ucl_object_t *obj, const char *key, size_t klen);
|
||||
UCL_EXTERN const ucl_object_t* ucl_object_find_keyl (const ucl_object_t *obj,
|
||||
const char *key, size_t klen);
|
||||
|
||||
/**
|
||||
* Return object identified by dot notation string
|
||||
* @param obj object to search in
|
||||
* @param path dot.notation.path to the path to lookup. May use numeric .index on arrays
|
||||
* @return object matched the specified path or NULL if path is not found
|
||||
*/
|
||||
UCL_EXTERN const ucl_object_t *ucl_lookup_path (const ucl_object_t *obj,
|
||||
const char *path);
|
||||
|
||||
/**
|
||||
* Returns a key of an object as a NULL terminated string
|
||||
* @param obj CL object
|
||||
* @return key or NULL if there is no key
|
||||
*/
|
||||
static inline const char *
|
||||
ucl_object_key (ucl_object_t *obj)
|
||||
{
|
||||
return ucl_copy_key_trash (obj);
|
||||
}
|
||||
UCL_EXTERN const char* ucl_object_key (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Returns a key of an object as a fixed size string (may be more efficient)
|
||||
@ -840,39 +570,47 @@ ucl_object_key (ucl_object_t *obj)
|
||||
* @param len target key length
|
||||
* @return key pointer
|
||||
*/
|
||||
static inline const char *
|
||||
ucl_object_keyl (ucl_object_t *obj, size_t *len)
|
||||
{
|
||||
*len = obj->keylen;
|
||||
return obj->key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free ucl object
|
||||
* @param obj ucl object to free
|
||||
*/
|
||||
UCL_EXTERN void ucl_object_free (ucl_object_t *obj);
|
||||
UCL_EXTERN const char* ucl_object_keyl (const ucl_object_t *obj, size_t *len);
|
||||
|
||||
/**
|
||||
* Increase reference count for an object
|
||||
* @param obj object to ref
|
||||
*/
|
||||
static inline ucl_object_t *
|
||||
ucl_object_ref (ucl_object_t *obj) {
|
||||
obj->ref ++;
|
||||
return obj;
|
||||
}
|
||||
UCL_EXTERN ucl_object_t* ucl_object_ref (const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Free ucl object
|
||||
* @param obj ucl object to free
|
||||
*/
|
||||
UCL_DEPRECATED(UCL_EXTERN void ucl_object_free (ucl_object_t *obj));
|
||||
|
||||
/**
|
||||
* Decrease reference count for an object
|
||||
* @param obj object to unref
|
||||
*/
|
||||
static inline void
|
||||
ucl_object_unref (ucl_object_t *obj) {
|
||||
if (obj != NULL && --obj->ref <= 0) {
|
||||
ucl_object_free (obj);
|
||||
}
|
||||
}
|
||||
UCL_EXTERN void ucl_object_unref (ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Compare objects `o1` and `o2`
|
||||
* @param o1 the first object
|
||||
* @param o2 the second object
|
||||
* @return values >0, 0 and <0 if `o1` is more than, equal and less than `o2`.
|
||||
* The order of comparison:
|
||||
* 1) Type of objects
|
||||
* 2) Size of objects
|
||||
* 3) Content of objects
|
||||
*/
|
||||
UCL_EXTERN int ucl_object_compare (const ucl_object_t *o1,
|
||||
const ucl_object_t *o2);
|
||||
|
||||
/**
|
||||
* Sort UCL array using `cmp` compare function
|
||||
* @param ar
|
||||
* @param cmp
|
||||
*/
|
||||
UCL_EXTERN void ucl_object_array_sort (ucl_object_t *ar,
|
||||
int (*cmp)(const ucl_object_t *o1, const ucl_object_t *o2));
|
||||
|
||||
/**
|
||||
* Opaque iterator object
|
||||
*/
|
||||
@ -886,7 +624,8 @@ typedef void* ucl_object_iter_t;
|
||||
* while ((cur = ucl_iterate_object (obj, &it)) != NULL) ...
|
||||
* @return the next object or NULL
|
||||
*/
|
||||
UCL_EXTERN ucl_object_t* ucl_iterate_object (ucl_object_t *obj, ucl_object_iter_t *iter, bool expand_values);
|
||||
UCL_EXTERN const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj,
|
||||
ucl_object_iter_t *iter, bool expand_values);
|
||||
/** @} */
|
||||
|
||||
|
||||
@ -927,6 +666,19 @@ UCL_EXTERN struct ucl_parser* ucl_parser_new (int flags);
|
||||
UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
|
||||
ucl_macro_handler handler, void* ud);
|
||||
|
||||
/**
|
||||
* Handler to detect unregistered variables
|
||||
* @param data variable data
|
||||
* @param len length of variable
|
||||
* @param replace (out) replace value for variable
|
||||
* @param replace_len (out) replace length for variable
|
||||
* @param need_free (out) UCL will free `dest` after usage
|
||||
* @param ud opaque userdata
|
||||
* @return true if variable
|
||||
*/
|
||||
typedef bool (*ucl_variable_handler) (const unsigned char *data, size_t len,
|
||||
unsigned char **replace, size_t *replace_len, bool *need_free, void* ud);
|
||||
|
||||
/**
|
||||
* Register new parser variable
|
||||
* @param parser parser object
|
||||
@ -936,6 +688,15 @@ UCL_EXTERN void ucl_parser_register_macro (struct ucl_parser *parser, const char
|
||||
UCL_EXTERN void ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
||||
const char *value);
|
||||
|
||||
/**
|
||||
* Set handler for unknown variables
|
||||
* @param parser parser structure
|
||||
* @param handler desired handler
|
||||
* @param ud opaque data for the handler
|
||||
*/
|
||||
UCL_EXTERN void ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
||||
ucl_variable_handler handler, void *ud);
|
||||
|
||||
/**
|
||||
* Load new chunk to a parser
|
||||
* @param parser parser structure
|
||||
@ -944,7 +705,18 @@ UCL_EXTERN void ucl_parser_register_variable (struct ucl_parser *parser, const c
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @return true if chunk has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data, size_t len);
|
||||
UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser,
|
||||
const unsigned char *data, size_t len);
|
||||
|
||||
/**
|
||||
* Load ucl object from a string
|
||||
* @param parser parser structure
|
||||
* @param data the pointer to the string
|
||||
* @param len the length of the string, if `len` is 0 then `data` must be zero-terminated string
|
||||
* @return true if string has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_string (struct ucl_parser *parser,
|
||||
const char *data,size_t len);
|
||||
|
||||
/**
|
||||
* Load and add data from a file
|
||||
@ -953,10 +725,21 @@ UCL_EXTERN bool ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @return true if chunk has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser, const char *filename);
|
||||
UCL_EXTERN bool ucl_parser_add_file (struct ucl_parser *parser,
|
||||
const char *filename);
|
||||
|
||||
/**
|
||||
* Get a top object for a parser
|
||||
* Load and add data from a file descriptor
|
||||
* @param parser parser structure
|
||||
* @param filename the name of file
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @return true if chunk has been added and false in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_parser_add_fd (struct ucl_parser *parser,
|
||||
int fd);
|
||||
|
||||
/**
|
||||
* Get a top object for a parser (refcount is increased)
|
||||
* @param parser parser structure
|
||||
* @param err if *err is NULL it is set to parser error
|
||||
* @return top parser object or NULL
|
||||
@ -1026,7 +809,8 @@ struct ucl_emitter_functions {
|
||||
* #UCL_EMIT_CONFIG then emit config like object
|
||||
* @return dump of an object (must be freed after using) or NULL in case of error
|
||||
*/
|
||||
UCL_EXTERN unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type);
|
||||
UCL_EXTERN unsigned char *ucl_object_emit (const ucl_object_t *obj,
|
||||
enum ucl_emitter emit_type);
|
||||
|
||||
/**
|
||||
* Emit object to a string
|
||||
@ -1035,10 +819,53 @@ UCL_EXTERN unsigned char *ucl_object_emit (ucl_object_t *obj, enum ucl_emitter e
|
||||
* #UCL_EMIT_CONFIG then emit config like object
|
||||
* @return dump of an object (must be freed after using) or NULL in case of error
|
||||
*/
|
||||
UCL_EXTERN bool ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
UCL_EXTERN bool ucl_object_emit_full (const ucl_object_t *obj,
|
||||
enum ucl_emitter emit_type,
|
||||
struct ucl_emitter_functions *emitter);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @defgroup schema Schema functions
|
||||
* These functions are used to validate UCL objects using json schema format
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used to define UCL schema error
|
||||
*/
|
||||
enum ucl_schema_error_code {
|
||||
UCL_SCHEMA_OK = 0, /**< no error */
|
||||
UCL_SCHEMA_TYPE_MISMATCH, /**< type of object is incorrect */
|
||||
UCL_SCHEMA_INVALID_SCHEMA, /**< schema is invalid */
|
||||
UCL_SCHEMA_MISSING_PROPERTY,/**< one or more missing properties */
|
||||
UCL_SCHEMA_CONSTRAINT, /**< constraint found */
|
||||
UCL_SCHEMA_MISSING_DEPENDENCY, /**< missing dependency */
|
||||
UCL_SCHEMA_UNKNOWN /**< generic error */
|
||||
};
|
||||
|
||||
/**
|
||||
* Generic ucl schema error
|
||||
*/
|
||||
struct ucl_schema_error {
|
||||
enum ucl_schema_error_code code; /**< error code */
|
||||
char msg[128]; /**< error message */
|
||||
const ucl_object_t *obj; /**< object where error occured */
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate object `obj` using schema object `schema`.
|
||||
* @param schema schema object
|
||||
* @param obj object to validate
|
||||
* @param err error pointer, if this parameter is not NULL and error has been
|
||||
* occured, then `err` is filled with the exact error definition.
|
||||
* @return true if `obj` is valid using `schema`
|
||||
*/
|
||||
UCL_EXTERN bool ucl_object_validate (const ucl_object_t *schema,
|
||||
const ucl_object_t *obj, struct ucl_schema_error *err);
|
||||
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
11
contrib/libucl/libucl.pc.in
Normal file
11
contrib/libucl/libucl.pc.in
Normal file
@ -0,0 +1,11 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: LibUCL
|
||||
Description: Universal configuration library
|
||||
Version: @UCL_VERSION@
|
||||
Libs: -L${libdir} -lucl
|
||||
Libs.private: @LIBS_EXTRA@
|
||||
Cflags: -I${includedir}/
|
25
contrib/libucl/src/Makefile.am
Normal file
25
contrib/libucl/src/Makefile.am
Normal file
@ -0,0 +1,25 @@
|
||||
libucl_common_cflags= -I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/uthash \
|
||||
-Wall -W -Wno-unused-parameter -Wno-pointer-sign
|
||||
lib_LTLIBRARIES= libucl.la
|
||||
libucl_la_SOURCES= ucl_emitter.c \
|
||||
ucl_hash.c \
|
||||
ucl_parser.c \
|
||||
ucl_schema.c \
|
||||
ucl_util.c \
|
||||
xxhash.c
|
||||
libucl_la_CFLAGS= $(libucl_common_cflags) \
|
||||
@CURL_CFLAGS@
|
||||
libucl_la_LDFLAGS = -version-info @SO_VERSION@
|
||||
libucl_la_LIBADD= @LIBFETCH_LIBS@ \
|
||||
@LIBCRYPTO_LIB@ \
|
||||
@LIBREGEX_LIB@ \
|
||||
@CURL_LIBS@
|
||||
|
||||
include_HEADERS= $(top_srcdir)/include/ucl.h
|
||||
noinst_HEADERS= ucl_internal.h \
|
||||
xxhash.h \
|
||||
ucl_hash.h \
|
||||
ucl_chartable.h \
|
||||
tree.h
|
212
contrib/libucl/src/tree.h
Normal file
212
contrib/libucl/src/tree.h
Normal file
@ -0,0 +1,212 @@
|
||||
/* tree.h -- AVL trees (in the spirit of BSD's 'queue.h') -*- C -*- */
|
||||
|
||||
/* Copyright (c) 2005 Ian Piumarta
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the 'Software'), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, and/or sell copies of the
|
||||
* Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* provided that the above copyright notice(s) and this permission notice appear
|
||||
* in all copies of the Software and that both the above copyright notice(s) and
|
||||
* this permission notice appear in supporting documentation.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED 'AS IS'. USE ENTIRELY AT YOUR OWN RISK.
|
||||
*/
|
||||
|
||||
/* This file defines an AVL balanced binary tree [Georgii M. Adelson-Velskii and
|
||||
* Evgenii M. Landis, 'An algorithm for the organization of information',
|
||||
* Doklady Akademii Nauk SSSR, 146:263-266, 1962 (Russian). Also in Myron
|
||||
* J. Ricci (trans.), Soviet Math, 3:1259-1263, 1962 (English)].
|
||||
*
|
||||
* An AVL tree is headed by pointers to the root node and to a function defining
|
||||
* the ordering relation between nodes. Each node contains an arbitrary payload
|
||||
* plus three fields per tree entry: the depth of the subtree for which it forms
|
||||
* the root and two pointers to child nodes (singly-linked for minimum space, at
|
||||
* the expense of direct access to the parent node given a pointer to one of the
|
||||
* children). The tree is rebalanced after every insertion or removal. The
|
||||
* tree may be traversed in two directions: forward (in-order left-to-right) and
|
||||
* reverse (in-order, right-to-left).
|
||||
*
|
||||
* Because of the recursive nature of many of the operations on trees it is
|
||||
* necessary to define a number of helper functions for each type of tree node.
|
||||
* The macro TREE_DEFINE(node_tag, entry_name) defines these functions with
|
||||
* unique names according to the node_tag. This macro should be invoked,
|
||||
* thereby defining the necessary functions, once per node tag in the program.
|
||||
*
|
||||
* For details on the use of these macros, see the tree(3) manual page.
|
||||
*/
|
||||
|
||||
#ifndef __tree_h
|
||||
#define __tree_h
|
||||
|
||||
|
||||
#define TREE_DELTA_MAX 1
|
||||
|
||||
#define TREE_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *avl_left; \
|
||||
struct type *avl_right; \
|
||||
int avl_height; \
|
||||
}
|
||||
|
||||
#define TREE_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *th_root; \
|
||||
int (*th_cmp)(struct type *lhs, struct type *rhs); \
|
||||
}
|
||||
|
||||
#define TREE_INITIALIZER(cmp) { 0, cmp }
|
||||
|
||||
#define TREE_DELTA(self, field) \
|
||||
(( (((self)->field.avl_left) ? (self)->field.avl_left->field.avl_height : 0)) \
|
||||
- (((self)->field.avl_right) ? (self)->field.avl_right->field.avl_height : 0))
|
||||
|
||||
/* Recursion prevents the following from being defined as macros. */
|
||||
|
||||
#define TREE_DEFINE(node, field) \
|
||||
\
|
||||
struct node *TREE_BALANCE_##node##_##field(struct node *); \
|
||||
\
|
||||
struct node *TREE_ROTL_##node##_##field(struct node *self) \
|
||||
{ \
|
||||
struct node *r= self->field.avl_right; \
|
||||
self->field.avl_right= r->field.avl_left; \
|
||||
r->field.avl_left= TREE_BALANCE_##node##_##field(self); \
|
||||
return TREE_BALANCE_##node##_##field(r); \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_ROTR_##node##_##field(struct node *self) \
|
||||
{ \
|
||||
struct node *l= self->field.avl_left; \
|
||||
self->field.avl_left= l->field.avl_right; \
|
||||
l->field.avl_right= TREE_BALANCE_##node##_##field(self); \
|
||||
return TREE_BALANCE_##node##_##field(l); \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_BALANCE_##node##_##field(struct node *self) \
|
||||
{ \
|
||||
int delta= TREE_DELTA(self, field); \
|
||||
\
|
||||
if (delta < -TREE_DELTA_MAX) \
|
||||
{ \
|
||||
if (TREE_DELTA(self->field.avl_right, field) > 0) \
|
||||
self->field.avl_right= TREE_ROTR_##node##_##field(self->field.avl_right); \
|
||||
return TREE_ROTL_##node##_##field(self); \
|
||||
} \
|
||||
else if (delta > TREE_DELTA_MAX) \
|
||||
{ \
|
||||
if (TREE_DELTA(self->field.avl_left, field) < 0) \
|
||||
self->field.avl_left= TREE_ROTL_##node##_##field(self->field.avl_left); \
|
||||
return TREE_ROTR_##node##_##field(self); \
|
||||
} \
|
||||
self->field.avl_height= 0; \
|
||||
if (self->field.avl_left && (self->field.avl_left->field.avl_height > self->field.avl_height)) \
|
||||
self->field.avl_height= self->field.avl_left->field.avl_height; \
|
||||
if (self->field.avl_right && (self->field.avl_right->field.avl_height > self->field.avl_height)) \
|
||||
self->field.avl_height= self->field.avl_right->field.avl_height; \
|
||||
self->field.avl_height += 1; \
|
||||
return self; \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_INSERT_##node##_##field \
|
||||
(struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
|
||||
{ \
|
||||
if (!self) \
|
||||
return elm; \
|
||||
if (compare(elm, self) < 0) \
|
||||
self->field.avl_left= TREE_INSERT_##node##_##field(self->field.avl_left, elm, compare); \
|
||||
else \
|
||||
self->field.avl_right= TREE_INSERT_##node##_##field(self->field.avl_right, elm, compare); \
|
||||
return TREE_BALANCE_##node##_##field(self); \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_FIND_##node##_##field \
|
||||
(struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
|
||||
{ \
|
||||
if (!self) \
|
||||
return 0; \
|
||||
if (compare(elm, self) == 0) \
|
||||
return self; \
|
||||
if (compare(elm, self) < 0) \
|
||||
return TREE_FIND_##node##_##field(self->field.avl_left, elm, compare); \
|
||||
else \
|
||||
return TREE_FIND_##node##_##field(self->field.avl_right, elm, compare); \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_MOVE_RIGHT(struct node *self, struct node *rhs) \
|
||||
{ \
|
||||
if (!self) \
|
||||
return rhs; \
|
||||
self->field.avl_right= TREE_MOVE_RIGHT(self->field.avl_right, rhs); \
|
||||
return TREE_BALANCE_##node##_##field(self); \
|
||||
} \
|
||||
\
|
||||
struct node *TREE_REMOVE_##node##_##field \
|
||||
(struct node *self, struct node *elm, int (*compare)(struct node *lhs, struct node *rhs)) \
|
||||
{ \
|
||||
if (!self) return 0; \
|
||||
\
|
||||
if (compare(elm, self) == 0) \
|
||||
{ \
|
||||
struct node *tmp= TREE_MOVE_RIGHT(self->field.avl_left, self->field.avl_right); \
|
||||
self->field.avl_left= 0; \
|
||||
self->field.avl_right= 0; \
|
||||
return tmp; \
|
||||
} \
|
||||
if (compare(elm, self) < 0) \
|
||||
self->field.avl_left= TREE_REMOVE_##node##_##field(self->field.avl_left, elm, compare); \
|
||||
else \
|
||||
self->field.avl_right= TREE_REMOVE_##node##_##field(self->field.avl_right, elm, compare); \
|
||||
return TREE_BALANCE_##node##_##field(self); \
|
||||
} \
|
||||
\
|
||||
void TREE_FORWARD_APPLY_ALL_##node##_##field \
|
||||
(struct node *self, void (*function)(struct node *node, void *data), void *data) \
|
||||
{ \
|
||||
if (self) \
|
||||
{ \
|
||||
TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
|
||||
function(self, data); \
|
||||
TREE_FORWARD_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
void TREE_REVERSE_APPLY_ALL_##node##_##field \
|
||||
(struct node *self, void (*function)(struct node *node, void *data), void *data) \
|
||||
{ \
|
||||
if (self) \
|
||||
{ \
|
||||
TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_right, function, data); \
|
||||
function(self, data); \
|
||||
TREE_REVERSE_APPLY_ALL_##node##_##field(self->field.avl_left, function, data); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TREE_INSERT(head, node, field, elm) \
|
||||
((head)->th_root= TREE_INSERT_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
|
||||
|
||||
#define TREE_FIND(head, node, field, elm) \
|
||||
(TREE_FIND_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
|
||||
|
||||
#define TREE_REMOVE(head, node, field, elm) \
|
||||
((head)->th_root= TREE_REMOVE_##node##_##field((head)->th_root, (elm), (head)->th_cmp))
|
||||
|
||||
#define TREE_DEPTH(head, field) \
|
||||
((head)->th_root->field.avl_height)
|
||||
|
||||
#define TREE_FORWARD_APPLY(head, node, field, function, data) \
|
||||
TREE_FORWARD_APPLY_ALL_##node##_##field((head)->th_root, function, data)
|
||||
|
||||
#define TREE_REVERSE_APPLY(head, node, field, function, data) \
|
||||
TREE_REVERSE_APPLY_ALL_##node##_##field((head)->th_root, function, data)
|
||||
|
||||
#define TREE_INIT(head, cmp) do { \
|
||||
(head)->th_root= 0; \
|
||||
(head)->th_cmp= (cmp); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#endif /* __tree_h */
|
@ -21,11 +21,19 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "ucl.h"
|
||||
#include "ucl_internal.h"
|
||||
#include "ucl_chartable.h"
|
||||
#ifdef HAVE_FLOAT_H
|
||||
#include <float.h>
|
||||
#endif
|
||||
#ifdef HAVE_MATH_H
|
||||
#include <math.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file rcl_emitter.c
|
||||
@ -33,29 +41,29 @@
|
||||
*/
|
||||
|
||||
|
||||
static void ucl_obj_write_json (ucl_object_t *obj,
|
||||
static void ucl_obj_write_json (const ucl_object_t *obj,
|
||||
struct ucl_emitter_functions *func,
|
||||
unsigned int tabs,
|
||||
bool start_tabs,
|
||||
bool compact);
|
||||
static void ucl_elt_write_json (ucl_object_t *obj,
|
||||
static void ucl_elt_write_json (const ucl_object_t *obj,
|
||||
struct ucl_emitter_functions *func,
|
||||
unsigned int tabs,
|
||||
bool start_tabs,
|
||||
bool compact);
|
||||
static void ucl_elt_write_config (ucl_object_t *obj,
|
||||
static void ucl_elt_write_config (const ucl_object_t *obj,
|
||||
struct ucl_emitter_functions *func,
|
||||
unsigned int tabs,
|
||||
bool start_tabs,
|
||||
bool is_top,
|
||||
bool expand_array);
|
||||
static void ucl_elt_write_yaml (ucl_object_t *obj,
|
||||
static void ucl_elt_write_yaml (const ucl_object_t *obj,
|
||||
struct ucl_emitter_functions *func,
|
||||
unsigned int tabs,
|
||||
bool start_tabs,
|
||||
bool compact,
|
||||
bool expand_array);
|
||||
static void ucl_elt_array_write_yaml (ucl_object_t *obj,
|
||||
static void ucl_elt_array_write_yaml (const ucl_object_t *obj,
|
||||
struct ucl_emitter_functions *func,
|
||||
unsigned int tabs,
|
||||
bool start_tabs,
|
||||
@ -136,10 +144,10 @@ ucl_elt_string_write_json (const char *str, size_t size,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool compact)
|
||||
{
|
||||
ucl_object_t *cur;
|
||||
const ucl_object_t *cur;
|
||||
ucl_hash_iter_t it = NULL;
|
||||
|
||||
if (start_tabs) {
|
||||
@ -188,10 +196,10 @@ ucl_elt_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_array_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool compact)
|
||||
{
|
||||
ucl_object_t *cur = obj;
|
||||
const ucl_object_t *cur = obj;
|
||||
|
||||
if (start_tabs) {
|
||||
ucl_add_tabs (func, tabs, compact);
|
||||
@ -227,7 +235,7 @@ ucl_elt_array_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool compact)
|
||||
{
|
||||
bool flag;
|
||||
@ -287,10 +295,10 @@ ucl_elt_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_obj_write_json (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool compact)
|
||||
{
|
||||
ucl_object_t *cur;
|
||||
const ucl_object_t *cur;
|
||||
bool is_array = (obj->next != NULL);
|
||||
|
||||
if (is_array) {
|
||||
@ -331,7 +339,8 @@ ucl_obj_write_json (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @return json output (should be freed after using)
|
||||
*/
|
||||
static void
|
||||
ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functions *func)
|
||||
ucl_object_emit_json (const ucl_object_t *obj, bool compact,
|
||||
struct ucl_emitter_functions *func)
|
||||
{
|
||||
ucl_obj_write_json (obj, func, 0, false, compact);
|
||||
}
|
||||
@ -342,10 +351,10 @@ ucl_object_emit_json (ucl_object_t *obj, bool compact, struct ucl_emitter_functi
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_obj_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top)
|
||||
{
|
||||
ucl_object_t *cur, *cur_obj;
|
||||
const ucl_object_t *cur, *cur_obj;
|
||||
ucl_hash_iter_t it = NULL;
|
||||
|
||||
if (start_tabs) {
|
||||
@ -394,10 +403,10 @@ ucl_elt_obj_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_array_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top)
|
||||
{
|
||||
ucl_object_t *cur = obj;
|
||||
const ucl_object_t *cur = obj;
|
||||
|
||||
if (start_tabs) {
|
||||
ucl_add_tabs (func, tabs, false);
|
||||
@ -419,7 +428,7 @@ ucl_elt_array_write_config (ucl_object_t *obj, struct ucl_emitter_functions *fun
|
||||
* @param buf buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_write_config (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
|
||||
{
|
||||
bool flag;
|
||||
@ -484,14 +493,14 @@ ucl_elt_write_config (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @return rcl output (should be freed after using)
|
||||
*/
|
||||
static void
|
||||
ucl_object_emit_config (ucl_object_t *obj, struct ucl_emitter_functions *func)
|
||||
ucl_object_emit_config (const ucl_object_t *obj, struct ucl_emitter_functions *func)
|
||||
{
|
||||
ucl_elt_write_config (obj, func, 0, false, true, true);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_obj_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs)
|
||||
{
|
||||
bool is_array = (obj->next != NULL);
|
||||
@ -510,10 +519,10 @@ ucl_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_obj_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top)
|
||||
{
|
||||
ucl_object_t *cur;
|
||||
const ucl_object_t *cur;
|
||||
ucl_hash_iter_t it = NULL;
|
||||
|
||||
if (start_tabs) {
|
||||
@ -558,10 +567,10 @@ ucl_elt_obj_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf target buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_array_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top)
|
||||
{
|
||||
ucl_object_t *cur = obj;
|
||||
const ucl_object_t *cur = obj;
|
||||
|
||||
if (start_tabs) {
|
||||
ucl_add_tabs (func, tabs, false);
|
||||
@ -583,7 +592,7 @@ ucl_elt_array_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @param buf buffer
|
||||
*/
|
||||
static void
|
||||
ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
ucl_elt_write_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
unsigned int tabs, bool start_tabs, bool is_top, bool expand_array)
|
||||
{
|
||||
bool flag;
|
||||
@ -648,7 +657,7 @@ ucl_elt_write_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func,
|
||||
* @return rcl output (should be freed after using)
|
||||
*/
|
||||
static void
|
||||
ucl_object_emit_yaml (ucl_object_t *obj, struct ucl_emitter_functions *func)
|
||||
ucl_object_emit_yaml (const ucl_object_t *obj, struct ucl_emitter_functions *func)
|
||||
{
|
||||
ucl_elt_write_yaml (obj, func, 0, false, true, true);
|
||||
}
|
||||
@ -715,7 +724,7 @@ ucl_utstring_append_double (double val, void *ud)
|
||||
|
||||
|
||||
unsigned char *
|
||||
ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
|
||||
ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type)
|
||||
{
|
||||
UT_string *buf = NULL;
|
||||
unsigned char *res = NULL;
|
||||
@ -755,7 +764,7 @@ ucl_object_emit (ucl_object_t *obj, enum ucl_emitter emit_type)
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
struct ucl_emitter_functions *emitter)
|
||||
{
|
||||
if (emit_type == UCL_EMIT_JSON) {
|
||||
@ -777,7 +786,7 @@ ucl_object_emit_full (ucl_object_t *obj, enum ucl_emitter emit_type,
|
||||
|
||||
|
||||
unsigned char *
|
||||
ucl_object_emit_single_json (ucl_object_t *obj)
|
||||
ucl_object_emit_single_json (const ucl_object_t *obj)
|
||||
{
|
||||
UT_string *buf = NULL;
|
||||
unsigned char *res = NULL;
|
||||
|
@ -21,6 +21,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "ucl_internal.h"
|
||||
#include "ucl_hash.h"
|
||||
#include "utlist.h"
|
||||
|
||||
@ -39,11 +40,15 @@ ucl_hash_create (void)
|
||||
void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
|
||||
{
|
||||
ucl_hash_node_t *elt, *tmp;
|
||||
const ucl_object_t *cur, *otmp;
|
||||
|
||||
HASH_ITER (hh, hashlin->buckets, elt, tmp) {
|
||||
HASH_DELETE (hh, hashlin->buckets, elt);
|
||||
if (func) {
|
||||
func (elt->data);
|
||||
DL_FOREACH_SAFE (elt->data, cur, otmp) {
|
||||
/* Need to deconst here */
|
||||
func (__DECONST (ucl_object_t *, cur));
|
||||
}
|
||||
}
|
||||
UCL_FREE (sizeof (ucl_hash_node_t), elt);
|
||||
}
|
||||
@ -51,7 +56,8 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func)
|
||||
}
|
||||
|
||||
void
|
||||
ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen)
|
||||
ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,
|
||||
const char *key, unsigned keylen)
|
||||
{
|
||||
ucl_hash_node_t *node;
|
||||
|
||||
@ -60,7 +66,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsign
|
||||
HASH_ADD_KEYPTR (hh, hashlin->buckets, key, keylen, node);
|
||||
}
|
||||
|
||||
void*
|
||||
const void*
|
||||
ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter)
|
||||
{
|
||||
ucl_hash_node_t *elt = *iter;
|
||||
@ -91,7 +97,7 @@ ucl_hash_iter_has_next (ucl_hash_iter_t iter)
|
||||
}
|
||||
|
||||
|
||||
ucl_object_t*
|
||||
const ucl_object_t*
|
||||
ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
|
||||
{
|
||||
ucl_hash_node_t *found;
|
||||
@ -108,7 +114,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)
|
||||
}
|
||||
|
||||
void
|
||||
ucl_hash_delete (ucl_hash_t* hashlin, ucl_object_t *obj)
|
||||
ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)
|
||||
{
|
||||
ucl_hash_node_t *found;
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
|
||||
typedef struct ucl_hash_node_s
|
||||
{
|
||||
ucl_object_t *data;
|
||||
const ucl_object_t *data;
|
||||
UT_hash_handle hh;
|
||||
} ucl_hash_node_t;
|
||||
|
||||
@ -62,17 +62,19 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func *func);
|
||||
/**
|
||||
* Inserts an element in the the hashtable.
|
||||
*/
|
||||
void ucl_hash_insert (ucl_hash_t* hashlin, ucl_object_t *obj, const char *key, unsigned keylen);
|
||||
void ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj, const char *key,
|
||||
unsigned keylen);
|
||||
|
||||
/**
|
||||
* Delete an element from the the hashtable.
|
||||
*/
|
||||
void ucl_hash_delete (ucl_hash_t* hashlin, ucl_object_t *obj);
|
||||
void ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj);
|
||||
|
||||
/**
|
||||
* Searches an element in the hashtable.
|
||||
*/
|
||||
ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen);
|
||||
const ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key,
|
||||
unsigned keylen);
|
||||
|
||||
|
||||
/**
|
||||
@ -81,7 +83,7 @@ ucl_object_t* ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned ke
|
||||
* @param iter iterator (must be NULL on first iteration)
|
||||
* @return the next object
|
||||
*/
|
||||
void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
|
||||
const void* ucl_hash_iterate (ucl_hash_t *hashlin, ucl_hash_iter_t *iter);
|
||||
|
||||
/**
|
||||
* Check whether an iterator has next element
|
||||
|
@ -24,18 +24,69 @@
|
||||
#ifndef UCL_INTERNAL_H_
|
||||
#define UCL_INTERNAL_H_
|
||||
|
||||
#include <sys/types.h>
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#else
|
||||
/* Help embedded builds */
|
||||
#define HAVE_SYS_TYPES_H
|
||||
#define HAVE_SYS_MMAN_H
|
||||
#define HAVE_SYS_STAT_H
|
||||
#define HAVE_SYS_PARAM_H
|
||||
#define HAVE_LIMITS_H
|
||||
#define HAVE_FCNTL_H
|
||||
#define HAVE_ERRNO_H
|
||||
#define HAVE_UNISTD_H
|
||||
#define HAVE_CTYPE_H
|
||||
#define HAVE_STDIO_H
|
||||
#define HAVE_STRING_H
|
||||
#define HAVE_FLOAT_H
|
||||
#define HAVE_LIBGEN_H
|
||||
#define HAVE_MATH_H
|
||||
#define HAVE_STDBOOL_H
|
||||
#define HAVE_STDINT_H
|
||||
#define HAVE_STDARG_H
|
||||
#ifndef _WIN32
|
||||
#include <sys/mman.h>
|
||||
# define HAVE_REGEX_H
|
||||
#endif
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
# ifndef _WIN32
|
||||
# include <sys/mman.h>
|
||||
# endif
|
||||
#endif
|
||||
#ifdef HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_LIMITS_H
|
||||
#include <limits.h>
|
||||
#endif
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_CTYPE_H
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDIO_H
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "utlist.h"
|
||||
#include "utstring.h"
|
||||
@ -48,6 +99,10 @@
|
||||
#include <openssl/evp.h>
|
||||
#endif
|
||||
|
||||
#ifndef __DECONST
|
||||
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file rcl_internal.h
|
||||
* Internal structures and functions of UCL library
|
||||
@ -142,6 +197,8 @@ struct ucl_parser {
|
||||
struct ucl_chunk *chunks;
|
||||
struct ucl_pubkey *keys;
|
||||
struct ucl_variable *variables;
|
||||
ucl_variable_handler var_handler;
|
||||
void *var_data;
|
||||
UT_string *err;
|
||||
};
|
||||
|
||||
@ -261,20 +318,21 @@ ucl_maybe_parse_boolean (ucl_object_t *obj, const unsigned char *start, size_t l
|
||||
* @return 0 if string is numeric and error code (EINVAL or ERANGE) in case of conversion error
|
||||
*/
|
||||
int ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes);
|
||||
const char *start, const char *end, const char **pos,
|
||||
bool allow_double, bool number_bytes, bool allow_time);
|
||||
|
||||
|
||||
static inline ucl_object_t *
|
||||
static inline const ucl_object_t *
|
||||
ucl_hash_search_obj (ucl_hash_t* hashlin, ucl_object_t *obj)
|
||||
{
|
||||
return (ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
|
||||
return (const ucl_object_t *)ucl_hash_search (hashlin, obj->key, obj->keylen);
|
||||
}
|
||||
|
||||
static inline ucl_hash_t *
|
||||
ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
|
||||
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj) UCL_WARN_UNUSED_RESULT;
|
||||
|
||||
static inline ucl_hash_t *
|
||||
ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj)
|
||||
ucl_hash_insert_object (ucl_hash_t *hashlin, const ucl_object_t *obj)
|
||||
{
|
||||
if (hashlin == NULL) {
|
||||
hashlin = ucl_hash_create ();
|
||||
@ -289,6 +347,6 @@ ucl_hash_insert_object (ucl_hash_t *hashlin, ucl_object_t *obj)
|
||||
* @param obj
|
||||
* @return
|
||||
*/
|
||||
unsigned char * ucl_object_emit_single_json (ucl_object_t *obj);
|
||||
unsigned char * ucl_object_emit_single_json (const ucl_object_t *obj);
|
||||
|
||||
#endif /* UCL_INTERNAL_H_ */
|
||||
|
@ -55,34 +55,6 @@ struct ucl_parser_saved_state {
|
||||
(chunk)->remain --; \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Save parser state
|
||||
* @param chunk
|
||||
* @param s
|
||||
*/
|
||||
static inline void
|
||||
ucl_chunk_save_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
|
||||
{
|
||||
s->column = chunk->column;
|
||||
s->pos = chunk->pos;
|
||||
s->line = chunk->line;
|
||||
s->remain = chunk->remain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore parser state
|
||||
* @param chunk
|
||||
* @param s
|
||||
*/
|
||||
static inline void
|
||||
ucl_chunk_restore_state (struct ucl_chunk *chunk, struct ucl_parser_saved_state *s)
|
||||
{
|
||||
chunk->column = s->column;
|
||||
chunk->pos = s->pos;
|
||||
chunk->line = s->line;
|
||||
chunk->remain = s->remain;
|
||||
}
|
||||
|
||||
static inline void
|
||||
ucl_set_err (struct ucl_chunk *chunk, int code, const char *str, UT_string **err)
|
||||
{
|
||||
@ -264,6 +236,9 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
|
||||
size_t *out_len, bool strict, bool *found)
|
||||
{
|
||||
struct ucl_variable *var;
|
||||
unsigned char *dst;
|
||||
size_t dstlen;
|
||||
bool need_free = false;
|
||||
|
||||
LL_FOREACH (parser->variables, var) {
|
||||
if (strict) {
|
||||
@ -286,6 +261,19 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
|
||||
}
|
||||
}
|
||||
|
||||
/* XXX: can only handle ${VAR} */
|
||||
if (!(*found) && parser->var_handler != NULL && strict) {
|
||||
/* Call generic handler */
|
||||
if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
|
||||
parser->var_data)) {
|
||||
*found = true;
|
||||
if (need_free) {
|
||||
free (dst);
|
||||
}
|
||||
return (ptr + remain);
|
||||
}
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@ -299,7 +287,8 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema
|
||||
* @return
|
||||
*/
|
||||
static const char *
|
||||
ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, size_t *out_len, bool *vars_found)
|
||||
ucl_check_variable (struct ucl_parser *parser, const char *ptr,
|
||||
size_t remain, size_t *out_len, bool *vars_found)
|
||||
{
|
||||
const char *p, *end, *ret = ptr;
|
||||
bool found = false;
|
||||
@ -310,7 +299,8 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr, size_t remain, s
|
||||
end = ptr + remain;
|
||||
while (p < end) {
|
||||
if (*p == '}') {
|
||||
ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1, out_len, true, &found);
|
||||
ret = ucl_check_variable_safe (parser, ptr + 1, p - ptr - 1,
|
||||
out_len, true, &found);
|
||||
if (found) {
|
||||
/* {} must be excluded actually */
|
||||
ret ++;
|
||||
@ -356,10 +346,13 @@ static const char *
|
||||
ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
|
||||
size_t remain, unsigned char **dest)
|
||||
{
|
||||
unsigned char *d = *dest;
|
||||
unsigned char *d = *dest, *dst;
|
||||
const char *p = ptr + 1, *ret;
|
||||
struct ucl_variable *var;
|
||||
size_t dstlen;
|
||||
bool need_free = false;
|
||||
bool found = false;
|
||||
bool strict = false;
|
||||
|
||||
ret = ptr + 1;
|
||||
remain --;
|
||||
@ -371,6 +364,7 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
|
||||
}
|
||||
else if (*p == '{') {
|
||||
p ++;
|
||||
strict = true;
|
||||
ret += 2;
|
||||
remain -= 2;
|
||||
}
|
||||
@ -387,9 +381,22 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
memcpy (d, ptr, 2);
|
||||
d += 2;
|
||||
ret --;
|
||||
if (strict && parser->var_handler != NULL) {
|
||||
if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,
|
||||
parser->var_data)) {
|
||||
memcpy (d, dst, dstlen);
|
||||
ret += dstlen;
|
||||
d += remain;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave variable as is */
|
||||
if (!found) {
|
||||
memcpy (d, ptr, 2);
|
||||
d += 2;
|
||||
ret --;
|
||||
}
|
||||
}
|
||||
|
||||
*dest = d;
|
||||
@ -544,6 +551,10 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
||||
}
|
||||
|
||||
st = UCL_ALLOC (sizeof (struct ucl_stack));
|
||||
if (st == NULL) {
|
||||
ucl_set_err (parser->chunks, 0, "cannot allocate memory for an object", &parser->err);
|
||||
return NULL;
|
||||
}
|
||||
st->obj = obj;
|
||||
st->level = level;
|
||||
LL_PREPEND (parser->stack, st);
|
||||
@ -554,12 +565,13 @@ ucl_add_parser_stack (ucl_object_t *obj, struct ucl_parser *parser, bool is_arra
|
||||
|
||||
int
|
||||
ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
const char *start, const char *end, const char **pos, bool allow_double, bool number_bytes)
|
||||
const char *start, const char *end, const char **pos,
|
||||
bool allow_double, bool number_bytes, bool allow_time)
|
||||
{
|
||||
const char *p = start, *c = start;
|
||||
char *endptr;
|
||||
bool got_dot = false, got_exp = false, need_double = false,
|
||||
is_date = false, valid_start = false, is_hex = false,
|
||||
is_time = false, valid_start = false, is_hex = false,
|
||||
is_neg = false;
|
||||
double dv = 0;
|
||||
int64_t lv = 0;
|
||||
@ -657,7 +669,8 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
}
|
||||
|
||||
/* Now check endptr */
|
||||
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {
|
||||
if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0' ||
|
||||
ucl_test_character (*endptr, UCL_CHARACTER_WHITESPACE_UNSAFE)) {
|
||||
p = endptr;
|
||||
goto set_obj;
|
||||
}
|
||||
@ -678,7 +691,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
need_double = true;
|
||||
dv = lv;
|
||||
}
|
||||
is_date = true;
|
||||
is_time = true;
|
||||
if (p[0] == 'm' || p[0] == 'M') {
|
||||
dv /= 1000.;
|
||||
}
|
||||
@ -708,7 +721,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
p ++;
|
||||
goto set_obj;
|
||||
}
|
||||
else if (end - p >= 3) {
|
||||
else if (allow_time && end - p >= 3) {
|
||||
if (tolower (p[0]) == 'm' &&
|
||||
tolower (p[1]) == 'i' &&
|
||||
tolower (p[2]) == 'n') {
|
||||
@ -717,7 +730,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
need_double = true;
|
||||
dv = lv;
|
||||
}
|
||||
is_date = true;
|
||||
is_time = true;
|
||||
dv *= 60.;
|
||||
p += 3;
|
||||
goto set_obj;
|
||||
@ -737,13 +750,14 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
break;
|
||||
case 'S':
|
||||
case 's':
|
||||
if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
|
||||
if (allow_time &&
|
||||
(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
|
||||
if (!need_double) {
|
||||
need_double = true;
|
||||
dv = lv;
|
||||
}
|
||||
p ++;
|
||||
is_date = true;
|
||||
is_time = true;
|
||||
goto set_obj;
|
||||
}
|
||||
break;
|
||||
@ -755,12 +769,13 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
case 'W':
|
||||
case 'Y':
|
||||
case 'y':
|
||||
if (p == end - 1 || ucl_lex_is_atom_end (p[1])) {
|
||||
if (allow_time &&
|
||||
(p == end - 1 || ucl_lex_is_atom_end (p[1]))) {
|
||||
if (!need_double) {
|
||||
need_double = true;
|
||||
dv = lv;
|
||||
}
|
||||
is_date = true;
|
||||
is_time = true;
|
||||
dv *= ucl_lex_time_multiplier (*p);
|
||||
p ++;
|
||||
goto set_obj;
|
||||
@ -773,8 +788,8 @@ ucl_maybe_parse_number (ucl_object_t *obj,
|
||||
return EINVAL;
|
||||
|
||||
set_obj:
|
||||
if (allow_double && (need_double || is_date)) {
|
||||
if (!is_date) {
|
||||
if (allow_double && (need_double || is_time)) {
|
||||
if (!is_time) {
|
||||
obj->type = UCL_FLOAT;
|
||||
}
|
||||
else {
|
||||
@ -803,7 +818,8 @@ ucl_lex_number (struct ucl_parser *parser,
|
||||
const unsigned char *pos;
|
||||
int ret;
|
||||
|
||||
ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos, true, false);
|
||||
ret = ucl_maybe_parse_number (obj, chunk->pos, chunk->end, (const char **)&pos,
|
||||
true, false, ((parser->flags & UCL_PARSER_NO_TIME) == 0));
|
||||
|
||||
if (ret == 0) {
|
||||
chunk->remain -= pos - chunk->pos;
|
||||
@ -1077,19 +1093,19 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, bool *next_ke
|
||||
keylen = ucl_copy_or_store_ptr (parser, c, &nobj->trash_stack[UCL_TRASH_KEY],
|
||||
&key, end - c, need_unescape, parser->flags & UCL_PARSER_KEY_LOWERCASE, false);
|
||||
if (keylen == -1) {
|
||||
ucl_object_free(nobj);
|
||||
ucl_object_unref (nobj);
|
||||
return false;
|
||||
}
|
||||
else if (keylen == 0) {
|
||||
ucl_set_err (chunk, UCL_ESYNTAX, "empty keys are not allowed", &parser->err);
|
||||
ucl_object_free(nobj);
|
||||
ucl_object_unref (nobj);
|
||||
return false;
|
||||
}
|
||||
|
||||
container = parser->stack->obj->value.ov;
|
||||
nobj->key = key;
|
||||
nobj->keylen = keylen;
|
||||
tobj = ucl_hash_search_obj (container, nobj);
|
||||
tobj = __DECONST (ucl_object_t *, ucl_hash_search_obj (container, nobj));
|
||||
if (tobj == NULL) {
|
||||
container = ucl_hash_insert_object (container, nobj);
|
||||
nobj->prev = nobj;
|
||||
@ -1308,6 +1324,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
||||
obj = ucl_get_value_object (parser);
|
||||
/* We have a new object */
|
||||
obj = ucl_add_parser_stack (obj, parser, false, parser->stack->level);
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
return true;
|
||||
@ -1316,6 +1335,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)
|
||||
obj = ucl_get_value_object (parser);
|
||||
/* We have a new array */
|
||||
obj = ucl_add_parser_stack (obj, parser, true, parser->stack->level);
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ucl_chunk_skipc (chunk, p);
|
||||
return true;
|
||||
@ -1608,6 +1630,9 @@ ucl_state_machine (struct ucl_parser *parser)
|
||||
else {
|
||||
obj = ucl_add_parser_stack (NULL, parser, false, 0);
|
||||
}
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
parser->top_obj = obj;
|
||||
parser->cur_obj = obj;
|
||||
parser->state = UCL_STATE_INIT;
|
||||
@ -1673,7 +1698,11 @@ ucl_state_machine (struct ucl_parser *parser)
|
||||
else if (parser->state != UCL_STATE_MACRO_NAME) {
|
||||
if (next_key && parser->stack->obj->type == UCL_OBJECT) {
|
||||
/* Parse more keys and nest objects accordingly */
|
||||
obj = ucl_add_parser_stack (parser->cur_obj, parser, false, parser->stack->level + 1);
|
||||
obj = ucl_add_parser_stack (parser->cur_obj, parser, false,
|
||||
parser->stack->level + 1);
|
||||
if (obj == NULL) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
parser->state = UCL_STATE_VALUE;
|
||||
@ -1787,6 +1816,9 @@ ucl_parser_new (int flags)
|
||||
struct ucl_parser *new;
|
||||
|
||||
new = UCL_ALLOC (sizeof (struct ucl_parser));
|
||||
if (new == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memset (new, 0, sizeof (struct ucl_parser));
|
||||
|
||||
ucl_parser_register_macro (new, "include", ucl_include_handler, new);
|
||||
@ -1808,7 +1840,13 @@ ucl_parser_register_macro (struct ucl_parser *parser, const char *macro,
|
||||
{
|
||||
struct ucl_macro *new;
|
||||
|
||||
if (macro == NULL || handler == NULL) {
|
||||
return;
|
||||
}
|
||||
new = UCL_ALLOC (sizeof (struct ucl_macro));
|
||||
if (new == NULL) {
|
||||
return;
|
||||
}
|
||||
memset (new, 0, sizeof (struct ucl_macro));
|
||||
new->handler = handler;
|
||||
new->name = strdup (macro);
|
||||
@ -1851,6 +1889,9 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
||||
else {
|
||||
if (new == NULL) {
|
||||
new = UCL_ALLOC (sizeof (struct ucl_variable));
|
||||
if (new == NULL) {
|
||||
return;
|
||||
}
|
||||
memset (new, 0, sizeof (struct ucl_variable));
|
||||
new->var = strdup (var);
|
||||
new->var_len = strlen (var);
|
||||
@ -1867,14 +1908,30 @@ ucl_parser_register_variable (struct ucl_parser *parser, const char *var,
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ucl_parser_set_variables_handler (struct ucl_parser *parser,
|
||||
ucl_variable_handler handler, void *ud)
|
||||
{
|
||||
parser->var_handler = handler;
|
||||
parser->var_data = ud;
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
||||
size_t len)
|
||||
{
|
||||
struct ucl_chunk *chunk;
|
||||
|
||||
if (data == NULL || len == 0) {
|
||||
ucl_create_err (&parser->err, "invalid chunk added");
|
||||
return false;
|
||||
}
|
||||
if (parser->state != UCL_STATE_ERROR) {
|
||||
chunk = UCL_ALLOC (sizeof (struct ucl_chunk));
|
||||
if (chunk == NULL) {
|
||||
ucl_create_err (&parser->err, "cannot allocate chunk structure");
|
||||
return false;
|
||||
}
|
||||
chunk->begin = data;
|
||||
chunk->remain = len;
|
||||
chunk->pos = chunk->begin;
|
||||
@ -1895,3 +1952,18 @@ ucl_parser_add_chunk (struct ucl_parser *parser, const unsigned char *data,
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ucl_parser_add_string (struct ucl_parser *parser, const char *data,
|
||||
size_t len)
|
||||
{
|
||||
if (data == NULL) {
|
||||
ucl_create_err (&parser->err, "invalid string added");
|
||||
return false;
|
||||
}
|
||||
if (len == 0) {
|
||||
len = strlen (data);
|
||||
}
|
||||
|
||||
return ucl_parser_add_chunk (parser, (const unsigned char *)data, len);
|
||||
}
|
||||
|
1014
contrib/libucl/src/ucl_schema.c
Normal file
1014
contrib/libucl/src/ucl_schema.c
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1
contrib/libucl/stamp-h.in
Normal file
1
contrib/libucl/stamp-h.in
Normal file
@ -0,0 +1 @@
|
||||
timestamp
|
8
contrib/libucl/tests/.gitignore
vendored
Normal file
8
contrib/libucl/tests/.gitignore
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
*.log
|
||||
*.trs
|
||||
*.plist
|
||||
|
||||
test_basic
|
||||
test_generate
|
||||
test_schema
|
||||
test_speed
|
@ -1 +0,0 @@
|
||||
a []
|
@ -1 +0,0 @@
|
||||
# test
|
@ -1 +0,0 @@
|
||||
|
@ -1 +0,0 @@
|
||||
|
33
contrib/libucl/tests/Makefile.am
Normal file
33
contrib/libucl/tests/Makefile.am
Normal file
@ -0,0 +1,33 @@
|
||||
EXTRA_DIST = $(TESTS) basic schema generate.res rcl_test.json.xz
|
||||
|
||||
TESTS = basic.test \
|
||||
generate.test \
|
||||
schema.test \
|
||||
speed.test
|
||||
TESTS_ENVIRONMENT = $(SH) \
|
||||
TEST_DIR=$(top_srcdir)/tests \
|
||||
TEST_OUT_DIR=$(top_builddir)/tests \
|
||||
TEST_BINARY_DIR=$(top_builddir)/tests
|
||||
|
||||
common_test_cflags = -I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/uthash
|
||||
common_test_ldadd = $(top_builddir)/src/libucl.la
|
||||
|
||||
test_basic_SOURCES = test_basic.c
|
||||
test_basic_LDADD = $(common_test_ldadd)
|
||||
test_basic_CFLAGS = $(common_test_cflags)
|
||||
|
||||
test_speed_SOURCES = test_speed.c
|
||||
test_speed_LDADD = $(common_test_ldadd)
|
||||
test_speed_CFLAGS = $(common_test_cflags)
|
||||
|
||||
test_generate_SOURCES = test_generate.c
|
||||
test_generate_LDADD = $(common_test_ldadd)
|
||||
test_generate_CFLAGS = $(common_test_cflags)
|
||||
|
||||
test_schema_SOURCES = test_schema.c
|
||||
test_schema_LDADD = $(common_test_ldadd)
|
||||
test_schema_CFLAGS = $(common_test_cflags)
|
||||
|
||||
check_PROGRAMS = test_basic test_speed test_generate test_schema
|
26
contrib/libucl/tests/basic.test
Executable file
26
contrib/libucl/tests/basic.test
Executable file
@ -0,0 +1,26 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${TEST_BINARY_DIR}/test_basic
|
||||
|
||||
for _tin in ${TEST_DIR}/basic/*.in ; do
|
||||
_t=`echo $_tin | sed -e 's/.in$//'`
|
||||
_out=${TEST_OUT_DIR}/basic.out
|
||||
$PROG $_t.in $_out
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Test: $_t failed, output:"
|
||||
cat $_out
|
||||
rm $_out
|
||||
exit 1
|
||||
fi
|
||||
if [ -f $_t.res ] ; then
|
||||
diff -s $_out $_t.res -u 2>/dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
rm $_out
|
||||
echo "Test: $_t output missmatch"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
rm $_out
|
||||
done
|
||||
|
||||
|
9
contrib/libucl/tests/basic/10.in
Normal file
9
contrib/libucl/tests/basic/10.in
Normal file
@ -0,0 +1,9 @@
|
||||
section foo bar {
|
||||
key = value
|
||||
}
|
||||
section foo baz {
|
||||
key = value
|
||||
}
|
||||
section foo {
|
||||
bar = lol /* removing this line makes parsing successful */
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
.include "$CURDIR/9.inc"
|
||||
.include "$CURDIR/9-empty.inc"
|
||||
.include "$CURDIR/9-comment.inc"
|
||||
#.include "$CURDIR/9.inc"
|
||||
.include "$CURDIR/9.inc"
|
13
contrib/libucl/tests/generate.test
Executable file
13
contrib/libucl/tests/generate.test
Executable file
@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${TEST_BINARY_DIR}/test_generate
|
||||
|
||||
$PROG ${TEST_OUT_DIR}/generate.out
|
||||
diff -s ${TEST_OUT_DIR}/generate.out ${TEST_DIR}/generate.res -u 2>/dev/null
|
||||
if [ $? -ne 0 ] ; then
|
||||
rm ${TEST_OUT_DIR}/generate.out
|
||||
echo "Test: generate.res output missmatch"
|
||||
exit 1
|
||||
fi
|
||||
rm ${TEST_OUT_DIR}/generate.out
|
||||
|
@ -37,6 +37,15 @@ if [ $# -gt 2 ] ; then
|
||||
rm ${TEST_DIR}/generate.out
|
||||
fi
|
||||
|
||||
if [ $# -gt 3 ] ; then
|
||||
rm /tmp/_ucl_test_schema.out ||true
|
||||
for i in ${TEST_DIR}/schema/*.json ; do
|
||||
_name=`basename $i`
|
||||
printf "running schema test suite $_name... "
|
||||
cat $i | $4 >> /tmp/_ucl_test_schema.out && ( echo "OK" ) || ( echo "Fail" )
|
||||
done
|
||||
fi
|
||||
|
||||
sh -c "xz -c < /dev/null > /dev/null"
|
||||
if [ $? -eq 0 -a $# -gt 1 ] ; then
|
||||
echo 'Running speed tests'
|
||||
|
9
contrib/libucl/tests/schema.test
Executable file
9
contrib/libucl/tests/schema.test
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${TEST_BINARY_DIR}/test_schema
|
||||
rm /tmp/_ucl_test_schema.out ||true
|
||||
for i in ${TEST_DIR}/schema/*.json ; do
|
||||
_name=`basename $i`
|
||||
printf "running schema test suite $_name... "
|
||||
$PROG >> /tmp/_ucl_test_schema.out < $i && ( echo "OK" ) || ( echo "Fail" )
|
||||
done
|
82
contrib/libucl/tests/schema/additionalItems.json
Normal file
82
contrib/libucl/tests/schema/additionalItems.json
Normal file
@ -0,0 +1,82 @@
|
||||
[
|
||||
{
|
||||
"description": "additionalItems as schema",
|
||||
"schema": {
|
||||
"items": [{}],
|
||||
"additionalItems": {"type": "integer"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "additional items match schema",
|
||||
"data": [ null, 2, 3, 4 ],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "additional items do not match schema",
|
||||
"data": [ null, 2, 3, "foo" ],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "items is schema, no additionalItems",
|
||||
"schema": {
|
||||
"items": {},
|
||||
"additionalItems": false
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "all items match schema",
|
||||
"data": [ 1, 2, 3, 4, 5 ],
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "array of items with no additionalItems",
|
||||
"schema": {
|
||||
"items": [{}, {}, {}],
|
||||
"additionalItems": false
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "no additional items present",
|
||||
"data": [ 1, 2, 3 ],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "additional items are not permitted",
|
||||
"data": [ 1, 2, 3, 4 ],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "additionalItems as false without items",
|
||||
"schema": {"additionalItems": false},
|
||||
"tests": [
|
||||
{
|
||||
"description":
|
||||
"items defaults to empty schema so everything is valid",
|
||||
"data": [ 1, 2, 3, 4, 5 ],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores non-arrays",
|
||||
"data": {"foo" : "bar"},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "additionalItems are allowed by default",
|
||||
"schema": {"items": [{"type": "integer"}]},
|
||||
"tests": [
|
||||
{
|
||||
"description": "only the first item is validated",
|
||||
"data": [1, "foo", false],
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
69
contrib/libucl/tests/schema/additionalProperties.json
Normal file
69
contrib/libucl/tests/schema/additionalProperties.json
Normal file
@ -0,0 +1,69 @@
|
||||
[
|
||||
{
|
||||
"description":
|
||||
"additionalProperties being false does not allow other properties",
|
||||
"schema": {
|
||||
"properties": {"foo": {}, "bar": {}},
|
||||
"patternProperties": { "^v": {} },
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "no additional properties is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an additional property is invalid",
|
||||
"data": {"foo" : 1, "bar" : 2, "quux" : "boom"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": [1, 2, 3],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "patternProperties are not additional properties",
|
||||
"data": {"foo":1, "vroom": 2},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description":
|
||||
"additionalProperties allows a schema which should validate",
|
||||
"schema": {
|
||||
"properties": {"foo": {}, "bar": {}},
|
||||
"additionalProperties": {"type": "boolean"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "no additional properties is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an additional valid property is valid",
|
||||
"data": {"foo" : 1, "bar" : 2, "quux" : true},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an additional invalid property is invalid",
|
||||
"data": {"foo" : 1, "bar" : 2, "quux" : 12},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "additionalProperties are allowed by default",
|
||||
"schema": {"properties": {"foo": {}, "bar": {}}},
|
||||
"tests": [
|
||||
{
|
||||
"description": "additional properties are allowed",
|
||||
"data": {"foo": 1, "bar": 2, "quux": true},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
112
contrib/libucl/tests/schema/allOf.json
Normal file
112
contrib/libucl/tests/schema/allOf.json
Normal file
@ -0,0 +1,112 @@
|
||||
[
|
||||
{
|
||||
"description": "allOf",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{
|
||||
"properties": {
|
||||
"bar": {"type": "integer"}
|
||||
},
|
||||
"required": ["bar"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"foo": {"type": "string"}
|
||||
},
|
||||
"required": ["foo"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "allOf",
|
||||
"data": {"foo": "baz", "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch second",
|
||||
"data": {"foo": "baz"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "mismatch first",
|
||||
"data": {"bar": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "wrong type",
|
||||
"data": {"foo": "baz", "bar": "quux"},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "allOf with base schema",
|
||||
"schema": {
|
||||
"properties": {"bar": {"type": "integer"}},
|
||||
"required": ["bar"],
|
||||
"allOf" : [
|
||||
{
|
||||
"properties": {
|
||||
"foo": {"type": "string"}
|
||||
},
|
||||
"required": ["foo"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"baz": {"type": "null"}
|
||||
},
|
||||
"required": ["baz"]
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid",
|
||||
"data": {"foo": "quux", "bar": 2, "baz": null},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch base schema",
|
||||
"data": {"foo": "quux", "baz": null},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "mismatch first allOf",
|
||||
"data": {"bar": 2, "baz": null},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "mismatch second allOf",
|
||||
"data": {"foo": "quux", "bar": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "mismatch both",
|
||||
"data": {"bar": 2},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "allOf simple types",
|
||||
"schema": {
|
||||
"allOf": [
|
||||
{"maximum": 30},
|
||||
{"minimum": 20}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid",
|
||||
"data": 25,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch one",
|
||||
"data": 35,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
68
contrib/libucl/tests/schema/anyOf.json
Normal file
68
contrib/libucl/tests/schema/anyOf.json
Normal file
@ -0,0 +1,68 @@
|
||||
[
|
||||
{
|
||||
"description": "anyOf",
|
||||
"schema": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"minimum": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "first anyOf valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "second anyOf valid",
|
||||
"data": 2.5,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "both anyOf valid",
|
||||
"data": 3,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "neither anyOf valid",
|
||||
"data": 1.5,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "anyOf with base schema",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"anyOf" : [
|
||||
{
|
||||
"maxLength": 2
|
||||
},
|
||||
{
|
||||
"minLength": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "mismatch base schema",
|
||||
"data": 3,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "one anyOf valid",
|
||||
"data": "foobar",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "both anyOf invalid",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
32
contrib/libucl/tests/schema/definitions.json
Normal file
32
contrib/libucl/tests/schema/definitions.json
Normal file
@ -0,0 +1,32 @@
|
||||
[
|
||||
{
|
||||
"description": "valid definition",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid definition schema",
|
||||
"data": {
|
||||
"definitions": {
|
||||
"foo": {"type": "integer"}
|
||||
}
|
||||
},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "invalid definition",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "invalid definition schema",
|
||||
"data": {
|
||||
"definitions": {
|
||||
"foo": {"type": 1}
|
||||
}
|
||||
},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
113
contrib/libucl/tests/schema/dependencies.json
Normal file
113
contrib/libucl/tests/schema/dependencies.json
Normal file
@ -0,0 +1,113 @@
|
||||
[
|
||||
{
|
||||
"description": "dependencies",
|
||||
"schema": {
|
||||
"dependencies": {"bar": ["foo"]}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "neither",
|
||||
"data": {},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "nondependant",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "with dependency",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "missing dependency",
|
||||
"data": {"bar": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "multiple dependencies",
|
||||
"schema": {
|
||||
"dependencies": {"quux": ["foo", "bar"]}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "neither",
|
||||
"data": {},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "nondependants",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "with dependencies",
|
||||
"data": {"foo": 1, "bar": 2, "quux": 3},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "missing dependency",
|
||||
"data": {"foo": 1, "quux": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "missing other dependency",
|
||||
"data": {"bar": 1, "quux": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "missing both dependencies",
|
||||
"data": {"quux": 1},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "multiple dependencies subschema",
|
||||
"schema": {
|
||||
"dependencies": {
|
||||
"bar": {
|
||||
"properties": {
|
||||
"foo": {"type": "integer"},
|
||||
"bar": {"type": "integer"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "no dependency",
|
||||
"data": {"foo": "quux"},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "wrong type",
|
||||
"data": {"foo": "quux", "bar": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "wrong type other",
|
||||
"data": {"foo": 2, "bar": "quux"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "wrong type both",
|
||||
"data": {"foo": "quux", "bar": "quux"},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
72
contrib/libucl/tests/schema/enum.json
Normal file
72
contrib/libucl/tests/schema/enum.json
Normal file
@ -0,0 +1,72 @@
|
||||
[
|
||||
{
|
||||
"description": "simple enum validation",
|
||||
"schema": {"enum": [1, 2, 3]},
|
||||
"tests": [
|
||||
{
|
||||
"description": "one of the enum is valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "something else is invalid",
|
||||
"data": 4,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "heterogeneous enum validation",
|
||||
"schema": {"enum": [6, "foo", [], true, {"foo": 12}]},
|
||||
"tests": [
|
||||
{
|
||||
"description": "one of the enum is valid",
|
||||
"data": [],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "something else is invalid",
|
||||
"data": null,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "objects are deep compared",
|
||||
"data": {"foo": false},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "enums in properties",
|
||||
"schema": {
|
||||
"type":"object",
|
||||
"properties": {
|
||||
"foo": {"enum":["foo"]},
|
||||
"bar": {"enum":["bar"]}
|
||||
},
|
||||
"required": ["bar"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "both properties are valid",
|
||||
"data": {"foo":"foo", "bar":"bar"},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "missing optional property is valid",
|
||||
"data": {"bar":"bar"},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "missing required property is invalid",
|
||||
"data": {"foo":"foo"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "missing all properties is invalid",
|
||||
"data": {},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
46
contrib/libucl/tests/schema/items.json
Normal file
46
contrib/libucl/tests/schema/items.json
Normal file
@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"description": "a schema given for items",
|
||||
"schema": {
|
||||
"items": {"type": "integer"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid items",
|
||||
"data": [ 1, 2, 3 ],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "wrong type of items",
|
||||
"data": [1, "x"],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-arrays",
|
||||
"data": {"foo" : "bar"},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "an array of schemas for items",
|
||||
"schema": {
|
||||
"items": [
|
||||
{"type": "integer"},
|
||||
{"type": "string"}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "correct types",
|
||||
"data": [ 1, "foo" ],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "wrong types",
|
||||
"data": [ "foo", 1 ],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/maxItems.json
Normal file
28
contrib/libucl/tests/schema/maxItems.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "maxItems validation",
|
||||
"schema": {"maxItems": 2},
|
||||
"tests": [
|
||||
{
|
||||
"description": "shorter is valid",
|
||||
"data": [1],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": [1, 2],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too long is invalid",
|
||||
"data": [1, 2, 3],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-arrays",
|
||||
"data": "foobar",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/maxLength.json
Normal file
28
contrib/libucl/tests/schema/maxLength.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "maxLength validation",
|
||||
"schema": {"maxLength": 2},
|
||||
"tests": [
|
||||
{
|
||||
"description": "shorter is valid",
|
||||
"data": "f",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": "fo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too long is invalid",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-strings",
|
||||
"data": 10,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/maxProperties.json
Normal file
28
contrib/libucl/tests/schema/maxProperties.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "maxProperties validation",
|
||||
"schema": {"maxProperties": 2},
|
||||
"tests": [
|
||||
{
|
||||
"description": "shorter is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too long is invalid",
|
||||
"data": {"foo": 1, "bar": 2, "baz": 3},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": "foobar",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
42
contrib/libucl/tests/schema/maximum.json
Normal file
42
contrib/libucl/tests/schema/maximum.json
Normal file
@ -0,0 +1,42 @@
|
||||
[
|
||||
{
|
||||
"description": "maximum validation",
|
||||
"schema": {"maximum": 3.0},
|
||||
"tests": [
|
||||
{
|
||||
"description": "below the maximum is valid",
|
||||
"data": 2.6,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "above the maximum is invalid",
|
||||
"data": 3.5,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-numbers",
|
||||
"data": "x",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "exclusiveMaximum validation",
|
||||
"schema": {
|
||||
"maximum": 3.0,
|
||||
"exclusiveMaximum": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "below the maximum is still valid",
|
||||
"data": 2.2,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "boundary point is invalid",
|
||||
"data": 3.0,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/minItems.json
Normal file
28
contrib/libucl/tests/schema/minItems.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "minItems validation",
|
||||
"schema": {"minItems": 1},
|
||||
"tests": [
|
||||
{
|
||||
"description": "longer is valid",
|
||||
"data": [1, 2],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": [1],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too short is invalid",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-arrays",
|
||||
"data": "",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/minLength.json
Normal file
28
contrib/libucl/tests/schema/minLength.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "minLength validation",
|
||||
"schema": {"minLength": 2},
|
||||
"tests": [
|
||||
{
|
||||
"description": "longer is valid",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": "fo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too short is invalid",
|
||||
"data": "f",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-strings",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
28
contrib/libucl/tests/schema/minProperties.json
Normal file
28
contrib/libucl/tests/schema/minProperties.json
Normal file
@ -0,0 +1,28 @@
|
||||
[
|
||||
{
|
||||
"description": "minProperties validation",
|
||||
"schema": {"minProperties": 1},
|
||||
"tests": [
|
||||
{
|
||||
"description": "longer is valid",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "exact length is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "too short is invalid",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": "",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
42
contrib/libucl/tests/schema/minimum.json
Normal file
42
contrib/libucl/tests/schema/minimum.json
Normal file
@ -0,0 +1,42 @@
|
||||
[
|
||||
{
|
||||
"description": "minimum validation",
|
||||
"schema": {"minimum": 1.1},
|
||||
"tests": [
|
||||
{
|
||||
"description": "above the minimum is valid",
|
||||
"data": 2.6,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "below the minimum is invalid",
|
||||
"data": 0.6,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-numbers",
|
||||
"data": "x",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "exclusiveMinimum validation",
|
||||
"schema": {
|
||||
"minimum": 1.1,
|
||||
"exclusiveMinimum": true
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "above the minimum is still valid",
|
||||
"data": 1.2,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "boundary point is invalid",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
60
contrib/libucl/tests/schema/multipleOf.json
Normal file
60
contrib/libucl/tests/schema/multipleOf.json
Normal file
@ -0,0 +1,60 @@
|
||||
[
|
||||
{
|
||||
"description": "by int",
|
||||
"schema": {"multipleOf": 2},
|
||||
"tests": [
|
||||
{
|
||||
"description": "int by int",
|
||||
"data": 10,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "int by int fail",
|
||||
"data": 7,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-numbers",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "by number",
|
||||
"schema": {"multipleOf": 1.5},
|
||||
"tests": [
|
||||
{
|
||||
"description": "zero is multiple of anything",
|
||||
"data": 0,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "4.5 is multiple of 1.5",
|
||||
"data": 4.5,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "35 is not multiple of 1.5",
|
||||
"data": 35,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "by small number",
|
||||
"schema": {"multipleOf": 0.0001},
|
||||
"tests": [
|
||||
{
|
||||
"description": "0.0075 is multiple of 0.0001",
|
||||
"data": 0.0075,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "0.00751 is not multiple of 0.0001",
|
||||
"data": 0.00751,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
96
contrib/libucl/tests/schema/not.json
Normal file
96
contrib/libucl/tests/schema/not.json
Normal file
@ -0,0 +1,96 @@
|
||||
[
|
||||
{
|
||||
"description": "not",
|
||||
"schema": {
|
||||
"not": {"type": "integer"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "allowed",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "disallowed",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "not multiple types",
|
||||
"schema": {
|
||||
"not": {"type": ["integer", "boolean"]}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "valid",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "other mismatch",
|
||||
"data": true,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "not more complex schema",
|
||||
"schema": {
|
||||
"not": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"foo": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "match",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "other match",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch",
|
||||
"data": {"foo": "bar"},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "forbidden property",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {
|
||||
"not": {}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "property present",
|
||||
"data": {"foo": 1, "bar": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "property absent",
|
||||
"data": {"bar": 1, "baz": 2},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
]
|
68
contrib/libucl/tests/schema/oneOf.json
Normal file
68
contrib/libucl/tests/schema/oneOf.json
Normal file
@ -0,0 +1,68 @@
|
||||
[
|
||||
{
|
||||
"description": "oneOf",
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"minimum": 2
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "first oneOf valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "second oneOf valid",
|
||||
"data": 2.5,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "both oneOf valid",
|
||||
"data": 3,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "neither oneOf valid",
|
||||
"data": 1.5,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "oneOf with base schema",
|
||||
"schema": {
|
||||
"type": "string",
|
||||
"oneOf" : [
|
||||
{
|
||||
"minLength": 2
|
||||
},
|
||||
{
|
||||
"maxLength": 4
|
||||
}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "mismatch base schema",
|
||||
"data": 3,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "one oneOf valid",
|
||||
"data": "foobar",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "both oneOf valid",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
23
contrib/libucl/tests/schema/pattern.json
Normal file
23
contrib/libucl/tests/schema/pattern.json
Normal file
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"description": "pattern validation",
|
||||
"schema": {"pattern": "^a*$"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a matching pattern is valid",
|
||||
"data": "aaa",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a non-matching pattern is invalid",
|
||||
"data": "abc",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-strings",
|
||||
"data": true,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
110
contrib/libucl/tests/schema/patternProperties.json
Normal file
110
contrib/libucl/tests/schema/patternProperties.json
Normal file
@ -0,0 +1,110 @@
|
||||
[
|
||||
{
|
||||
"description":
|
||||
"patternProperties validates properties matching a regex",
|
||||
"schema": {
|
||||
"patternProperties": {
|
||||
"f.*o": {"type": "integer"}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a single valid match is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "multiple valid matches is valid",
|
||||
"data": {"foo": 1, "foooooo" : 2},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a single invalid match is invalid",
|
||||
"data": {"foo": "bar", "fooooo": 2},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "multiple invalid matches is invalid",
|
||||
"data": {"foo": "bar", "foooooo" : "baz"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": 12,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "multiple simultaneous patternProperties are validated",
|
||||
"schema": {
|
||||
"patternProperties": {
|
||||
"a*": {"type": "integer"},
|
||||
"aaa*": {"maximum": 20}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "a single valid match is valid",
|
||||
"data": {"a": 21},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a simultaneous match is valid",
|
||||
"data": {"aaaa": 18},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "multiple matches is valid",
|
||||
"data": {"a": 21, "aaaa": 18},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an invalid due to one is invalid",
|
||||
"data": {"a": "bar"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an invalid due to the other is invalid",
|
||||
"data": {"aaaa": 31},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an invalid due to both is invalid",
|
||||
"data": {"aaa": "foo", "aaaa": 31},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "regexes are not anchored by default and are case sensitive",
|
||||
"schema": {
|
||||
"patternProperties": {
|
||||
"[0-9]{2,}": { "type": "boolean" },
|
||||
"X_": { "type": "string" }
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "non recognized members are ignored",
|
||||
"data": { "answer 1": "42" },
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "recognized members are accounted for",
|
||||
"data": { "a31b": null },
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "regexes are case sensitive",
|
||||
"data": { "a_x_3": 3 },
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "regexes are case sensitive, 2",
|
||||
"data": { "a_X_3": 3 },
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
92
contrib/libucl/tests/schema/properties.json
Normal file
92
contrib/libucl/tests/schema/properties.json
Normal file
@ -0,0 +1,92 @@
|
||||
[
|
||||
{
|
||||
"description": "object properties validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {"type": "integer"},
|
||||
"bar": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "both properties present and valid is valid",
|
||||
"data": {"foo": 1, "bar": "baz"},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "one property invalid is invalid",
|
||||
"data": {"foo": 1, "bar": {}},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "both properties invalid is invalid",
|
||||
"data": {"foo": [], "bar": {}},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "doesn't invalidate other properties",
|
||||
"data": {"quux": []},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ignores non-objects",
|
||||
"data": [],
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description":
|
||||
"properties, patternProperties, additionalProperties interaction",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {"type": "array", "maxItems": 3},
|
||||
"bar": {"type": "array"}
|
||||
},
|
||||
"patternProperties": {"f.o": {"minItems": 2}},
|
||||
"additionalProperties": {"type": "integer"}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "property validates property",
|
||||
"data": {"foo": [1, 2]},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "property invalidates property",
|
||||
"data": {"foo": [1, 2, 3, 4]},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "patternProperty invalidates property",
|
||||
"data": {"foo": []},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "patternProperty validates nonproperty",
|
||||
"data": {"fxo": [1, 2]},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "patternProperty invalidates nonproperty",
|
||||
"data": {"fxo": []},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "additionalProperty ignores property",
|
||||
"data": {"bar": []},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "additionalProperty validates others",
|
||||
"data": {"quux": 3},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "additionalProperty invalidates others",
|
||||
"data": {"quux": "foo"},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
146
contrib/libucl/tests/schema/ref.json
Normal file
146
contrib/libucl/tests/schema/ref.json
Normal file
@ -0,0 +1,146 @@
|
||||
[
|
||||
{
|
||||
"description": "root pointer ref",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {"$ref": "#"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "match",
|
||||
"data": {"foo": false},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "recursive match",
|
||||
"data": {"foo": {"foo": false}},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch",
|
||||
"data": {"bar": false},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "recursive mismatch",
|
||||
"data": {"foo": {"bar": false}},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "relative pointer ref to object",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {"type": "integer"},
|
||||
"bar": {"$ref": "#/properties/foo"}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "match",
|
||||
"data": {"bar": 3},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch",
|
||||
"data": {"bar": true},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "relative pointer ref to array",
|
||||
"schema": {
|
||||
"items": [
|
||||
{"type": "integer"},
|
||||
{"$ref": "#/items/0"}
|
||||
]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "match array",
|
||||
"data": [1, 2],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "mismatch array",
|
||||
"data": [1, "foo"],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "escaped pointer ref",
|
||||
"schema": {
|
||||
"tilda~field": {"type": "integer"},
|
||||
"slash/field": {"type": "integer"},
|
||||
"percent%field": {"type": "integer"},
|
||||
"properties": {
|
||||
"tilda": {"$ref": "#/tilda~0field"},
|
||||
"slash": {"$ref": "#/slash~1field"},
|
||||
"percent": {"$ref": "#/percent%25field"}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "slash",
|
||||
"data": {"slash": "aoeu"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "tilda",
|
||||
"data": {"tilda": "aoeu"},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "percent",
|
||||
"data": {"percent": "aoeu"},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "nested refs",
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"a": {"type": "integer"},
|
||||
"b": {"$ref": "#/definitions/a"},
|
||||
"c": {"$ref": "#/definitions/b"}
|
||||
},
|
||||
"$ref": "#/definitions/c"
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "nested ref valid",
|
||||
"data": 5,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "nested ref invalid",
|
||||
"data": "a",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
/*
|
||||
{
|
||||
"description": "remote ref, containing refs itself",
|
||||
"schema": {"$ref": "http://json-schema.org/draft-04/schema#"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "remote ref valid",
|
||||
"data": {"minLength": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "remote ref invalid",
|
||||
"data": {"minLength": -1},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
]
|
74
contrib/libucl/tests/schema/refRemote.json
Normal file
74
contrib/libucl/tests/schema/refRemote.json
Normal file
@ -0,0 +1,74 @@
|
||||
[
|
||||
{
|
||||
"description": "remote ref",
|
||||
"schema": {"$ref": "http://localhost:1234/integer.json"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "remote ref valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "remote ref invalid",
|
||||
"data": "a",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "fragment within remote ref",
|
||||
"schema": {"$ref": "http://localhost:1234/subSchemas.json#/integer"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "remote fragment valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "remote fragment invalid",
|
||||
"data": "a",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "ref within remote ref",
|
||||
"schema": {
|
||||
"$ref": "http://localhost:1234/subSchemas.json#/refToInteger"
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "ref within ref valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "ref within ref invalid",
|
||||
"data": "a",
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "change resolution scope",
|
||||
"schema": {
|
||||
"id": "http://localhost:1234/",
|
||||
"items": {
|
||||
"id": "folder/",
|
||||
"items": {"$ref": "folderInteger.json"}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "changed scope ref valid",
|
||||
"data": [[1]],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "changed scope ref invalid",
|
||||
"data": [["a"]],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
39
contrib/libucl/tests/schema/required.json
Normal file
39
contrib/libucl/tests/schema/required.json
Normal file
@ -0,0 +1,39 @@
|
||||
[
|
||||
{
|
||||
"description": "required validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {},
|
||||
"bar": {}
|
||||
},
|
||||
"required": ["foo"]
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "present required property is valid",
|
||||
"data": {"foo": 1},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-present required property is invalid",
|
||||
"data": {"bar": 1},
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "required default validation",
|
||||
"schema": {
|
||||
"properties": {
|
||||
"foo": {}
|
||||
}
|
||||
},
|
||||
"tests": [
|
||||
{
|
||||
"description": "not required by default",
|
||||
"data": {},
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
330
contrib/libucl/tests/schema/type.json
Normal file
330
contrib/libucl/tests/schema/type.json
Normal file
@ -0,0 +1,330 @@
|
||||
[
|
||||
{
|
||||
"description": "integer type matches integers",
|
||||
"schema": {"type": "integer"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is an integer",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a float is not an integer",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is not an integer",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is not an integer",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not an integer",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not an integer",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is not an integer",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "number type matches numbers",
|
||||
"schema": {"type": "number"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is a number",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a float is a number",
|
||||
"data": 1.1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a string is not a number",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is not a number",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not a number",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not a number",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is not a number",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "string type matches strings",
|
||||
"schema": {"type": "string"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "1 is not a string",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a float is not a string",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is a string",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an object is not a string",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not a string",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not a string",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is not a string",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "object type matches objects",
|
||||
"schema": {"type": "object"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is not an object",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a float is not an object",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is not an object",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is an object",
|
||||
"data": {},
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "an array is not an object",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not an object",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is not an object",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "array type matches arrays",
|
||||
"schema": {"type": "array"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is not an array",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a float is not an array",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is not an array",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is not an array",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not an array",
|
||||
"data": [],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not an array",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is not an array",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "boolean type matches booleans",
|
||||
"schema": {"type": "boolean"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is not a boolean",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a float is not a boolean",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is not a boolean",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is not a boolean",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not a boolean",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not a boolean",
|
||||
"data": true,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "null is not a boolean",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "null type matches only the null object",
|
||||
"schema": {"type": "null"},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is not null",
|
||||
"data": 1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a float is not null",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a string is not null",
|
||||
"data": "foo",
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is not null",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is not null",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is not null",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is null",
|
||||
"data": null,
|
||||
"valid": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"description": "multiple types can be specified in an array",
|
||||
"schema": {"type": ["integer", "string"]},
|
||||
"tests": [
|
||||
{
|
||||
"description": "an integer is valid",
|
||||
"data": 1,
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a string is valid",
|
||||
"data": "foo",
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "a float is invalid",
|
||||
"data": 1.1,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an object is invalid",
|
||||
"data": {},
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "an array is invalid",
|
||||
"data": [],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "a boolean is invalid",
|
||||
"data": true,
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "null is invalid",
|
||||
"data": null,
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
79
contrib/libucl/tests/schema/uniqueItems.json
Normal file
79
contrib/libucl/tests/schema/uniqueItems.json
Normal file
@ -0,0 +1,79 @@
|
||||
[
|
||||
{
|
||||
"description": "uniqueItems validation",
|
||||
"schema": {"uniqueItems": true},
|
||||
"tests": [
|
||||
{
|
||||
"description": "unique array of integers is valid",
|
||||
"data": [1, 2],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-unique array of integers is invalid",
|
||||
"data": [1, 1],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "numbers are unique if mathematically unequal",
|
||||
"data": [1.0, 1.00, 1],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "unique array of objects is valid",
|
||||
"data": [{"foo": "bar"}, {"foo": "baz"}],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-unique array of objects is invalid",
|
||||
"data": [{"foo": "bar"}, {"foo": "bar"}],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "unique array of nested objects is valid",
|
||||
"data": [
|
||||
{"foo": {"bar" : {"baz" : true}}},
|
||||
{"foo": {"bar" : {"baz" : false}}}
|
||||
],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-unique array of nested objects is invalid",
|
||||
"data": [
|
||||
{"foo": {"bar" : {"baz" : true}}},
|
||||
{"foo": {"bar" : {"baz" : true}}}
|
||||
],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "unique array of arrays is valid",
|
||||
"data": [["foo"], ["bar"]],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-unique array of arrays is invalid",
|
||||
"data": [["foo"], ["foo"]],
|
||||
"valid": false
|
||||
},
|
||||
{
|
||||
"description": "1 and true are unique",
|
||||
"data": [1, true],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "0 and false are unique",
|
||||
"data": [0, false],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "unique heterogeneous types are valid",
|
||||
"data": [{}, [1], true, null, 1],
|
||||
"valid": true
|
||||
},
|
||||
{
|
||||
"description": "non-unique heterogeneous types are invalid",
|
||||
"data": [{}, [1], true, null, {}, 1],
|
||||
"valid": false
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
21
contrib/libucl/tests/speed.test
Executable file
21
contrib/libucl/tests/speed.test
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/sh
|
||||
|
||||
PROG=${TEST_BINARY_DIR}/test_speed
|
||||
|
||||
sh -c "xz -c < /dev/null > /dev/null"
|
||||
echo 'Running speed tests'
|
||||
for _tin in ${TEST_DIR}/*.xz ; do
|
||||
echo "Unpacking $_tin..."
|
||||
xz -cd < $_tin > ${TEST_OUT_DIR}/test_file
|
||||
# Preread file to cheat benchmark!
|
||||
cat ${TEST_OUT_DIR}/test_file > /dev/null
|
||||
echo "Starting benchmarking for $_tin..."
|
||||
$PROG ${TEST_OUT_DIR}/test_file
|
||||
if [ $? -ne 0 ] ; then
|
||||
echo "Test: $_tin failed"
|
||||
rm ${TEST_OUT_DIR}/test_file
|
||||
exit 1
|
||||
fi
|
||||
rm ${TEST_OUT_DIR}/test_file
|
||||
done
|
||||
|
@ -21,10 +21,8 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "ucl.h"
|
||||
#include "ucl_internal.h"
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
@ -80,7 +78,9 @@ main (int argc, char **argv)
|
||||
|
||||
while (!feof (in)) {
|
||||
memset (inbuf, 0, sizeof (inbuf));
|
||||
(void)fread (inbuf, sizeof (inbuf) - 1, 1, in);
|
||||
if (fread (inbuf, 1, sizeof (inbuf) - 1, in) == 0) {
|
||||
break;
|
||||
}
|
||||
inlen = strlen (inbuf);
|
||||
test_in = malloc (inlen);
|
||||
memcpy (test_in, inbuf, inlen);
|
||||
@ -97,7 +97,7 @@ main (int argc, char **argv)
|
||||
else {
|
||||
out = stdout;
|
||||
}
|
||||
if (ucl_parser_get_error(parser) != NULL) {
|
||||
if (ucl_parser_get_error (parser) != NULL) {
|
||||
fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser));
|
||||
ret = 1;
|
||||
goto end;
|
||||
@ -112,7 +112,7 @@ main (int argc, char **argv)
|
||||
ucl_parser_free (parser);
|
||||
ucl_object_unref (obj);
|
||||
parser2 = ucl_parser_new (UCL_PARSER_KEY_LOWERCASE);
|
||||
ucl_parser_add_chunk (parser2, emitted, strlen (emitted));
|
||||
ucl_parser_add_string (parser2, emitted, 0);
|
||||
|
||||
if (ucl_parser_get_error(parser2) != NULL) {
|
||||
fprintf (out, "Error occurred: %s\n", ucl_parser_get_error(parser2));
|
||||
|
@ -29,7 +29,8 @@
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
ucl_object_t *obj, *cur, *ar;
|
||||
ucl_object_t *obj, *cur, *ar, *ref;
|
||||
const ucl_object_t *found;
|
||||
FILE *out;
|
||||
unsigned char *emitted;
|
||||
const char *fname_out = NULL;
|
||||
@ -55,62 +56,81 @@ main (int argc, char **argv)
|
||||
obj = ucl_object_typed_new (UCL_OBJECT);
|
||||
/* Create some strings */
|
||||
cur = ucl_object_fromstring_common (" test string ", 0, UCL_STRING_TRIM);
|
||||
obj = ucl_object_insert_key (obj, cur, "key1", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key1", 0, false);
|
||||
cur = ucl_object_fromstring_common (" test \nstring\n ", 0, UCL_STRING_TRIM | UCL_STRING_ESCAPE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key2", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key2", 0, false);
|
||||
cur = ucl_object_fromstring_common (" test string \n", 0, 0);
|
||||
obj = ucl_object_insert_key (obj, cur, "key3", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key3", 0, false);
|
||||
/* Array of numbers */
|
||||
ar = ucl_object_typed_new (UCL_ARRAY);
|
||||
cur = ucl_object_fromint (10);
|
||||
ar = ucl_array_append (NULL, cur);
|
||||
ucl_array_append (ar, cur);
|
||||
cur = ucl_object_fromdouble (10.1);
|
||||
ar = ucl_array_append (ar, cur);
|
||||
ucl_array_append (ar, cur);
|
||||
cur = ucl_object_fromdouble (9.999);
|
||||
ar = ucl_array_prepend (ar, cur);
|
||||
ucl_array_prepend (ar, cur);
|
||||
|
||||
/* Removing from an array */
|
||||
cur = ucl_object_fromdouble (1.0);
|
||||
ar = ucl_array_append (ar, cur);
|
||||
ucl_array_append (ar, cur);
|
||||
cur = ucl_array_delete (ar, cur);
|
||||
assert (ucl_object_todouble (cur) == 1.0);
|
||||
ucl_object_unref (cur);
|
||||
cur = ucl_object_fromdouble (2.0);
|
||||
ar = ucl_array_append (ar, cur);
|
||||
ucl_array_append (ar, cur);
|
||||
cur = ucl_array_pop_last (ar);
|
||||
assert (ucl_object_todouble (cur) == 2.0);
|
||||
ucl_object_unref (cur);
|
||||
cur = ucl_object_fromdouble (3.0);
|
||||
ar = ucl_array_prepend (ar, cur);
|
||||
ucl_array_prepend (ar, cur);
|
||||
cur = ucl_array_pop_first (ar);
|
||||
assert (ucl_object_todouble (cur) == 3.0);
|
||||
ucl_object_unref (cur);
|
||||
|
||||
obj = ucl_object_insert_key (obj, ar, "key4", 0, false);
|
||||
ucl_object_insert_key (obj, ar, "key4", 0, false);
|
||||
cur = ucl_object_frombool (true);
|
||||
obj = ucl_object_insert_key (obj, cur, "key4", 0, false);
|
||||
/* Ref object to test refcounts */
|
||||
ref = ucl_object_ref (cur);
|
||||
ucl_object_insert_key (obj, cur, "key4", 0, false);
|
||||
/* Empty strings */
|
||||
cur = ucl_object_fromstring_common (" ", 0, UCL_STRING_TRIM);
|
||||
obj = ucl_object_insert_key (obj, cur, "key5", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key5", 0, false);
|
||||
cur = ucl_object_fromstring_common ("", 0, UCL_STRING_ESCAPE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key6", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key6", 0, false);
|
||||
cur = ucl_object_fromstring_common (" \n", 0, UCL_STRING_ESCAPE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key7", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key7", 0, false);
|
||||
/* Numbers and booleans */
|
||||
cur = ucl_object_fromstring_common ("1mb", 0, UCL_STRING_ESCAPE | UCL_STRING_PARSE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key8", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key8", 0, false);
|
||||
cur = ucl_object_fromstring_common ("3.14", 0, UCL_STRING_PARSE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key9", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key9", 0, false);
|
||||
cur = ucl_object_fromstring_common ("true", 0, UCL_STRING_PARSE);
|
||||
obj = ucl_object_insert_key (obj, cur, "key10", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key10", 0, false);
|
||||
cur = ucl_object_fromstring_common (" off ", 0, UCL_STRING_PARSE | UCL_STRING_TRIM);
|
||||
obj = ucl_object_insert_key (obj, cur, "key11", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key11", 0, false);
|
||||
cur = ucl_object_fromstring_common ("gslin@gslin.org", 0, UCL_STRING_PARSE_INT);
|
||||
obj = ucl_object_insert_key (obj, cur, "key12", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key12", 0, false);
|
||||
cur = ucl_object_fromstring_common ("#test", 0, UCL_STRING_PARSE_INT);
|
||||
obj = ucl_object_insert_key (obj, cur, "key13", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "key13", 0, false);
|
||||
cur = ucl_object_frombool (true);
|
||||
obj = ucl_object_insert_key (obj, cur, "k=3", 0, false);
|
||||
ucl_object_insert_key (obj, cur, "k=3", 0, false);
|
||||
|
||||
/* Try to find using path */
|
||||
/* Should exist */
|
||||
found = ucl_lookup_path (obj, "key4.1");
|
||||
assert (found != NULL && ucl_object_toint (found) == 10);
|
||||
/* . should be ignored */
|
||||
found = ucl_lookup_path (obj, ".key4.1");
|
||||
assert (found != NULL && ucl_object_toint (found) == 10);
|
||||
/* moar dots... */
|
||||
found = ucl_lookup_path (obj, ".key4........1...");
|
||||
assert (found != NULL && ucl_object_toint (found) == 10);
|
||||
/* No such index */
|
||||
found = ucl_lookup_path (obj, ".key4.3");
|
||||
assert (found == NULL);
|
||||
/* No such key */
|
||||
found = ucl_lookup_path (obj, "key9..key1");
|
||||
assert (found == NULL);
|
||||
|
||||
emitted = ucl_object_emit (obj, UCL_EMIT_CONFIG);
|
||||
|
||||
@ -122,5 +142,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
fclose (out);
|
||||
|
||||
/* Ref should still be accessible */
|
||||
ref->value.iv = 100500;
|
||||
ucl_object_unref (ref);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
158
contrib/libucl/tests/test_schema.c
Normal file
158
contrib/libucl/tests/test_schema.c
Normal file
@ -0,0 +1,158 @@
|
||||
/* Copyright (c) 2014, 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 ''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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include "ucl.h"
|
||||
|
||||
static int
|
||||
read_stdin (char **buf)
|
||||
{
|
||||
int size = BUFSIZ, remain, ret;
|
||||
char *p;
|
||||
|
||||
*buf = malloc (size);
|
||||
if (*buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = *buf;
|
||||
remain = size;
|
||||
|
||||
while ((ret = read (STDIN_FILENO, p, remain)) > 0) {
|
||||
remain -= ret;
|
||||
p += ret;
|
||||
if (remain == 0) {
|
||||
*buf = realloc (*buf, size * 2);
|
||||
if (*buf == NULL) {
|
||||
return -1;
|
||||
}
|
||||
p = *buf + size;
|
||||
remain = size;
|
||||
size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool
|
||||
perform_test (const ucl_object_t *schema, const ucl_object_t *obj,
|
||||
struct ucl_schema_error *err)
|
||||
{
|
||||
const const ucl_object_t *valid, *data, *description;
|
||||
bool match;
|
||||
|
||||
data = ucl_object_find_key (obj, "data");
|
||||
description = ucl_object_find_key (obj, "description");
|
||||
valid = ucl_object_find_key (obj, "valid");
|
||||
|
||||
if (data == NULL || description == NULL || valid == NULL) {
|
||||
fprintf (stdout, "Bad test case\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
match = ucl_object_validate (schema, data, err);
|
||||
if (match != ucl_object_toboolean (valid)) {
|
||||
fprintf (stdout, "Test case '%s' failed (expected %s): '%s'\n",
|
||||
ucl_object_tostring (description),
|
||||
ucl_object_toboolean (valid) ? "valid" : "invalid",
|
||||
err->msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int
|
||||
perform_tests (const ucl_object_t *obj)
|
||||
{
|
||||
struct ucl_schema_error err;
|
||||
ucl_object_iter_t iter = NULL;
|
||||
const ucl_object_t *schema, *tests, *description, *test;
|
||||
|
||||
if (obj->type != UCL_OBJECT) {
|
||||
fprintf (stdout, "Bad test case\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
schema = ucl_object_find_key (obj, "schema");
|
||||
tests = ucl_object_find_key (obj, "tests");
|
||||
description = ucl_object_find_key (obj, "description");
|
||||
|
||||
if (schema == NULL || tests == NULL || description == NULL) {
|
||||
fprintf (stdout, "Bad test case\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
memset (&err, 0, sizeof (err));
|
||||
|
||||
while ((test = ucl_iterate_object (tests, &iter, true)) != NULL) {
|
||||
if (!perform_test (schema, test, &err)) {
|
||||
fprintf (stdout, "Test suite '%s' failed\n",
|
||||
ucl_object_tostring (description));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
char *buf = NULL;
|
||||
struct ucl_parser *parser;
|
||||
ucl_object_t *obj = NULL;
|
||||
const ucl_object_t *elt;
|
||||
ucl_object_iter_t iter = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (read_stdin (&buf) == -1) {
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
parser = ucl_parser_new (0);
|
||||
|
||||
ucl_parser_add_string (parser, buf, 0);
|
||||
|
||||
if (ucl_parser_get_error (parser) != NULL) {
|
||||
fprintf (stdout, "Error occurred: %s\n", ucl_parser_get_error (parser));
|
||||
ret = 1;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
obj = ucl_parser_get_object (parser);
|
||||
ucl_parser_free (parser);
|
||||
|
||||
while ((elt = ucl_iterate_object (obj, &iter, true)) != NULL) {
|
||||
ret = perform_tests (elt);
|
||||
if (ret != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ucl_object_unref (obj);
|
||||
|
||||
return ret;
|
||||
}
|
@ -32,8 +32,10 @@
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#ifdef HAVE_MACH_MACH_TIME_H
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ucl.h"
|
||||
|
||||
|
19
contrib/libucl/utils/Makefile.am
Normal file
19
contrib/libucl/utils/Makefile.am
Normal file
@ -0,0 +1,19 @@
|
||||
common_utils_cflags = -I$(top_srcdir)/include \
|
||||
-I$(top_srcdir)/src \
|
||||
-I$(top_srcdir)/uthash
|
||||
common_utils_ldadd = $(top_builddir)/src/libucl.la
|
||||
|
||||
ucl_chargen_SOURCES = chargen.c
|
||||
ucl_chargen_LDADD = $(common_utils_ldadd)
|
||||
ucl_chargen_CFLAGS = $(common_utils_cflags)
|
||||
|
||||
ucl_objdump_SOURCES = objdump.c
|
||||
ucl_objdump_LDADD = $(common_utils_ldadd)
|
||||
ucl_objdump_CFLAGS = $(common_utils_cflags)
|
||||
|
||||
if UTILS
|
||||
UTL = ucl_chargen ucl_objdump
|
||||
else
|
||||
UTL =
|
||||
endif
|
||||
bin_PROGRAMS = $(UTL)
|
@ -28,11 +28,11 @@
|
||||
#include "ucl.h"
|
||||
|
||||
void
|
||||
ucl_obj_dump(ucl_object_t *obj, unsigned int shift)
|
||||
ucl_obj_dump (const ucl_object_t *obj, unsigned int shift)
|
||||
{
|
||||
int num = shift * 4 + 5;
|
||||
char *pre = (char *) malloc (num * sizeof(char));
|
||||
ucl_object_t *cur, *tmp;
|
||||
const ucl_object_t *cur, *tmp;
|
||||
ucl_object_iter_t it = NULL, it_obj = NULL;
|
||||
|
||||
pre[--num] = 0x00;
|
||||
@ -64,7 +64,7 @@ ucl_obj_dump(ucl_object_t *obj, unsigned int shift)
|
||||
}
|
||||
else if (obj->type == UCL_INT) {
|
||||
printf ("%stype: UCL_INT\n", pre);
|
||||
printf ("%svalue: %ld\n", pre, ucl_object_toint (obj));
|
||||
printf ("%svalue: %jd\n", pre, (intmax_t)ucl_object_toint (obj));
|
||||
}
|
||||
else if (obj->type == UCL_FLOAT) {
|
||||
printf ("%stype: UCL_FLOAT\n", pre);
|
||||
@ -99,7 +99,7 @@ main(int argc, char **argv)
|
||||
struct ucl_parser *parser;
|
||||
int k, ret = 0, r = 0;
|
||||
ucl_object_t *obj = NULL;
|
||||
ucl_object_t *par;
|
||||
const ucl_object_t *par;
|
||||
FILE *in;
|
||||
|
||||
if (argc > 1) {
|
||||
@ -129,7 +129,7 @@ main(int argc, char **argv)
|
||||
}
|
||||
|
||||
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));
|
||||
ret = 1;
|
||||
goto end;
|
||||
|
@ -8,6 +8,7 @@ SHLIB_MAJOR= 1
|
||||
SRCS= ucl_emitter.c \
|
||||
ucl_hash.c \
|
||||
ucl_parser.c \
|
||||
ucl_schema.c \
|
||||
ucl_util.c \
|
||||
xxhash.c
|
||||
|
||||
|
@ -517,10 +517,10 @@ boolstr_to_bool(const char *str)
|
||||
}
|
||||
|
||||
static void
|
||||
config_parse(ucl_object_t *obj, pkg_conf_file_t conftype)
|
||||
config_parse(const ucl_object_t *obj, pkg_conf_file_t conftype)
|
||||
{
|
||||
struct sbuf *buf = sbuf_new_auto();
|
||||
ucl_object_t *cur, *seq;
|
||||
const ucl_object_t *cur, *seq;
|
||||
ucl_object_iter_t it = NULL, itseq = NULL;
|
||||
struct config_entry *temp_config;
|
||||
struct config_value *cv;
|
||||
@ -638,7 +638,7 @@ static void
|
||||
parse_repo_file(ucl_object_t *obj)
|
||||
{
|
||||
ucl_object_iter_t it = NULL;
|
||||
ucl_object_t *cur;
|
||||
const ucl_object_t *cur;
|
||||
const char *key;
|
||||
|
||||
while ((cur = ucl_iterate_object(obj, &it, true))) {
|
||||
@ -683,7 +683,7 @@ read_conf_file(const char *confpath, pkg_conf_file_t conftype)
|
||||
parse_repo_file(obj);
|
||||
}
|
||||
|
||||
ucl_object_free(obj);
|
||||
ucl_object_unref(obj);
|
||||
ucl_parser_free(p);
|
||||
|
||||
return (0);
|
||||
|
@ -273,7 +273,7 @@ cleanup:
|
||||
static struct fingerprint *
|
||||
parse_fingerprint(ucl_object_t *obj)
|
||||
{
|
||||
ucl_object_t *cur;
|
||||
const ucl_object_t *cur;
|
||||
ucl_object_iter_t it = NULL;
|
||||
const char *function, *fp, *key;
|
||||
struct fingerprint *f;
|
||||
@ -353,7 +353,7 @@ load_fingerprint(const char *dir, const char *filename)
|
||||
if (f != NULL)
|
||||
f->name = strdup(filename);
|
||||
|
||||
ucl_object_free(obj);
|
||||
ucl_object_unref(obj);
|
||||
ucl_parser_free(p);
|
||||
|
||||
return (f);
|
||||
|
Loading…
x
Reference in New Issue
Block a user