diff options
| -rw-r--r-- | .github/workflows/cmake-multi-platform.yml | 75 | ||||
| -rw-r--r-- | .github/workflows/makefile.yml | 30 | ||||
| -rw-r--r-- | .gitignore | 35 | ||||
| -rw-r--r-- | CMakeLists.txt | 27 | ||||
| -rw-r--r-- | ChangeLog.md | 140 | ||||
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | Makefile.unix | 4 | ||||
| -rw-r--r-- | README.md | 23 | ||||
| -rw-r--r-- | configure.ac | 6 | ||||
| -rw-r--r-- | include/ucl.h | 4 | ||||
| -rw-r--r-- | libucl.pc | 11 | ||||
| -rw-r--r-- | lua/lua_ucl.c | 83 | ||||
| -rw-r--r-- | m4/.gitignore | 4 | ||||
| -rw-r--r-- | python/setup.py | 4 | ||||
| -rw-r--r-- | src/ucl_emitter.c | 80 | ||||
| -rw-r--r-- | src/ucl_emitter_streamline.c | 9 | ||||
| -rw-r--r-- | src/ucl_hash.c | 146 | ||||
| -rw-r--r-- | src/ucl_parser.c | 214 | ||||
| -rw-r--r-- | src/ucl_schema.c | 1 | ||||
| -rw-r--r-- | src/ucl_util.c | 87 | ||||
| -rw-r--r-- | tests/schema/definitions.json | 32 | ||||
| -rw-r--r-- | tests/schema/ref.json | 16 | ||||
| -rw-r--r-- | tests/schema/refRemote.json | 76 | ||||
| -rw-r--r-- | tests/test_speed.c | 2 | ||||
| -rw-r--r-- | tests/test_streamline.c | 43 | ||||
| -rw-r--r-- | uthash/utlist.h | 749 | 
26 files changed, 1301 insertions, 602 deletions
| diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml new file mode 100644 index 000000000000..9ec0432eeb03 --- /dev/null +++ b/.github/workflows/cmake-multi-platform.yml @@ -0,0 +1,75 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: CMake on multiple platforms + +on: +  push: +    branches: [ "master" ] +  pull_request: +    branches: [ "master" ] + +jobs: +  build: +    runs-on: ${{ matrix.os }} + +    strategy: +      # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. +      fail-fast: false + +      # Set up a matrix to run the following 3 configurations: +      # 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator> +      # 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator> +      # 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator> +      # +      # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. +      matrix: +        os: [ubuntu-latest, windows-latest] +        build_type: [Release] +        c_compiler: [gcc, clang, cl] +        include: +          - os: windows-latest +            c_compiler: cl +            cpp_compiler: cl +          - os: ubuntu-latest +            c_compiler: gcc +            cpp_compiler: g++ +          - os: ubuntu-latest +            c_compiler: clang +            cpp_compiler: clang++ +        exclude: +          - os: windows-latest +            c_compiler: gcc +          - os: windows-latest +            c_compiler: clang +          - os: ubuntu-latest +            c_compiler: cl + +    steps: +    - uses: actions/checkout@v3 + +    - name: Set reusable strings +      # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. +      id: strings +      shell: bash +      run: | +        echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + +    - name: Configure CMake +      # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. +      # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type +      run: > +        cmake -B ${{ steps.strings.outputs.build-output-dir }} +        -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} +        -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} +        -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} +        -S ${{ github.workspace }} + +    - name: Build +      # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). +      run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + +    - name: Test +      working-directory: ${{ steps.strings.outputs.build-output-dir }} +      # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). +      # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail +      run: ctest --build-config ${{ matrix.build_type }} diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml new file mode 100644 index 000000000000..ddb16b7880b2 --- /dev/null +++ b/.github/workflows/makefile.yml @@ -0,0 +1,30 @@ +name: Makefile CI + +on: +  push: +    branches: [ "master" ] +  pull_request: +    branches: [ "master" ] + +jobs: +  build: + +    runs-on: ubuntu-latest + +    steps: +    - name: Install Lua +      run: sudo apt-get install -y liblua5.4-dev lua5.4 + +    - uses: actions/checkout@v3 + +    - name: configure +      run: ./autogen.sh && ./configure --enable-lua + +    - name: Install dependencies +      run: make + +    - name: Run check +      run: make check + +    - name: Run distcheck +      run: make distcheck diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000000..3887386865cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +.cproject +.project +.settings + +# Auto*/libtool +Makefile +Makefile.in +/aclocal.m4 +/autom4te.cache/ +/config.* +/configure +/depcomp +/install-sh +/libtool +/ltmain.sh +/missing +/stamp-h* +/ar-lib +/test-driver +/compile +.deps/ +.dirstamp +.libs/ +*.l[ao] +*~ +*.o + +# pkgconf +libucl.pc + +# python extension +python/build + +# Default CMake build directory +/build/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 5fe772a30f88..3d73910c887a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 3.1.0 FATAL_ERROR)  PROJECT(libucl C) -CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)  SET(LIBUCL_VERSION_MAJOR 0) -SET(LIBUCL_VERSION_MINOR 5) -SET(LIBUCL_VERSION_PATCH 0) +SET(LIBUCL_VERSION_MINOR 9) +SET(LIBUCL_VERSION_PATCH 2)  SET(LIBUCL_VERSION          "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}") @@ -237,12 +237,13 @@ ADD_LIBRARY(ucl ${LIB_TYPE} ${UCLSRC})  ADD_LIBRARY(ucl::ucl ALIAS ucl)  SET_TARGET_PROPERTIES(ucl PROPERTIES VERSION ${LIBUCL_VERSION} SOVERSION ${LIBUCL_VERSION_MAJOR})  TARGET_INCLUDE_DIRECTORIES(ucl -	PUBLIC -	  include -	PRIVATE -	  src -	  uthash -	  klib) +        PUBLIC +          $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> +          $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}> +        PRIVATE +          ${CMAKE_CURRENT_SOURCE_DIR}/src +          ${CMAKE_CURRENT_SOURCE_DIR}/uthash +          ${CMAKE_CURRENT_SOURCE_DIR}/klib)  TARGET_COMPILE_DEFINITIONS(ucl      PRIVATE      ${UCL_COMPILE_DEFS} @@ -305,10 +306,16 @@ ENDIF(UNIX)  SET_TARGET_PROPERTIES(ucl PROPERTIES  	PUBLIC_HEADER "${UCLHDR}") -INSTALL(TARGETS ucl DESTINATION ${CMAKE_INSTALL_LIBDIR} +INSTALL(TARGETS ucl EXPORT uclConfig DESTINATION ${CMAKE_INSTALL_LIBDIR}  		PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})  IF(ENABLE_UTILS MATCHES "ON")      ADD_SUBDIRECTORY(utils)  ENDIF() +install(EXPORT uclConfig +	FILE ucl-config.cmake +	NAMESPACE ucl:: +	DESTINATION "share/ucl" +) + diff --git a/ChangeLog.md b/ChangeLog.md index cba29aa9a7b5..b32b9e08d019 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,21 @@  # Version history +## Libucl 0.9.0 + +* 803b588 Breaking: Try to fix streamline embedding +* 9eddef0 Fix: set p to endptr before checking +* 25d3f51 Fix broken tests +* ac644e2 Update makefile.yml +* 0a5739e Create makefile.yml +* 987389a Merge branch 'master' into vstakhov-gh-actions +* 7433904 Import lua code from Rspamd +* 3912614 Create cmake-multi-platform.yml +* 3a04c92 lua: Push string with len +* 2fefed6 Use `_WIN32` instead of `_MSC_VER` +* aecf17e Avoid build failure trying to create setup.py link if it already exists. +* 4ef9e6d Add inttypes.h for PRId64 +* dcb43f0 Fix excessive escaping when using ucl_object_fromstring() +  ## Libucl 0.5  - Streamline emitter has been added, so it is now possible to output partial `ucl` objects @@ -100,4 +116,126 @@  - Performance improvements in Lua API  - Allow to pass opaque objects in Lua API for transparent C passthrough  - Various bugs fixed -- Couple of memory leaks plugged
\ No newline at end of file +- Couple of memory leaks plugged + +### Libucl 0.8.2 + +* .include: also validate priority to be within range +* Add -W into list of warnings +* Add ability to add file preprocessors +* Add ability to pass both the parser and userdata into a macro handler +* Add missing tests for .gitignore +* Add more safe guards when trying to insert objects +* Add some documentation/example about the .priority macro +* Add tests for single quotes +* Added CMake compile definitions +* Added CMake support to build utils +* Added a fuzzer for OSS-fuzz integration +* Added a return statement if the string is 0 +* Added default CMake "build" directory to gitignore +* Added fuzzer for msgpack +* Adding another fix +* Adjust example. +* Allow to test msgpack inputs +* Another sync +* Assume gcov absense as a non-fatal error +* Avoid read when a chunk is ended +* CMake: Install headers and library. +* Check for NULL inputs in ucl_object_compare() +* Cleanup CURL handle after use +* Cleanup CURL handle after use +* Convert ucl_hash_insert() from returning int to returning bool. +* Convert ucl_hash_reserve() from returning int to bool. +* Do not try to emit single quoted strings in json mode +* Document single quotes +* Document ucl_object_iter_chk_excpn(). +* Document usage of ucl_object_iter_chk_excpn(). +* Don't double-escape Lua strings +* Excercise ucl_object_iter_chk_excpn(). +* Fix '\v' encoding +* Fix 68d87c362b0d7fbb45f395bfae616a28439e0bbc by setting error to 0 always. Which makes it even uglier. +* Fix cmake public include install +* Fix emitting of the bad unicode escapes +* Fix format strings, add printf attribute to schema functions +* Fix levels and objects closing +* Fix load macro with try=true +* Fix mismerge. +* Fix mismerge. +* Fix old issue with parsing numbers +* Fix processing of the incomplete msgpack objects +* Fix remain calculations +* Fix remain lenght calculation that led to assertion failure +* Fix single quotes emitting +* Fix spelling and markup errors. +* Fix typos: replace missmatch with mismatch +* Fix ucl++ bug where iterators stop on a null field. +* Fix ucl_util.c not having the prototype for ucl_hash_sort() +* Fix variables expansion +* Fix vertical tab handling +* Fixed Visual Studio compilation error +* Fixed expanding variables at runtime +* Fixed linker error +* Fixed ucl_tool's command line argument parsing +* Fixing error with installing using pip from git with following command: 'pip install -e git+https://github.com/vstakhov/libucl.git/#egg=ucl +* Forgot hash sort function +* Improve ENOMEM handling: handle most of errors while consuructing parser, also extend iterator routines to allow capturing such exception and checking it in the higher level code using new ucl_object_iter_chk_excpn() API. +* Mark + as unsafe which fixes export a key with + in config mode +* Modernise the CMake build system slightly. +* Modernize CMake file with target-based includes. +* Pass correct pointer to var_handler +* Port util objdump to Windows (Visual Studio) +* Port util ucl-tool to Windows +* Provide inline free(3) wrapper, so it's easier to plug the code into out memory usage tracking framework. +* Provide inline free(3) wrapper, so it's easier to plug the code into out memory usage tracking framework. +* Provide priority validation for the .priority macro +* Put space between "exit" and (). +* Put space between name of teh function and (). +* Python build fixes +* Read data in chunks +* Remove leak in the test +* Remove one more bit of unused logic +* Remove one more stupid assertion +* Remove unnecessary (and ignored) `const` from return types. +* Remove unnecessary std::move from return statement. +* Remove unused CMake logic and ad -Wno-pointer-sign. +* Removed dependency from rspamd CMake file +* Removed null-terminator for input data +* Rename ENOMEM-safe version of kv_xxx macros from kv_xxx into kv_xxx_safe and put back old version as well (with a big warning in the header file) for a compat purposes. +* Renamed util binaries to match autotools +* Replace *neat* and *tidy* implementation of kv_xxx() macros using error handling labels with a much *uglier* implementation using "error code pointer". One man's "ugly" is other man's "pretty", I suppose. +* Replaced spaces by tabs to match coding style +* Rework hash table structure to provide pointers and order safety +* Save chunk in the parser stack +* Save filename in chunk +* Split level and flags, add obrace flag, fix msgpack flags +* Squelch incompatible pointer type warning +* Support single quoted strings +* Suppress the [-Wunused-parameter] warning. +* Sync changes from Rspamd +* Sync changes from rspamd +* Sync with Rspamd +* Understand nan and inf +* Use safe iterator - avoid leaking memory. +* docs: fix simple typo, tectual -> textual +* fix: Changed OpenSSL check inside configure.am +* fix: Incorrect pointer arithmetics in ucl_expand_single_variable +* fix: ucl_expand_single_variable doesn't call free +* lua: Return early when init fails +* make use of the undocumented flag UCL_PARSER_NO_IMPLICIT_ARRAYS, so that multiple keys are treated as arrays, and special code doesn't have to be added to the Python module to handle it. +* mypy/stubgen: add typeinterfaces for ucl python module +* o `ucl_object_iterate2()` -> `ucl_object_iterate_with_error()`; +* python: update package to 0.8.1 +* `ucl_check_variable`: fix out_len on unterminated variable +* `ucl_chunk_skipc`: avoid out-of-bounds read +* `ucl_expand_single_variable`: better bounds check +* `ucl_expand_variable`: fix out-of-bounds read +* `ucl_inherit_handler`: fix format string for non-null-terminated strings +* `ucl_lc_cmp` is not used outside ucl_hash.c +* `ucl_lex_json_string`: fix out-of-bounds read +* `ucl_maybe_parse_number`: if there is trailing content, it is not a number +* `ucl_object_copy_internal`: null terminate keys +* `ucl_object_copy_internal`: use memcpy instead of strdup +* `ucl_object_free` is deprecated +* `ucl_parse_value`: fix out-of-bounds read +* `ucl_strnstr`: fix out-of-bounds read +* update JSON example to match w/ UCL example diff --git a/Makefile.am b/Makefile.am index 5b51bcc3b468..090542d14e8b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -69,7 +69,7 @@ clean-coverage-report:  	-rm -rf $(COVERAGE_REPORT_DIR)  clean-coverage: clean-coverage-report -	-$(LCOV) --gcov-tool $(GCOV) --zerocounters --directory $(top_builddir) +	-$(LCOV) --gcov-tool $(GCOV) --zerocounters --directory $(top_builddir) || true  	@if xargs --version 2>/dev/null; then \  		find $(top_builddir) -name "*.gcno" | xargs --no-run-if-empty rm; \  	else \ diff --git a/Makefile.unix b/Makefile.unix index 0653d4843f7e..dbb8f4cb5a90 100644 --- a/Makefile.unix +++ b/Makefile.unix @@ -3,8 +3,8 @@ DESTDIR ?= /usr/local  LD ?= gcc  C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src -I./klib  MAJOR_VERSION = 0 -MINOR_VERSION = 2 -PATCH_VERSION = 9 +MINOR_VERSION = 9 +PATCH_VERSION = 2  VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)"  SONAME = libucl.so  SONAME_FULL = $(SONAME).$(MAJOR_VERSION) diff --git a/README.md b/README.md index 53d8a651d73b..321db170db88 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,4 @@ -# LIBUCL - -[](https://circleci.com/gh/vstakhov/libucl) -[](https://scan.coverity.com/projects/4138) -[](https://coveralls.io/github/vstakhov/libucl?branch=master) +# UCL - Universal Configuration Language  **Table of Contents**  *generated with [DocToc](http://doctoc.herokuapp.com/)* @@ -26,15 +22,19 @@  ## Introduction -This document describes the main features and principles of the configuration -language called `UCL` - universal configuration language. +This repository provides the `C` library for parsing configurations written in `UCL` - universal configuration language. It also provides functions to operate with other formats: + +* `JSON`: read, write and pretty format +* `Messagepack`: read and write +* `S-Expressions`: read only (canonical form) +* `Yaml`: limited write support (mainly for compatibility)  If you are looking for the libucl API documentation you can find it at [this page](doc/api.md).  ## Basic structure -UCL is heavily infused by `nginx` configuration as the example of a convenient configuration -system. However, UCL is fully compatible with `JSON` format and is able to parse json files. +`UCL` is heavily infused by `nginx` configuration as the example of a convenient configuration +system. However, `UCL` is fully compatible with `JSON` format and is able to parse json files.  For example, you can write the same configuration in the following ways:  * in nginx like: @@ -234,7 +234,7 @@ UCL supports external macros both multiline and single line ones:  ```  Moreover, each macro can accept an optional list of arguments in braces. These -arguments themselves are the UCL object that is parsed and passed to a macro as +arguments themselves are the `UCL` object that is parsed and passed to a macro as  options:  ```nginx @@ -374,7 +374,8 @@ Each UCL object can be serialized to one of the four supported formats:  * `JSON` - canonic json notation (with spaces indented structure);  * `Compacted JSON` - compact json notation (without spaces or newlines);  * `Configuration` - nginx like notation; -* `YAML` - yaml inlined notation. +* `YAML` - yaml inlined notation; +* `messagepack` - MessagePack binary format.  ## Validation diff --git a/configure.ac b/configure.ac index 731b7113e689..2e8cbabded3b 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@  m4_define([maj_ver], [0]) -m4_define([med_ver], [8]) -m4_define([min_ver], [1]) -m4_define([so_version], [6:0:1]) +m4_define([med_ver], [9]) +m4_define([min_ver], [2]) +m4_define([so_version], [9:0:2])  m4_define([ucl_version], [maj_ver.med_ver.min_ver])  AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl]) diff --git a/include/ucl.h b/include/ucl.h index 39da2593648d..b8625b9fce2f 100644 --- a/include/ucl.h +++ b/include/ucl.h @@ -1411,13 +1411,13 @@ struct ucl_emitter_operations {  		const ucl_object_t *obj, bool first, bool print_key);  	/** Start ucl object */  	void (*ucl_emitter_start_object) (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key); +		const ucl_object_t *obj, bool first, bool print_key);  	/** End ucl object */  	void (*ucl_emitter_end_object) (struct ucl_emitter_context *ctx,  		const ucl_object_t *obj);  	/** Start ucl array */  	void (*ucl_emitter_start_array) (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key); +		const ucl_object_t *obj, bool first, bool print_key);  	void (*ucl_emitter_end_array) (struct ucl_emitter_context *ctx,  		const ucl_object_t *obj);  }; diff --git a/libucl.pc b/libucl.pc deleted file mode 100644 index 4878bebafcdd..000000000000 --- a/libucl.pc +++ /dev/null @@ -1,11 +0,0 @@ -prefix=/usr/local -exec_prefix=${prefix} -libdir=${exec_prefix}/lib -includedir=${prefix}/include - -Name: LibUCL -Description: Universal configuration library -Version: 0.9.0 -Libs: -L${libdir} -lucl -Libs.private:   -Cflags: -I${includedir}/ diff --git a/lua/lua_ucl.c b/lua/lua_ucl.c index b34fd56878b8..d6be69e42a71 100644 --- a/lua/lua_ucl.c +++ b/lua/lua_ucl.c @@ -82,6 +82,11 @@ static ucl_object_t* ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_f  static void *ucl_null; +struct _rspamd_lua_text { +	const char *start; +	unsigned int len; +	unsigned int flags; +};  enum lua_ucl_push_flags {  	LUA_UCL_DEFAULT_FLAGS = 0, @@ -240,7 +245,7 @@ ucl_object_lua_push_scalar (lua_State *L, const ucl_object_t *obj,  		lua_pushboolean (L, ucl_obj_toboolean (obj));  		break;  	case UCL_STRING: -		lua_pushstring (L, ucl_obj_tostring (obj)); +		lua_pushlstring (L, ucl_obj_tostring (obj), obj->len);  		break;  	case UCL_INT:  #if LUA_VERSION_NUM >= 501 @@ -401,7 +406,6 @@ ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)  	/* Table iterate */  	if (is_array) { -		int i;  		if (!is_implicit) {  			top = ucl_object_typed_new (UCL_ARRAY); @@ -411,7 +415,7 @@ ucl_object_lua_fromtable (lua_State *L, int idx, ucl_string_flags_t flags)  			top = NULL;  		} -		for (i = 1; i <= max; i ++) { +		for (size_t i = 1; i <= max; i ++) {  			lua_pushinteger (L, i);  			lua_gettable (L, idx); @@ -479,7 +483,16 @@ ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)  		str = lua_tolstring (L, idx, &sz);  		if (str) { -			obj = ucl_object_fromstring_common (str, sz, flags); +			/* +			 * ucl_object_fromstring_common has a `logic` to use strlen if sz is zero +			 * which is totally broken... +			 */ +			if (sz > 0) { +				obj = ucl_object_fromstring_common(str, sz, flags); +			} +			else { +				obj = ucl_object_fromstring_common("", sz, flags); +			}  		}  		else {  			obj = ucl_object_typed_new (UCL_NULL); @@ -501,6 +514,24 @@ ucl_object_lua_fromelt (lua_State *L, int idx, ucl_string_flags_t flags)  		if (lua_topointer (L, idx) == ucl_null) {  			obj = ucl_object_typed_new (UCL_NULL);  		} +		else { +			/* Assume it is a text like object */ +			struct _rspamd_lua_text *t = lua_touserdata (L, idx); + +			if (t) { +				if (t->len >0) { +					obj = ucl_object_fromstring_common(t->start, t->len, 0); +				} +				else { +					obj = ucl_object_fromstring_common("", 0, 0); +				} + +				/* Binary text */ +				if (t->flags & (1u << 5u)) { +					obj->flags |= UCL_OBJECT_BINARY; +				} +			} +		}  		break;  	case LUA_TTABLE:  	case LUA_TFUNCTION: @@ -556,10 +587,10 @@ ucl_object_lua_import (lua_State *L, int idx)  	t = lua_type (L, idx);  	switch (t) {  	case LUA_TTABLE: -		obj = ucl_object_lua_fromtable (L, idx, 0); +		obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW);  		break;  	default: -		obj = ucl_object_lua_fromelt (L, idx, 0); +		obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW);  		break;  	} @@ -584,10 +615,10 @@ ucl_object_lua_import_escape (lua_State *L, int idx)  	t = lua_type (L, idx);  	switch (t) {  	case LUA_TTABLE: -		obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_RAW); +		obj = ucl_object_lua_fromtable (L, idx, UCL_STRING_ESCAPE);  		break;  	default: -		obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_RAW); +		obj = ucl_object_lua_fromelt (L, idx, UCL_STRING_ESCAPE);  		break;  	} @@ -598,11 +629,12 @@ static int  lua_ucl_to_string (lua_State *L, const ucl_object_t *obj, enum ucl_emitter type)  {  	unsigned char *result; +	size_t outlen; -	result = ucl_object_emit (obj, type); +	result = ucl_object_emit_len (obj, type, &outlen);  	if (result != NULL) { -		lua_pushstring (L, (const char *)result); +		lua_pushlstring (L, (const char *)result, outlen);  		free (result);  	}  	else { @@ -625,7 +657,6 @@ lua_ucl_parser_init (lua_State *L)  	parser = ucl_parser_new (flags);  	if (parser == NULL) {  		lua_pushnil (L); -		return 1;  	}  	pparser = lua_newuserdata (L, sizeof (parser)); @@ -834,12 +865,6 @@ lua_ucl_parser_parse_string (lua_State *L)  	return ret;  } -struct _rspamd_lua_text { -	const char *start; -	unsigned int len; -	unsigned int flags; -}; -  /***   * @method parser:parse_text(input)   * Parse UCL object from text object (Rspamd specific). @@ -855,7 +880,24 @@ lua_ucl_parser_parse_text (lua_State *L)  	int ret = 2;  	parser = lua_ucl_parser_get (L, 1); -	t = lua_touserdata (L, 2); + +	if (lua_type (L, 2) == LUA_TUSERDATA) { +		t = lua_touserdata (L, 2); +	} +	else if (lua_type (L, 2) == LUA_TSTRING) { +		const char *s; +		size_t len; +		static struct _rspamd_lua_text st_t; + +		s = lua_tolstring (L, 2, &len); +		st_t.start = s; +		st_t.len = len; + +		t = &st_t; +	} +	else { +		return luaL_error(L, "invalid argument as input, expected userdata or a string"); +	}  	if (lua_type (L, 3) == LUA_TSTRING) {  		type = lua_ucl_str_to_parse_type (lua_tostring (L, 3)); @@ -1426,10 +1468,11 @@ lua_ucl_to_format (lua_State *L)  				format = UCL_EMIT_YAML;  			}  			else if (strcasecmp (strtype, "config") == 0 || -				strcasecmp (strtype, "ucl") == 0) { +					 strcasecmp (strtype, "ucl") == 0) {  				format = UCL_EMIT_CONFIG;  			} -			else if (strcasecmp (strtype, "msgpack") == 0) { +			else if (strcasecmp (strtype, "msgpack") == 0 || +					 strcasecmp (strtype, "messagepack") == 0) {  				format = UCL_EMIT_MSGPACK;  			}  		} diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 000000000000..5e7d2734cfc6 --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/python/setup.py b/python/setup.py index 8da832bac381..c30395d97b5a 100644 --- a/python/setup.py +++ b/python/setup.py @@ -41,12 +41,12 @@ template = 'python/MANIFEST.in'  # distutils assume setup.py is in the root of the project  # we need to include C source from the parent so trick it  in_ucl_root = 'setup.py' in os.listdir('python') -if in_ucl_root: +if not os.path.isfile('setup.py') and in_ucl_root:      os.link('python/setup.py', 'setup.py')  setup(      name = 'ucl', -    version = '0.8.1', +    version = '0.8.2',      description = 'ucl parser and emitter',      ext_modules = [uclmodule],      template=template, # no longer supported with setuptools but doesn't hurt diff --git a/src/ucl_emitter.c b/src/ucl_emitter.c index 4f4465dfbf4a..97d8f618021f 100644 --- a/src/ucl_emitter.c +++ b/src/ucl_emitter.c @@ -47,9 +47,9 @@ static void ucl_emitter_common_elt (struct ucl_emitter_context *ctx,  	static void ucl_emit_ ## type ## _elt (struct ucl_emitter_context *ctx,	\  		const ucl_object_t *obj, bool first, bool print_key);	\  	static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx,	\ -		const ucl_object_t *obj, bool print_key);	\ +		const ucl_object_t *obj, bool first, bool print_key);	\  	static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx,	\ -		const ucl_object_t *obj, bool print_key);	\ +		const ucl_object_t *obj, bool first, bool print_key);	\  	static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx,	\  		const ucl_object_t *obj);	\  	static void ucl_emit_ ##type## _end_array (struct ucl_emitter_context *ctx,	\ @@ -248,12 +248,26 @@ ucl_emitter_common_end_array (struct ucl_emitter_context *ctx,   */  static void  ucl_emitter_common_start_array (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key, bool compact) +		const ucl_object_t *obj, bool first, bool print_key, bool compact)  {  	const ucl_object_t *cur;  	ucl_object_iter_t iter = NULL;  	const struct ucl_emitter_functions *func = ctx->func; -	bool first = true; +	bool first_key = true; + +	if (ctx->id != UCL_EMIT_CONFIG && !first) { +		if (compact) { +			func->ucl_emitter_append_character (',', 1, func->ud); +		} +		else { +			if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { +				func->ucl_emitter_append_len ("\n", 1, func->ud); +			} else { +				func->ucl_emitter_append_len (",\n", 2, func->ud); +			} +		} +		ucl_add_tabs (func, ctx->indent, compact); +	}  	ucl_emitter_print_key (print_key, ctx, obj, compact); @@ -269,16 +283,16 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,  	if (obj->type == UCL_ARRAY) {  		/* explicit array */  		while ((cur = ucl_object_iterate (obj, &iter, true)) != NULL) { -			ucl_emitter_common_elt (ctx, cur, first, false, compact); -			first = false; +			ucl_emitter_common_elt (ctx, cur, first_key, false, compact); +			first_key = false;  		}  	}  	else {  		/* implicit array */  		cur = obj;  		while (cur) { -			ucl_emitter_common_elt (ctx, cur, first, false, compact); -			first = false; +			ucl_emitter_common_elt (ctx, cur, first_key, false, compact); +			first_key = false;  			cur = cur->next;  		}  	} @@ -294,12 +308,26 @@ ucl_emitter_common_start_array (struct ucl_emitter_context *ctx,   */  static void  ucl_emitter_common_start_object (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key, bool compact) +		const ucl_object_t *obj, bool first, bool print_key, bool compact)  {  	ucl_hash_iter_t it = NULL;  	const ucl_object_t *cur, *elt;  	const struct ucl_emitter_functions *func = ctx->func; -	bool first = true; +	bool first_key = true; + +	if (ctx->id != UCL_EMIT_CONFIG && !first) { +		if (compact) { +			func->ucl_emitter_append_character (',', 1, func->ud); +		} +		else { +			if (ctx->id == UCL_EMIT_YAML && ctx->indent == 0) { +				func->ucl_emitter_append_len ("\n", 1, func->ud); +			} else { +				func->ucl_emitter_append_len (",\n", 2, func->ud); +			} +		} +		ucl_add_tabs (func, ctx->indent, compact); +	}  	ucl_emitter_print_key (print_key, ctx, obj, compact);  	/* @@ -320,13 +348,13 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,  		if (ctx->id == UCL_EMIT_CONFIG) {  			LL_FOREACH (cur, elt) { -				ucl_emitter_common_elt (ctx, elt, first, true, compact); +				ucl_emitter_common_elt (ctx, elt, first_key, true, compact);  			}  		}  		else {  			/* Expand implicit arrays */  			if (cur->next != NULL) { -				if (!first) { +				if (!first_key) {  					if (compact) {  						func->ucl_emitter_append_character (',', 1, func->ud);  					} @@ -335,15 +363,15 @@ ucl_emitter_common_start_object (struct ucl_emitter_context *ctx,  					}  				}  				ucl_add_tabs (func, ctx->indent, compact); -				ucl_emitter_common_start_array (ctx, cur, true, compact); +				ucl_emitter_common_start_array (ctx, cur, first_key, true, compact);  				ucl_emitter_common_end_array (ctx, cur, compact);  			}  			else { -				ucl_emitter_common_elt (ctx, cur, first, true, compact); +				ucl_emitter_common_elt (ctx, cur, first_key, true, compact);  			}  		} -		first = false; +		first_key = false;  	}  } @@ -446,11 +474,11 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,  		ucl_emitter_finish_object (ctx, obj, compact, !print_key);  		break;  	case UCL_OBJECT: -		ucl_emitter_common_start_object (ctx, obj, print_key, compact); +		ucl_emitter_common_start_object (ctx, obj, true, print_key, compact);  		ucl_emitter_common_end_object (ctx, obj, compact);  		break;  	case UCL_ARRAY: -		ucl_emitter_common_start_array (ctx, obj, print_key, compact); +		ucl_emitter_common_start_array (ctx, obj, true, print_key, compact);  		ucl_emitter_common_end_array (ctx, obj, compact);  		break;  	case UCL_USERDATA: @@ -490,12 +518,12 @@ ucl_emitter_common_elt (struct ucl_emitter_context *ctx,  		ucl_emitter_common_elt (ctx, obj, first, print_key, (compact));	\  	}	\  	static void ucl_emit_ ## type ## _start_obj (struct ucl_emitter_context *ctx,	\ -		const ucl_object_t *obj, bool print_key) {	\ -		ucl_emitter_common_start_object (ctx, obj, print_key, (compact));	\ +		const ucl_object_t *obj, bool first, bool print_key) {	\ +		ucl_emitter_common_start_object (ctx, obj, first, print_key, (compact));	\  	}	\  	static void ucl_emit_ ## type## _start_array (struct ucl_emitter_context *ctx,	\ -		const ucl_object_t *obj, bool print_key) {	\ -		ucl_emitter_common_start_array (ctx, obj, print_key, (compact));	\ +		const ucl_object_t *obj, bool first, bool print_key) {	\ +		ucl_emitter_common_start_array (ctx, obj, first, print_key, (compact));	\  	}	\  	static void ucl_emit_ ##type## _end_object (struct ucl_emitter_context *ctx,	\  		const ucl_object_t *obj) {	\ @@ -513,7 +541,7 @@ UCL_EMIT_TYPE_IMPL(yaml, false)  static void  ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool first, bool print_key) +		const ucl_object_t *obj, bool _first, bool print_key)  {  	ucl_object_iter_t it;  	struct ucl_object_userdata *ud; @@ -556,7 +584,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,  	case UCL_OBJECT:  		ucl_emitter_print_key_msgpack (print_key, ctx, obj); -		ucl_emit_msgpack_start_obj (ctx, obj, print_key); +		ucl_emit_msgpack_start_obj (ctx, obj, false, print_key);  		it = NULL;  		while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { @@ -575,7 +603,7 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,  	case UCL_ARRAY:  		ucl_emitter_print_key_msgpack (print_key, ctx, obj); -		ucl_emit_msgpack_start_array (ctx, obj, print_key); +		ucl_emit_msgpack_start_array (ctx, obj, false, print_key);  		it = NULL;  		while ((cur = ucl_object_iterate (obj, &it, true)) != NULL) { @@ -601,14 +629,14 @@ ucl_emit_msgpack_elt (struct ucl_emitter_context *ctx,  static void  ucl_emit_msgpack_start_obj (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key) +		const ucl_object_t *obj, bool _first, bool _print_key)  {  	ucl_emitter_print_object_msgpack (ctx, obj->len);  }  static void  ucl_emit_msgpack_start_array (struct ucl_emitter_context *ctx, -		const ucl_object_t *obj, bool print_key) +		const ucl_object_t *obj, bool _first, bool _print_key)  {  	ucl_emitter_print_array_msgpack (ctx, obj->len);  } diff --git a/src/ucl_emitter_streamline.c b/src/ucl_emitter_streamline.c index a7178c5d74b0..8ca86fa081c9 100644 --- a/src/ucl_emitter_streamline.c +++ b/src/ucl_emitter_streamline.c @@ -103,18 +103,19 @@ ucl_object_emit_streamline_start_container (struct ucl_emitter_context *ctx,  	top = sctx->containers;  	st = malloc (sizeof (*st));  	if (st != NULL) { -		if (top != NULL && !top->is_array) { +		st->empty = true; +		if (top && !top->is_array) {  			print_key = true;  		} -		st->empty = true; +  		st->obj = obj;  		if (obj != NULL && obj->type == UCL_ARRAY) {  			st->is_array = true; -			sctx->ops->ucl_emitter_start_array (ctx, obj, print_key); +			sctx->ops->ucl_emitter_start_array (ctx, obj, top == NULL, print_key);  		}  		else {  			st->is_array = false; -			sctx->ops->ucl_emitter_start_object (ctx, obj, print_key); +			sctx->ops->ucl_emitter_start_object (ctx, obj, top == NULL, print_key);  		}  		LL_PREPEND (sctx->containers, st);  	} diff --git a/src/ucl_hash.c b/src/ucl_hash.c index a74dfcdee68e..0208cfd29c9a 100644 --- a/src/ucl_hash.c +++ b/src/ucl_hash.c @@ -32,12 +32,12 @@  struct ucl_hash_elt {  	const ucl_object_t *obj; -	size_t ar_idx; +	struct ucl_hash_elt *prev, *next;  };  struct ucl_hash_struct {  	void *hash; -	kvec_t(const ucl_object_t *) ar; +	struct ucl_hash_elt *head;  	bool caseless;  }; @@ -45,7 +45,6 @@ static uint64_t  ucl_hash_seed (void)  {  	static uint64_t seed; -  	if (seed == 0) {  #ifdef UCL_RANDOM_FUNCTION  		seed = UCL_RANDOM_FUNCTION; @@ -115,7 +114,7 @@ ucl_hash_equal (const ucl_object_t *k1, const ucl_object_t *k2)  	return 0;  } -KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt, 1, +KHASH_INIT (ucl_hash_node, const ucl_object_t *, struct ucl_hash_elt *, 1,  		ucl_hash_func, ucl_hash_equal)  static inline uint32_t @@ -227,7 +226,7 @@ ucl_hash_caseless_equal (const ucl_object_t *k1, const ucl_object_t *k2)  	return 0;  } -KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt, 1, +KHASH_INIT (ucl_hash_caseless_node, const ucl_object_t *, struct ucl_hash_elt *, 1,  		ucl_hash_caseless_func, ucl_hash_caseless_equal)  ucl_hash_t* @@ -238,8 +237,7 @@ ucl_hash_create (bool ignore_case)  	new = UCL_ALLOC (sizeof (ucl_hash_t));  	if (new != NULL) {  		void *h; -		kv_init (new->ar); - +		new->head = NULL;  		new->caseless = ignore_case;  		if (ignore_case) {  			h = (void *)kh_init (ucl_hash_caseless_node); @@ -258,7 +256,6 @@ ucl_hash_create (bool ignore_case)  void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)  { -	const ucl_object_t *cur, *tmp;  	if (hashlin == NULL) {  		return; @@ -269,10 +266,11 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)  		khash_t(ucl_hash_node) *h = (khash_t(ucl_hash_node) *)  				hashlin->hash;  		khiter_t k; +		const ucl_object_t *cur, *tmp;  		for (k = kh_begin (h); k != kh_end (h); ++k) {  			if (kh_exist (h, k)) { -				cur = (kh_value (h, k)).obj; +				cur = (kh_value (h, k))->obj;  				while (cur != NULL) {  					tmp = cur->next;  					func (__DECONST (ucl_object_t *, cur)); @@ -293,7 +291,12 @@ void ucl_hash_destroy (ucl_hash_t* hashlin, ucl_hash_free_func func)  		kh_destroy (ucl_hash_node, h);  	} -	kv_destroy (hashlin->ar); +	struct ucl_hash_elt *cur, *tmp; + +	DL_FOREACH_SAFE(hashlin->head, cur, tmp) { +		UCL_FREE(sizeof(*cur), cur); +	} +  	UCL_FREE (sizeof (*hashlin), hashlin);  } @@ -303,7 +306,7 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,  {  	khiter_t k;  	int ret; -	struct ucl_hash_elt *elt; +	struct ucl_hash_elt **pelt, *elt;  	if (hashlin == NULL) {  		return false; @@ -314,10 +317,14 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,  				hashlin->hash;  		k = kh_put (ucl_hash_caseless_node, h, obj, &ret);  		if (ret > 0) { -			elt = &kh_value (h, k); -			kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); +			elt = UCL_ALLOC(sizeof(*elt)); +			pelt = &kh_value (h, k); +			*pelt = elt; +			DL_APPEND(hashlin->head, elt);  			elt->obj = obj; -			elt->ar_idx = kv_size (hashlin->ar) - 1; +		} +		else if (ret < 0) { +			goto e0;  		}  	}  	else { @@ -325,10 +332,11 @@ ucl_hash_insert (ucl_hash_t* hashlin, const ucl_object_t *obj,  				hashlin->hash;  		k = kh_put (ucl_hash_node, h, obj, &ret);  		if (ret > 0) { -			elt = &kh_value (h, k); -			kv_push_safe (const ucl_object_t *, hashlin->ar, obj, e0); +			elt = UCL_ALLOC(sizeof(*elt)); +			pelt = &kh_value (h, k); +			*pelt = elt; +			DL_APPEND(hashlin->head, elt);  			elt->obj = obj; -			elt->ar_idx = kv_size (hashlin->ar) - 1;  		} else if (ret < 0) {  			goto e0;  		} @@ -343,7 +351,7 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,  {  	khiter_t k;  	int ret; -	struct ucl_hash_elt elt, *pelt; +	struct ucl_hash_elt *elt, *nelt;  	if (hashlin == NULL) {  		return; @@ -354,13 +362,14 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,  				hashlin->hash;  		k = kh_put (ucl_hash_caseless_node, h, old, &ret);  		if (ret == 0) { -			elt = kh_value (h, k); +			elt = kh_value(h, k);  			kh_del (ucl_hash_caseless_node, h, k);  			k = kh_put (ucl_hash_caseless_node, h, new, &ret); -			pelt = &kh_value (h, k); -			pelt->obj = new; -			pelt->ar_idx = elt.ar_idx; -			kv_A (hashlin->ar, elt.ar_idx) = new; +			nelt = UCL_ALLOC(sizeof(*nelt)); +			nelt->obj = new; +			kh_value(h, k) = nelt; +			DL_REPLACE_ELEM(hashlin->head, elt, nelt); +			UCL_FREE(sizeof(*elt), elt);  		}  	}  	else { @@ -371,17 +380,17 @@ void ucl_hash_replace (ucl_hash_t* hashlin, const ucl_object_t *old,  			elt = kh_value (h, k);  			kh_del (ucl_hash_node, h, k);  			k = kh_put (ucl_hash_node, h, new, &ret); -			pelt = &kh_value (h, k); -			pelt->obj = new; -			pelt->ar_idx = elt.ar_idx; -			kv_A (hashlin->ar, elt.ar_idx) = new; +			nelt = UCL_ALLOC(sizeof(*nelt)); +			nelt->obj = new; +			kh_value(h, k) = nelt; +			DL_REPLACE_ELEM(hashlin->head, elt, nelt); +			UCL_FREE(sizeof(*elt), elt);  		}  	}  }  struct ucl_hash_real_iter { -	const ucl_object_t **cur; -	const ucl_object_t **end; +	const struct ucl_hash_elt *cur;  };  #define UHI_SETERR(ep, ern) {if (ep != NULL) *ep = (ern);} @@ -405,13 +414,13 @@ ucl_hash_iterate2 (ucl_hash_t *hashlin, ucl_hash_iter_t *iter, int *ep)  			return NULL;  		} -		it->cur = &hashlin->ar.a[0]; -		it->end = it->cur + hashlin->ar.n; +		it->cur = hashlin->head;  	}  	UHI_SETERR(ep, 0); -	if (it->cur < it->end) { -		ret = *it->cur++; +	if (it->cur) { +		ret = it->cur->obj; +		it->cur = it->cur->next;  	}  	else {  		UCL_FREE (sizeof (*it), it); @@ -429,7 +438,7 @@ ucl_hash_iter_has_next (ucl_hash_t *hashlin, ucl_hash_iter_t iter)  {  	struct ucl_hash_real_iter *it = (struct ucl_hash_real_iter *)(iter); -	return it->cur < it->end - 1; +	return it->cur != NULL;  } @@ -454,7 +463,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)  		k = kh_get (ucl_hash_caseless_node, h, &search);  		if (k != kh_end (h)) { -			elt = &kh_value (h, k); +			elt = kh_value (h, k);  			ret = elt->obj;  		}  	} @@ -463,7 +472,7 @@ ucl_hash_search (ucl_hash_t* hashlin, const char *key, unsigned keylen)  						hashlin->hash;  		k = kh_get (ucl_hash_node, h, &search);  		if (k != kh_end (h)) { -			elt = &kh_value (h, k); +			elt = kh_value (h, k);  			ret = elt->obj;  		}  	} @@ -476,7 +485,6 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)  {  	khiter_t k;  	struct ucl_hash_elt *elt; -	size_t i;  	if (hashlin == NULL) {  		return; @@ -488,16 +496,10 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)  		k = kh_get (ucl_hash_caseless_node, h, obj);  		if (k != kh_end (h)) { -			elt = &kh_value (h, k); -			i = elt->ar_idx; -			kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx); +			elt = kh_value (h, k); +			DL_DELETE(hashlin->head, elt);  			kh_del (ucl_hash_caseless_node, h, k); - -			/* Update subsequent elts */ -			for (; i < hashlin->ar.n; i ++) { -				elt = &kh_value (h, i); -				elt->ar_idx --; -			} +			UCL_FREE(sizeof(*elt), elt);  		}  	}  	else { @@ -505,16 +507,10 @@ ucl_hash_delete (ucl_hash_t* hashlin, const ucl_object_t *obj)  			hashlin->hash;  		k = kh_get (ucl_hash_node, h, obj);  		if (k != kh_end (h)) { -			elt = &kh_value (h, k); -			i = elt->ar_idx; -			kv_del (const ucl_object_t *, hashlin->ar, elt->ar_idx); +			elt = kh_value (h, k); +			DL_DELETE(hashlin->head, elt);  			kh_del (ucl_hash_node, h, k); - -			/* Update subsequent elts */ -			for (; i < hashlin->ar.n; i ++) { -				elt = &kh_value (h, i); -				elt->ar_idx --; -			} +			UCL_FREE(sizeof(*elt), elt);  		}  	}  } @@ -525,9 +521,7 @@ bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)  		return false;  	} -	if (sz > hashlin->ar.m) { -		kv_resize_safe (const ucl_object_t *, hashlin->ar, sz, e0); - +	if (sz > kh_size((khash_t(ucl_hash_node) *)hashlin->hash)) {  		if (hashlin->caseless) {  			khash_t(ucl_hash_caseless_node) *h = (khash_t(  					ucl_hash_caseless_node) *) @@ -540,8 +534,6 @@ bool ucl_hash_reserve (ucl_hash_t *hashlin, size_t sz)  		}  	}  	return true; -e0: -	return false;  }  static int @@ -591,27 +583,27 @@ ucl_lc_cmp (const char *s, const char *d, size_t l)  static int  ucl_hash_cmp_icase (const void *a, const void *b)  { -	const ucl_object_t *oa = *(const ucl_object_t **)a, -			*ob = *(const ucl_object_t **)b; +	const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a, +		*ob = (const struct ucl_hash_elt *)b; -	if (oa->keylen == ob->keylen) { -		return ucl_lc_cmp (oa->key, ob->key, oa->keylen); +	if (oa->obj->keylen == ob->obj->keylen) { +		return ucl_lc_cmp (oa->obj->key, ob->obj->key, oa->obj->keylen);  	} -	return ((int)(oa->keylen)) - ob->keylen; +	return ((int)(oa->obj->keylen)) - ob->obj->keylen;  }  static int  ucl_hash_cmp_case_sens (const void *a, const void *b)  { -	const ucl_object_t *oa = *(const ucl_object_t **)a, -			*ob = *(const ucl_object_t **)b; +	const struct ucl_hash_elt *oa = (const struct ucl_hash_elt *)a, +			*ob = (const struct ucl_hash_elt *)b; -	if (oa->keylen == ob->keylen) { -		return memcmp (oa->key, ob->key, oa->keylen); +	if (oa->obj->keylen == ob->obj->keylen) { +		return memcmp (oa->obj->key, ob->obj->key, oa->obj->keylen);  	} -	return ((int)(oa->keylen)) - ob->keylen; +	return ((int)(oa->obj->keylen)) - ob->obj->keylen;  }  void @@ -619,18 +611,18 @@ ucl_hash_sort (ucl_hash_t *hashlin, enum ucl_object_keys_sort_flags fl)  {  	if (fl & UCL_SORT_KEYS_ICASE) { -		qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *), -				ucl_hash_cmp_icase); +		DL_SORT(hashlin->head, ucl_hash_cmp_icase);  	}  	else { -		qsort (hashlin->ar.a, hashlin->ar.n, sizeof (ucl_object_t *), -				ucl_hash_cmp_case_sens); +		DL_SORT(hashlin->head, ucl_hash_cmp_case_sens);  	}  	if (fl & UCL_SORT_KEYS_RECURSIVE) { -		for (size_t i = 0; i < hashlin->ar.n; i ++) { -			if (ucl_object_type (hashlin->ar.a[i]) == UCL_OBJECT) { -				ucl_hash_sort (hashlin->ar.a[i]->value.ov, fl); +		struct ucl_hash_elt *elt; + +		DL_FOREACH(hashlin->head, elt) { +			if (ucl_object_type (elt->obj) == UCL_OBJECT) { +				ucl_hash_sort (elt->obj->value.ov, fl);  			}  		}  	} diff --git a/src/ucl_parser.c b/src/ucl_parser.c index 23f5bce3056f..6be16d12169c 100644 --- a/src/ucl_parser.c +++ b/src/ucl_parser.c @@ -47,6 +47,9 @@ struct ucl_parser_saved_state {   */  #define ucl_chunk_skipc(chunk, p)    \  do {                                 \ +	if (p == chunk->end) {       \ +		break;                   \ +	}                            \  	if (*(p) == '\n') {          \  		(chunk)->line ++;    \  		(chunk)->column = 0; \ @@ -176,7 +179,7 @@ start:  				if (!quoted) {  					if (*p == '*') {  						ucl_chunk_skipc (chunk, p); -						if (*p == '/') { +						if (chunk->remain > 0 && *p == '/') {  							comments_nested --;  							if (comments_nested == 0) {  								if (parser->flags & UCL_PARSER_SAVE_COMMENTS) { @@ -345,8 +348,9 @@ ucl_check_variable_safe (struct ucl_parser *parser, const char *ptr, size_t rema  		/* Call generic handler */  		if (parser->var_handler (ptr, remain, &dst, &dstlen, &need_free,  				parser->var_data)) { -			*out_len = dstlen;  			*found = true; +			*out_len = dstlen; +  			if (need_free) {  				free (dst);  			} @@ -395,6 +399,9 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr,  			}  			p ++;  		} +		if(p == end) { +			(*out_len) ++; +		}  	}  	else if (*ptr != '$') {  		/* Not count escaped dollar sign */ @@ -418,13 +425,14 @@ ucl_check_variable (struct ucl_parser *parser, const char *ptr,   * Expand a single variable   * @param parser   * @param ptr - * @param remain + * @param in_len   * @param dest + * @param out_len   * @return   */  static const char *  ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr, -		size_t remain, unsigned char **dest) +		size_t in_len, unsigned char **dest, size_t out_len)  {  	unsigned char *d = *dest, *dst;  	const char *p = ptr + 1, *ret; @@ -435,7 +443,8 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,  	bool strict = false;  	ret = ptr + 1; -	remain --; +	/* For the $ sign */ +	in_len --;  	if (*p == '$') {  		*d++ = *p++; @@ -444,39 +453,53 @@ ucl_expand_single_variable (struct ucl_parser *parser, const char *ptr,  	}  	else if (*p == '{') {  		p ++; +		in_len --;  		strict = true;  		ret += 2; -		remain -= 2;  	}  	LL_FOREACH (parser->variables, var) { -		if (remain >= var->var_len) { +		if (out_len >= var->value_len && in_len >= (var->var_len + (strict ? 1 : 0))) {  			if (memcmp (p, var->var, var->var_len) == 0) { -				memcpy (d, var->value, var->value_len); -				ret += var->var_len; -				d += var->value_len; -				found = true; -				break; +				if (!strict || p[var->var_len] == '}') { +					memcpy (d, var->value, var->value_len); +					ret += var->var_len; +					d += var->value_len; +					found = true; +					break; +				}  			}  		}  	} +  	if (!found) {  		if (strict && parser->var_handler != NULL) { -			if (parser->var_handler (p, remain, &dst, &dstlen, &need_free, +			dstlen = out_len; + +			if (parser->var_handler (p, in_len, &dst, &dstlen, &need_free,  							parser->var_data)) { -				memcpy (d, dst, dstlen); -				ret += remain; -				d += dstlen; -				found = true; -				if (need_free) { -					free (dst); +				if (dstlen > out_len) { +					/* We do not have enough space! */ +					if (need_free) { +						free (dst); +					} +				} +				else { +					memcpy(d, dst, dstlen); +					ret += in_len; +					d += dstlen; +					found = true; + +					if (need_free) { +						free(dst); +					}  				}  			}  		} -		/* Leave variable as is */ +		/* Leave variable as is, in this case we use dest */  		if (!found) { -			if (strict) { +			if (strict && out_len >= 2) {  				/* Copy '${' */  				memcpy (d, ptr, 2);  				d += 2; @@ -506,7 +529,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,  		const char *src, size_t in_len)  {  	const char *p, *end = src + in_len; -	unsigned char *d; +	unsigned char *d, *d_end;  	size_t out_len = 0;  	bool vars_found = false; @@ -517,7 +540,7 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,  	p = src;  	while (p != end) { -		if (*p == '$') { +		if (*p == '$' && p + 1 != end) {  			p = ucl_check_variable (parser, p + 1, end - p - 1, &out_len, &vars_found);  		}  		else { @@ -538,10 +561,11 @@ ucl_expand_variable (struct ucl_parser *parser, unsigned char **dst,  	}  	d = *dst; +	d_end = d + out_len;  	p = src; -	while (p != end) { -		if (*p == '$') { -			p = ucl_expand_single_variable (parser, p, end - p, &d); +	while (p != end && d != d_end) { +		if (*p == '$' && p + 1 != end) { +			p = ucl_expand_single_variable (parser, p, end - p, &d, d_end - d);  		}  		else {  			*d++ = *p++; @@ -686,6 +710,8 @@ ucl_parser_add_container (ucl_object_t *obj, struct ucl_parser *parser,  			ucl_object_unref (obj);  		} +		UCL_FREE(sizeof (struct ucl_stack), st); +  		return NULL;  	} @@ -722,13 +748,13 @@ ucl_maybe_parse_number (ucl_object_t *obj,  	const char *p = start, *c = start;  	char *endptr;  	bool got_dot = false, got_exp = false, need_double = false, -			is_time = false, valid_start = false, is_hex = false, -			is_neg = false; +			is_time = false, valid_start = false, is_hex = false; +	int is_neg = 0;  	double dv = 0;  	int64_t lv = 0;  	if (*p == '-') { -		is_neg = true; +		is_neg = 1;  		c ++;  		p ++;  	} @@ -744,6 +770,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,  			is_hex = true;  			allow_double = false;  			c = p + 1; +			p ++;  		}  		else if (allow_double) {  			if (p == c) { @@ -792,26 +819,46 @@ ucl_maybe_parse_number (ucl_object_t *obj,  				break;  			}  		} +		else if (!allow_double && *p == '.') { +			/* Unexpected dot */ +			*pos = start; +			return EINVAL; +		}  		else {  			break;  		}  	} -	if (!valid_start) { +	if (!valid_start || p == c) { +		*pos = start; +		return EINVAL; +	} + +	char numbuf[128]; + +	if ((size_t)(p - c + 1) >= sizeof(numbuf)) {  		*pos = start;  		return EINVAL;  	} +	if (is_neg) { +		numbuf[0] = '-'; +		ucl_strlcpy (&numbuf[1], c, p - c + 1); +	} +	else { +		ucl_strlcpy (numbuf, c, p - c + 1); +	} +  	errno = 0;  	if (need_double) { -		dv = strtod (c, &endptr); +		dv = strtod (numbuf, &endptr);  	}  	else {  		if (is_hex) { -			lv = strtoimax (c, &endptr, 16); +			lv = strtoimax (numbuf, &endptr, 16);  		}  		else { -			lv = strtoimax (c, &endptr, 10); +			lv = strtoimax (numbuf, &endptr, 10);  		}  	}  	if (errno == ERANGE) { @@ -819,7 +866,15 @@ ucl_maybe_parse_number (ucl_object_t *obj,  		return ERANGE;  	} -	/* Now check endptr */ +	/* Now check endptr and move it from numbuf to the real ending */ +	if (endptr != NULL) { +		long shift = endptr - numbuf - is_neg; +		endptr = (char *)c + shift; +	} +	if (endptr >= end) { +		p = end; +		goto set_obj; +	}  	if (endptr == NULL || ucl_lex_is_atom_end (*endptr) || *endptr == '\0') {  		p = endptr;  		goto set_obj; @@ -849,6 +904,10 @@ ucl_maybe_parse_number (ucl_object_t *obj,  						dv *= ucl_lex_num_multiplier (*p, false);  					}  					p += 2; +					if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { +						*pos = start; +						return EINVAL; +					}  					goto set_obj;  				}  				else if (number_bytes || (p[1] == 'b' || p[1] == 'B')) { @@ -859,6 +918,10 @@ ucl_maybe_parse_number (ucl_object_t *obj,  					}  					lv *= ucl_lex_num_multiplier (*p, true);  					p += 2; +					if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { +						*pos = start; +						return EINVAL; +					}  					goto set_obj;  				}  				else if (ucl_lex_is_atom_end (p[1])) { @@ -883,6 +946,10 @@ ucl_maybe_parse_number (ucl_object_t *obj,  						is_time = true;  						dv *= 60.;  						p += 3; +						if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { +							*pos = start; +							return EINVAL; +						}  						goto set_obj;  					}  				} @@ -895,6 +962,10 @@ ucl_maybe_parse_number (ucl_object_t *obj,  					lv *= ucl_lex_num_multiplier (*p, number_bytes);  				}  				p ++; +				if (end - p > 0 && !ucl_lex_is_atom_end (*p)) { +					*pos = start; +					return EINVAL; +				}  				goto set_obj;  			}  			break; @@ -943,7 +1014,7 @@ ucl_maybe_parse_number (ucl_object_t *obj,  	}  	else if (endptr == end) {  		/* Just a number at the end of chunk */ -		p = endptr; +		p = end;  		goto set_obj;  	} @@ -959,11 +1030,11 @@ set_obj:  			else {  				obj->type = UCL_TIME;  			} -			obj->value.dv = is_neg ? (-dv) : dv; +			obj->value.dv = dv;  		}  		else {  			obj->type = UCL_INT; -			obj->value.iv = is_neg ? (-lv) : lv; +			obj->value.iv = lv;  		}  	}  	*pos = p; @@ -1037,13 +1108,13 @@ ucl_lex_json_string (struct ucl_parser *parser,  		}  		else if (c == '\\') {  			ucl_chunk_skipc (chunk, p); -			c = *p;  			if (p >= chunk->end) {  				ucl_set_err (parser, UCL_ESYNTAX, "unfinished escape character",  						&parser->err);  				return false;  			} -			else if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) { +			c = *p; +			if (ucl_test_character (c, UCL_CHARACTER_ESCAPE)) {  				if (c == 'u') {  					ucl_chunk_skipc (chunk, p);  					for (i = 0; i < 4 && p < chunk->end; i ++) { @@ -1289,24 +1360,20 @@ ucl_parser_process_object_element (struct ucl_parser *parser, ucl_object_t *nobj   */  static bool  ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk, -		bool *next_key, bool *end_of_object) +		bool *next_key, bool *end_of_object, bool *got_content)  {  	const unsigned char *p, *c = NULL, *end, *t;  	const char *key = NULL;  	bool got_quote = false, got_eq = false, got_semicolon = false,  			need_unescape = false, ucl_escape = false, var_expand = false, -			got_content = false, got_sep = false; +			got_sep = false;  	ucl_object_t *nobj;  	ssize_t keylen;  	p = chunk->pos; -	if (*p == '.') { -		/* It is macro actually */ -		if (!(parser->flags & UCL_PARSER_DISABLE_MACRO)) { -			ucl_chunk_skipc (chunk, p); -		} - +	if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) { +		ucl_chunk_skipc (chunk, p);  		parser->prev_state = parser->state;  		parser->state = UCL_STATE_MACRO_NAME;  		*end_of_object = false; @@ -1330,13 +1397,13 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,  				/* The first symbol */  				c = p;  				ucl_chunk_skipc (chunk, p); -				got_content = true; +				*got_content = true;  			}  			else if (*p == '"') {  				/* JSON style key */  				c = p + 1;  				got_quote = true; -				got_content = true; +				*got_content = true;  				ucl_chunk_skipc (chunk, p);  			}  			else if (*p == '}') { @@ -1344,7 +1411,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,  				*end_of_object = true;  				return true;  			} -			else if (*p == '.') { +			else if (*p == '.' && !(parser->flags & UCL_PARSER_DISABLE_MACRO)) {  				ucl_chunk_skipc (chunk, p);  				parser->prev_state = parser->state;  				parser->state = UCL_STATE_MACRO_NAME; @@ -1361,7 +1428,7 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,  			/* Parse the body of a key */  			if (!got_quote) {  				if (ucl_test_character (*p, UCL_CHARACTER_KEY)) { -					got_content = true; +					*got_content = true;  					ucl_chunk_skipc (chunk, p);  				}  				else if (ucl_test_character (*p, UCL_CHARACTER_KEY_SEP)) { @@ -1387,11 +1454,11 @@ ucl_parse_key (struct ucl_parser *parser, struct ucl_chunk *chunk,  		}  	} -	if (p >= chunk->end && got_content) { +	if (p >= chunk->end && *got_content) {  		ucl_set_err (parser, UCL_ESYNTAX, "unfinished key", &parser->err);  		return false;  	} -	else if (!got_content) { +	else if (!*got_content) {  		return true;  	}  	*end_of_object = false; @@ -1752,6 +1819,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)  		case '{':  			obj = ucl_parser_get_container (parser);  			if (obj == NULL) { +				parser->state = UCL_STATE_ERROR; +				ucl_set_err(parser, UCL_ESYNTAX, "object value must be a part of an object", +					&parser->err);  				return false;  			}  			/* We have a new object */ @@ -1773,6 +1843,9 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)  		case '[':  			obj = ucl_parser_get_container (parser);  			if (obj == NULL) { +				parser->state = UCL_STATE_ERROR; +				ucl_set_err(parser, UCL_ESYNTAX, "array value must be a part of an object", +					&parser->err);  				return false;  			}  			/* We have a new array */ @@ -1804,6 +1877,12 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)  			break;  		case '<':  			obj = ucl_parser_get_container (parser); +			if (obj == NULL) { +				parser->state = UCL_STATE_ERROR; +				ucl_set_err(parser, UCL_ESYNTAX, "multiline value must be a part of an object", +						&parser->err); +				return false; +			}  			/* We have something like multiline value, which must be <<[A-Z]+\n */  			if (chunk->end - p > 3) {  				if (memcmp (p, "<<", 2) == 0) { @@ -1812,6 +1891,11 @@ ucl_parse_value (struct ucl_parser *parser, struct ucl_chunk *chunk)  					while (p < chunk->end && *p >= 'A' && *p <= 'Z') {  						p ++;  					} +					if(p == chunk->end) { +						ucl_set_err (parser, UCL_ESYNTAX, +								"unterminated multiline value", &parser->err); +						return false; +					}  					if (*p =='\n') {  						/* Set chunk positions and start multiline parsing */  						chunk->remain -= p - c + 1; @@ -1850,6 +1934,13 @@ parse_string:  				obj = ucl_parser_get_container (parser);  			} +			if (obj == NULL) { +				parser->state = UCL_STATE_ERROR; +				ucl_set_err(parser, UCL_ESYNTAX, "value must be a part of an object", +					&parser->err); +				return false; +			} +  			/* Parse atom */  			if (ucl_test_character (*p, UCL_CHARACTER_VALUE_DIGIT_START)) {  				if (!ucl_lex_number (parser, chunk, obj)) { @@ -2339,7 +2430,7 @@ ucl_state_machine (struct ucl_parser *parser)  	unsigned char *macro_escaped;  	size_t macro_len = 0;  	struct ucl_macro *macro = NULL; -	bool next_key = false, end_of_object = false, ret; +	bool next_key = false, end_of_object = false, got_content = false, ret;  	if (parser->top_obj == NULL) {  		parser->state = UCL_STATE_INIT; @@ -2428,7 +2519,10 @@ ucl_state_machine (struct ucl_parser *parser)  				parser->state = UCL_STATE_ERROR;  				return false;  			} -			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object)) { + +			got_content = false; + +			if (!ucl_parse_key (parser, chunk, &next_key, &end_of_object, &got_content)) {  				parser->prev_state = parser->state;  				parser->state = UCL_STATE_ERROR;  				return false; @@ -2451,7 +2545,8 @@ ucl_state_machine (struct ucl_parser *parser)  						return false;  					}  				} -				else { +				else if (got_content) { +					/* Do not switch state if we have not read any content */  					parser->state = UCL_STATE_VALUE;  				}  			} @@ -2617,6 +2712,9 @@ ucl_state_machine (struct ucl_parser *parser)  				return false;  			}  			break; +		case UCL_STATE_ERROR: +			/* Already in the error state */ +			return false;  		default:  			ucl_set_err (parser, UCL_EINTERNAL,  					"internal error: parser is in an unknown state", &parser->err); @@ -2889,7 +2987,9 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,  				if (!special_handler->handler (parser, data, len, &ndata, &nlen,  						special_handler->user_data)) { +					UCL_FREE(sizeof (struct ucl_chunk), chunk);  					ucl_create_err (&parser->err, "call for external handler failed"); +  					return false;  				} @@ -2909,7 +3009,7 @@ ucl_parser_add_chunk_full (struct ucl_parser *parser, const unsigned char *data,  		if (parse_type == UCL_PARSE_AUTO && len > 0) {  			/* We need to detect parse type by the first symbol */ -			if ((*data & 0x80) == 0x80 && (*data >= 0xdc && *data <= 0xdf)) { +			if ((*data & 0x80) == 0x80) {  				parse_type = UCL_PARSE_MSGPACK;  			}  			else if (*data == '(') { diff --git a/src/ucl_schema.c b/src/ucl_schema.c index 68f01187e375..f4ec0ed3284a 100644 --- a/src/ucl_schema.c +++ b/src/ucl_schema.c @@ -39,6 +39,7 @@  #ifdef HAVE_MATH_H  #include <math.h>  #endif +#include <inttypes.h>  static bool ucl_schema_validate (const ucl_object_t *schema,  		const ucl_object_t *obj, bool try_array, diff --git a/src/ucl_util.c b/src/ucl_util.c index b00a34787e5a..8f97c20db503 100644 --- a/src/ucl_util.c +++ b/src/ucl_util.c @@ -67,7 +67,7 @@ typedef kvec_t(ucl_object_t *) ucl_array_t;  #include <fetch.h>  #endif -#if defined(_MSC_VER) +#if defined(_WIN32)  #include <windows.h>  #include <io.h>  #include <direct.h> @@ -889,44 +889,49 @@ ucl_fetch_file (const unsigned char *filename, unsigned char **buf, size_t *bufl  {  	int fd;  	struct stat st; +	if ((fd = open (filename, O_RDONLY)) == -1) { +		ucl_create_err (err, "cannot open file %s: %s", +				filename, strerror (errno)); +		return false; +	} -	if (stat (filename, &st) == -1) { +	if (fstat (fd, &st) == -1) {  		if (must_exist || errno == EPERM) {  			ucl_create_err (err, "cannot stat file %s: %s",  					filename, strerror (errno));  		} +		close (fd); +  		return false;  	}  	if (!S_ISREG (st.st_mode)) {  		if (must_exist) {  			ucl_create_err (err, "file %s is not a regular file", filename);  		} +		close (fd);  		return false;  	} +  	if (st.st_size == 0) {  		/* Do not map empty files */  		*buf = NULL;  		*buflen = 0;  	}  	else { -		if ((fd = open (filename, O_RDONLY)) == -1) { -			ucl_create_err (err, "cannot open file %s: %s", -					filename, strerror (errno)); -			return false; -		} -		if ((*buf = ucl_mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { -			close (fd); -			ucl_create_err (err, "cannot mmap file %s: %s", -					filename, strerror (errno)); +		if ((*buf = ucl_mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED) { +			close(fd); +			ucl_create_err(err, "cannot mmap file %s: %s", +					filename, strerror(errno));  			*buf = NULL;  			return false;  		}  		*buflen = st.st_size; -		close (fd);  	} +	close (fd); +  	return true;  } @@ -1017,6 +1022,9 @@ ucl_include_url (const unsigned char *data, size_t len,  	snprintf (urlbuf, sizeof (urlbuf), "%.*s", (int)len, data);  	if (!ucl_fetch_url (urlbuf, &buf, &buflen, &parser->err, params->must_exist)) { +		if (!params->must_exist) { +			ucl_parser_clear_error (parser); +		}  		return !params->must_exist;  	} @@ -1092,6 +1100,11 @@ ucl_include_file_single (const unsigned char *data, size_t len,  	ucl_hash_t *container = NULL;  	struct ucl_stack *st = NULL; +	if (parser->state == UCL_STATE_ERROR) { +		/* Return immediately if we are in the error state... */ +		return false; +	} +  	snprintf (filebuf, sizeof (filebuf), "%.*s", (int)len, data);  	if (ucl_realpath (filebuf, realbuf) == NULL) {  		if (params->soft_fail) { @@ -1128,6 +1141,8 @@ ucl_include_file_single (const unsigned char *data, size_t len,  			return false;  		} +		ucl_parser_clear_error (parser); +  		return true;  	} @@ -1138,6 +1153,10 @@ ucl_include_file_single (const unsigned char *data, size_t len,  		/* We need to check signature first */  		snprintf (filebuf, sizeof (filebuf), "%s.sig", realbuf);  		if (!ucl_fetch_file (filebuf, &sigbuf, &siglen, &parser->err, true)) { +			if (buf) { +				ucl_munmap (buf, buflen); +			} +  			return false;  		}  		if (!ucl_sig_check (buf, buflen, sigbuf, siglen, parser)) { @@ -1147,8 +1166,13 @@ ucl_include_file_single (const unsigned char *data, size_t len,  			if (sigbuf) {  				ucl_munmap (sigbuf, siglen);  			} +			if (buf) { +				ucl_munmap (buf, buflen); +			} +  			return false;  		} +  		if (sigbuf) {  			ucl_munmap (sigbuf, siglen);  		} @@ -1257,6 +1281,8 @@ ucl_include_file_single (const unsigned char *data, size_t len,  							ucl_munmap (buf, buflen);  						} +						ucl_object_unref (new_obj); +  						return false;  					}  					nest_obj->prev = nest_obj; @@ -1576,11 +1602,6 @@ ucl_include_common (const unsigned char *data, size_t len,  			else if (param->type == UCL_INT) {  				if (strncmp (param->key, "priority", param->keylen) == 0) {  					params.priority = ucl_object_toint (param); -					if (params.priority > UCL_PRIORITY_MAX) { -						ucl_create_err (&parser->err, "Invalid priority value in macro: %d", -							params.priority); -						return false; -					}  				}  			}  		} @@ -1719,9 +1740,8 @@ ucl_priority_handler (const unsigned char *data, size_t len,  	if (len > 0) {  		value = malloc(len + 1);  		ucl_strlcpy(value, (const char *)data, len + 1); -		errno = 0; -		priority = strtoul(value, &leftover, 10); -		if (errno != 0 || *leftover != '\0' || priority > UCL_PRIORITY_MAX) { +		priority = strtol(value, &leftover, 10); +		if (*leftover != '\0') {  			ucl_create_err (&parser->err, "Invalid priority value in macro: %s",  				value);  			free(value); @@ -1842,6 +1862,10 @@ ucl_load_handler (const unsigned char *data, size_t len,  				!try_load)) {  			free (load_file); +			if (try_load) { +				ucl_parser_clear_error (parser); +			} +  			return (try_load || false);  		} @@ -1919,7 +1943,7 @@ ucl_inherit_handler (const unsigned char *data, size_t len,  	/* Some sanity checks */  	if (parent == NULL || ucl_object_type (parent) != UCL_OBJECT) { -		ucl_create_err (&parser->err, "Unable to find inherited object %*.s", +		ucl_create_err (&parser->err, "Unable to find inherited object %.*s",  				(int)len, data);  		return false;  	} @@ -2177,7 +2201,7 @@ ucl_strnstr (const char *s, const char *find, int len)  		mlen = strlen (find);  		do {  			do { -				if ((sc = *s++) == 0 || len-- == 0) +				if ((sc = *s++) == 0 || len-- < mlen)  					return (NULL);  			} while (sc != c);  		} while (strncmp (s, find, mlen) != 0); @@ -2596,6 +2620,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)  						if (!ucl_object_merge (found, cp, copy)) {  							return false;  						} +						ucl_object_unref (cp);  					}  					else {  						ucl_hash_replace (top->value.ov, found, cp); @@ -2627,6 +2652,7 @@ ucl_object_merge (ucl_object_t *top, ucl_object_t *elt, bool copy)  					if (!ucl_object_merge (found, cp, copy)) {  						return false;  					} +					ucl_object_unref (cp);  				}  				else {  					ucl_hash_replace (top->value.ov, found, cp); @@ -3068,13 +3094,13 @@ ucl_object_type (const ucl_object_t *obj)  ucl_object_t*  ucl_object_fromstring (const char *str)  { -	return ucl_object_fromstring_common (str, 0, UCL_STRING_ESCAPE); +	return ucl_object_fromstring_common (str, 0, UCL_STRING_RAW);  }  ucl_object_t *  ucl_object_fromlstring (const char *str, size_t len)  { -	return ucl_object_fromstring_common (str, len, UCL_STRING_ESCAPE); +	return ucl_object_fromstring_common (str, len, UCL_STRING_RAW);  }  ucl_object_t * @@ -3594,9 +3620,11 @@ ucl_object_copy_internal (const ucl_object_t *other, bool allow_array)  		/* deep copy of values stored */  		if (other->trash_stack[UCL_TRASH_KEY] != NULL) { -			new->trash_stack[UCL_TRASH_KEY] = -					strdup (other->trash_stack[UCL_TRASH_KEY]); +			new->trash_stack[UCL_TRASH_KEY] = NULL;  			if (other->key == (const char *)other->trash_stack[UCL_TRASH_KEY]) { +				new->trash_stack[UCL_TRASH_KEY] = malloc(other->keylen + 1); +				memcpy(new->trash_stack[UCL_TRASH_KEY], other->trash_stack[UCL_TRASH_KEY], other->keylen); +				new->trash_stack[UCL_TRASH_KEY][other->keylen] = '\0';  				new->key = new->trash_stack[UCL_TRASH_KEY];  			}  		} @@ -3666,13 +3694,6 @@ ucl_object_compare (const ucl_object_t *o1, const ucl_object_t *o2)  	ucl_object_iter_t iter = NULL;  	int ret = 0; -    // Must check for NULL or code will segfault -    if ((o1 == NULL) || (o2 == NULL)) -    { -        // The only way this could be true is of both are NULL -        return (o1 == NULL) && (o2 == NULL); -    } -      	if (o1->type != o2->type) {  		return (o1->type) - (o2->type);  	} diff --git a/tests/schema/definitions.json b/tests/schema/definitions.json deleted file mode 100644 index 1ab9b2163c44..000000000000 --- a/tests/schema/definitions.json +++ /dev/null @@ -1,32 +0,0 @@ -[ -    { -        "description": "valid definition", -        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, -        "tests": [ -            { -                "description": "valid definition schema", -                "data": { -                    "definitions": { -                        "foo": {"type": "integer"} -                    } -                }, -                "valid": true -            } -        ] -    }, -    { -        "description": "invalid definition", -        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, -        "tests": [ -            { -                "description": "invalid definition schema", -                "data": { -                    "definitions": { -                        "foo": {"type": 1} -                    } -                }, -                "valid": false -            } -        ] -    } -] diff --git a/tests/schema/ref.json b/tests/schema/ref.json index 1767769cd845..d8214bc2b30c 100644 --- a/tests/schema/ref.json +++ b/tests/schema/ref.json @@ -124,21 +124,5 @@                  "valid": false              }          ] -    }, -    { -        "description": "remote ref, containing refs itself", -        "schema": {"$ref": "http://highsecure.ru/ucl-schema/schema#"}, -        "tests": [ -            { -                "description": "remote ref valid", -                "data": {"minLength": 1}, -                "valid": true -            }, -            { -                "description": "remote ref invalid", -                "data": {"minLength": -1}, -                "valid": false -            } -        ]      }  ] diff --git a/tests/schema/refRemote.json b/tests/schema/refRemote.json deleted file mode 100644 index 067c666b0ec8..000000000000 --- a/tests/schema/refRemote.json +++ /dev/null @@ -1,76 +0,0 @@ -[ -    { -        "description": "remote ref", -        "schema": {"$ref": "http://highsecure.ru/ucl-schema/remotes/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://highsecure.ru/ucl-schema/remotes/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://highsecure.ru/ucl-schema/remotes/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://highsecure.ru/ucl-schema/remotes/", -            "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 -            } -        ] -    } -*/ -] diff --git a/tests/test_speed.c b/tests/test_speed.c index 56f2e5abc6c7..51476c94940b 100644 --- a/tests/test_speed.c +++ b/tests/test_speed.c @@ -44,7 +44,7 @@ get_ticks (void)  {  	double res; -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(HAVE_MACH_MACH_TIME_H)  	res = mach_absolute_time () / 1000000000.;  #else  	struct timespec ts; diff --git a/tests/test_streamline.c b/tests/test_streamline.c index 4c56c4cdcffd..37fe14f9fb97 100644 --- a/tests/test_streamline.c +++ b/tests/test_streamline.c @@ -26,6 +26,10 @@  #include <assert.h>  #include "ucl.h" +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +  int  main (int argc, char **argv)  { @@ -34,7 +38,28 @@ main (int argc, char **argv)  	const char *fname_out = NULL;  	struct ucl_emitter_context *ctx;  	struct ucl_emitter_functions *f; -	int ret = 0; +	int ret = 0, opt, json = 0, compact = 0, yaml = 0; + +	while ((opt = getopt(argc, argv, "jcy")) != -1) { +		switch (opt) { +		case 'j': +			json = 1; +			break; +		case 'c': +			compact = 1; +			break; +		case 'y': +			yaml = 1; +			break; +		default: /* '?' */ +			fprintf (stderr, "Usage: %s [-jcy] [out]\n", +				argv[0]); +			exit (EXIT_FAILURE); +		} +	} + +	argc -= optind; +	argv += optind;  	switch (argc) {  	case 2: @@ -63,7 +88,21 @@ main (int argc, char **argv)  	ucl_object_insert_key (obj, cur, "key3", 0, false);  	f = ucl_object_emit_file_funcs (out); -	ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_CONFIG, f); + +	if (yaml) { +		ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_YAML, f); +	} +	else if (json) { +		if (compact) { +			ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_JSON_COMPACT, f); +		} +		else { +			ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_JSON, f); +		} +	} +	else { +		ctx = ucl_object_emit_streamline_new (obj, UCL_EMIT_CONFIG, f); +	}  	assert (ctx != NULL); diff --git a/uthash/utlist.h b/uthash/utlist.h index c82dd916e2ed..08fc59ae6bef 100644 --- a/uthash/utlist.h +++ b/uthash/utlist.h @@ -1,5 +1,5 @@  /* -Copyright (c) 2007-2013, Troy D. Hanson   http://troydhanson.github.com/uthash/ +Copyright (c) 2007-2022, Troy D. Hanson  https://troydhanson.github.io/uthash/  All rights reserved.  Redistribution and use in source and binary forms, with or without @@ -24,11 +24,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  #ifndef UTLIST_H  #define UTLIST_H -#define UTLIST_VERSION 1.9.8 +#define UTLIST_VERSION 2.3.0  #include <assert.h> -/*  +/*   * This file contains macros to manipulate singly and doubly-linked lists.   *   * 1. LL_ macros:  singly-linked lists. @@ -38,7 +38,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * To use singly-linked lists, your structure must have a "next" pointer.   * To use doubly-linked lists, your structure must "prev" and "next" pointers.   * Either way, the pointer to the head of the list must be initialized to NULL. - *  + *   * ----------------.EXAMPLE -------------------------   * struct item {   *      int id; @@ -61,41 +61,46 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  /* These macros use decltype or the earlier __typeof GNU extension.     As decltype is only available in newer compilers (VS2010 or gcc 4.3+ -   when compiling c++ code), this code uses whatever method is needed +   when compiling c++ source) this code uses whatever method is needed     or, for VS2008 where neither is available, uses casting workarounds. */ -#ifdef _MSC_VER            /* MS compiler */ +#if !defined(LDECLTYPE) && !defined(NO_DECLTYPE) +#if defined(_MSC_VER)   /* MS compiler */  #if _MSC_VER >= 1600 && defined(__cplusplus)  /* VS2010 or newer in C++ mode */  #define LDECLTYPE(x) decltype(x) -#else                     /* VS2008 or older (or VS2010 in C mode) */ +#else                   /* VS2008 or older (or VS2010 in C mode) */  #define NO_DECLTYPE -#define LDECLTYPE(x) char*  #endif -#elif defined(__ICCARM__) +#elif defined(__MCST__)  /* Elbrus C Compiler */ +#define LDECLTYPE(x) __typeof(x) +#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)  #define NO_DECLTYPE -#define LDECLTYPE(x) char* -#else                      /* GNU, Sun and other compilers */ +#else                   /* GNU, Sun and other compilers */  #define LDECLTYPE(x) __typeof(x)  #endif +#endif  /* for VS2008 we use some workarounds to get around the lack of decltype,   * namely, we always reassign our tmp variable to the list head if we need   * to dereference its prev/next pointers, and save/restore the real head.*/  #ifdef NO_DECLTYPE -#define _SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } -#define _NEXT(elt,list,next) ((char*)((list)->next)) -#define _NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } -/* #define _PREV(elt,list,prev) ((char*)((list)->prev)) */ -#define _PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } -#define _RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } -#define _CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } -#else  -#define _SV(elt,list) -#define _NEXT(elt,list,next) ((elt)->next) -#define _NEXTASGN(elt,list,to,next) ((elt)->next)=(to) -/* #define _PREV(elt,list,prev) ((elt)->prev) */ -#define _PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) -#define _RS(list) -#define _CASTASGN(a,b) (a)=(b) +#define IF_NO_DECLTYPE(x) x +#define LDECLTYPE(x) char* +#define UTLIST_SV(elt,list) _tmp = (char*)(list); {char **_alias = (char**)&(list); *_alias = (elt); } +#define UTLIST_NEXT(elt,list,next) ((char*)((list)->next)) +#define UTLIST_NEXTASGN(elt,list,to,next) { char **_alias = (char**)&((list)->next); *_alias=(char*)(to); } +/* #define UTLIST_PREV(elt,list,prev) ((char*)((list)->prev)) */ +#define UTLIST_PREVASGN(elt,list,to,prev) { char **_alias = (char**)&((list)->prev); *_alias=(char*)(to); } +#define UTLIST_RS(list) { char **_alias = (char**)&(list); *_alias=_tmp; } +#define UTLIST_CASTASGN(a,b) { char **_alias = (char**)&(a); *_alias=(char*)(b); } +#else +#define IF_NO_DECLTYPE(x) +#define UTLIST_SV(elt,list) +#define UTLIST_NEXT(elt,list,next) ((elt)->next) +#define UTLIST_NEXTASGN(elt,list,to,next) ((elt)->next)=(to) +/* #define UTLIST_PREV(elt,list,prev) ((elt)->prev) */ +#define UTLIST_PREVASGN(elt,list,to,prev) ((elt)->prev)=(to) +#define UTLIST_RS(list) +#define UTLIST_CASTASGN(a,b) (a)=(b)  #endif  /****************************************************************************** @@ -111,13 +116,14 @@ do {    LDECLTYPE(list) _ls_q;                                                                       \    LDECLTYPE(list) _ls_e;                                                                       \    LDECLTYPE(list) _ls_tail;                                                                    \ +  IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;)                                                        \    int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \    if (list) {                                                                                  \      _ls_insize = 1;                                                                            \      _ls_looping = 1;                                                                           \      while (_ls_looping) {                                                                      \ -      _CASTASGN(_ls_p,list);                                                                   \ -      list = NULL;                                                                             \ +      UTLIST_CASTASGN(_ls_p,list);                                                             \ +      (list) = NULL;                                                                           \        _ls_tail = NULL;                                                                         \        _ls_nmerges = 0;                                                                         \        while (_ls_p) {                                                                          \ @@ -126,35 +132,35 @@ do {          _ls_psize = 0;                                                                         \          for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \            _ls_psize++;                                                                         \ -          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \ +          UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list);        \            if (!_ls_q) break;                                                                   \          }                                                                                      \          _ls_qsize = _ls_insize;                                                                \          while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \            if (_ls_psize == 0) {                                                                \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \            } else if (_ls_qsize == 0 || !_ls_q) {                                               \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \            } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \            } else {                                                                             \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \            }                                                                                    \            if (_ls_tail) {                                                                      \ -            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \ +            UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \            } else {                                                                             \ -            _CASTASGN(list,_ls_e);                                                             \ +            UTLIST_CASTASGN(list,_ls_e);                                                       \            }                                                                                    \            _ls_tail = _ls_e;                                                                    \          }                                                                                      \          _ls_p = _ls_q;                                                                         \        }                                                                                        \        if (_ls_tail) {                                                                          \ -        _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                     \ +        UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list);   \        }                                                                                        \        if (_ls_nmerges <= 1) {                                                                  \          _ls_looping=0;                                                                         \ @@ -174,13 +180,14 @@ do {    LDECLTYPE(list) _ls_q;                                                                       \    LDECLTYPE(list) _ls_e;                                                                       \    LDECLTYPE(list) _ls_tail;                                                                    \ +  IF_NO_DECLTYPE(LDECLTYPE(list) _tmp;)                                                        \    int _ls_insize, _ls_nmerges, _ls_psize, _ls_qsize, _ls_i, _ls_looping;                       \    if (list) {                                                                                  \      _ls_insize = 1;                                                                            \      _ls_looping = 1;                                                                           \      while (_ls_looping) {                                                                      \ -      _CASTASGN(_ls_p,list);                                                                   \ -      list = NULL;                                                                             \ +      UTLIST_CASTASGN(_ls_p,list);                                                             \ +      (list) = NULL;                                                                           \        _ls_tail = NULL;                                                                         \        _ls_nmerges = 0;                                                                         \        while (_ls_p) {                                                                          \ @@ -189,36 +196,36 @@ do {          _ls_psize = 0;                                                                         \          for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \            _ls_psize++;                                                                         \ -          _SV(_ls_q,list); _ls_q = _NEXT(_ls_q,list,next); _RS(list);                          \ +          UTLIST_SV(_ls_q,list); _ls_q = UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list);        \            if (!_ls_q) break;                                                                   \          }                                                                                      \          _ls_qsize = _ls_insize;                                                                \ -        while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \ +        while ((_ls_psize > 0) || ((_ls_qsize > 0) && _ls_q)) {                                \            if (_ls_psize == 0) {                                                                \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ -          } else if (_ls_qsize == 0 || !_ls_q) {                                               \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \ +          } else if ((_ls_qsize == 0) || (!_ls_q)) {                                           \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \            } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \            } else {                                                                             \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \            }                                                                                    \            if (_ls_tail) {                                                                      \ -            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \ +            UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \            } else {                                                                             \ -            _CASTASGN(list,_ls_e);                                                             \ +            UTLIST_CASTASGN(list,_ls_e);                                                       \            }                                                                                    \ -          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \ +          UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list);   \            _ls_tail = _ls_e;                                                                    \          }                                                                                      \          _ls_p = _ls_q;                                                                         \        }                                                                                        \ -      _CASTASGN(list->prev, _ls_tail);                                                         \ -      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,NULL,next); _RS(list);                       \ +      UTLIST_CASTASGN((list)->prev, _ls_tail);                                                 \ +      UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,NULL,next); UTLIST_RS(list);     \        if (_ls_nmerges <= 1) {                                                                  \          _ls_looping=0;                                                                         \        }                                                                                        \ @@ -243,9 +250,9 @@ do {      _ls_insize = 1;                                                                            \      _ls_looping = 1;                                                                           \      while (_ls_looping) {                                                                      \ -      _CASTASGN(_ls_p,list);                                                                   \ -      _CASTASGN(_ls_oldhead,list);                                                             \ -      list = NULL;                                                                             \ +      UTLIST_CASTASGN(_ls_p,list);                                                             \ +      UTLIST_CASTASGN(_ls_oldhead,list);                                                       \ +      (list) = NULL;                                                                           \        _ls_tail = NULL;                                                                         \        _ls_nmerges = 0;                                                                         \        while (_ls_p) {                                                                          \ @@ -254,47 +261,47 @@ do {          _ls_psize = 0;                                                                         \          for (_ls_i = 0; _ls_i < _ls_insize; _ls_i++) {                                         \            _ls_psize++;                                                                         \ -          _SV(_ls_q,list);                                                                     \ -          if (_NEXT(_ls_q,list,next) == _ls_oldhead) {                                         \ +          UTLIST_SV(_ls_q,list);                                                               \ +          if (UTLIST_NEXT(_ls_q,list,next) == _ls_oldhead) {                                   \              _ls_q = NULL;                                                                      \            } else {                                                                             \ -            _ls_q = _NEXT(_ls_q,list,next);                                                    \ +            _ls_q = UTLIST_NEXT(_ls_q,list,next);                                              \            }                                                                                    \ -          _RS(list);                                                                           \ +          UTLIST_RS(list);                                                                     \            if (!_ls_q) break;                                                                   \          }                                                                                      \          _ls_qsize = _ls_insize;                                                                \          while (_ls_psize > 0 || (_ls_qsize > 0 && _ls_q)) {                                    \            if (_ls_psize == 0) {                                                                \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \              if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \            } else if (_ls_qsize == 0 || !_ls_q) {                                               \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \              if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \            } else if (cmp(_ls_p,_ls_q) <= 0) {                                                  \ -            _ls_e = _ls_p; _SV(_ls_p,list); _ls_p =                                            \ -              _NEXT(_ls_p,list,next); _RS(list); _ls_psize--;                                  \ +            _ls_e = _ls_p; UTLIST_SV(_ls_p,list); _ls_p =                                      \ +              UTLIST_NEXT(_ls_p,list,next); UTLIST_RS(list); _ls_psize--;                      \              if (_ls_p == _ls_oldhead) { _ls_p = NULL; }                                        \            } else {                                                                             \ -            _ls_e = _ls_q; _SV(_ls_q,list); _ls_q =                                            \ -              _NEXT(_ls_q,list,next); _RS(list); _ls_qsize--;                                  \ +            _ls_e = _ls_q; UTLIST_SV(_ls_q,list); _ls_q =                                      \ +              UTLIST_NEXT(_ls_q,list,next); UTLIST_RS(list); _ls_qsize--;                      \              if (_ls_q == _ls_oldhead) { _ls_q = NULL; }                                        \            }                                                                                    \            if (_ls_tail) {                                                                      \ -            _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_ls_e,next); _RS(list);                \ +            UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_ls_e,next); UTLIST_RS(list); \            } else {                                                                             \ -            _CASTASGN(list,_ls_e);                                                             \ +            UTLIST_CASTASGN(list,_ls_e);                                                       \            }                                                                                    \ -          _SV(_ls_e,list); _PREVASGN(_ls_e,list,_ls_tail,prev); _RS(list);                     \ +          UTLIST_SV(_ls_e,list); UTLIST_PREVASGN(_ls_e,list,_ls_tail,prev); UTLIST_RS(list);   \            _ls_tail = _ls_e;                                                                    \          }                                                                                      \          _ls_p = _ls_q;                                                                         \        }                                                                                        \ -      _CASTASGN(list->prev,_ls_tail);                                                          \ -      _CASTASGN(_tmp,list);                                                                    \ -      _SV(_ls_tail,list); _NEXTASGN(_ls_tail,list,_tmp,next); _RS(list);                       \ +      UTLIST_CASTASGN((list)->prev,_ls_tail);                                                  \ +      UTLIST_CASTASGN(_tmp,list);                                                              \ +      UTLIST_SV(_ls_tail,list); UTLIST_NEXTASGN(_ls_tail,list,_tmp,next); UTLIST_RS(list);     \        if (_ls_nmerges <= 1) {                                                                  \          _ls_looping=0;                                                                         \        }                                                                                        \ @@ -311,8 +318,8 @@ do {  #define LL_PREPEND2(head,add,next)                                                             \  do {                                                                                           \ -  (add)->next = head;                                                                          \ -  head = add;                                                                                  \ +  (add)->next = (head);                                                                        \ +  (head) = (add);                                                                              \  } while (0)  #define LL_CONCAT(head1,head2)                                                                 \ @@ -322,7 +329,7 @@ do {  do {                                                                                           \    LDECLTYPE(head1) _tmp;                                                                       \    if (head1) {                                                                                 \ -    _tmp = head1;                                                                              \ +    _tmp = (head1);                                                                            \      while (_tmp->next) { _tmp = _tmp->next; }                                                  \      _tmp->next=(head2);                                                                        \    } else {                                                                                     \ @@ -338,7 +345,7 @@ do {    LDECLTYPE(head) _tmp;                                                                        \    (add)->next=NULL;                                                                            \    if (head) {                                                                                  \ -    _tmp = head;                                                                               \ +    _tmp = (head);                                                                             \      while (_tmp->next) { _tmp = _tmp->next; }                                                  \      _tmp->next=(add);                                                                          \    } else {                                                                                     \ @@ -346,96 +353,76 @@ do {    }                                                                                            \  } while (0) -#define LL_DELETE(head,del)                                                                    \ -    LL_DELETE2(head,del,next) +#define LL_INSERT_INORDER(head,add,cmp)                                                        \ +    LL_INSERT_INORDER2(head,add,cmp,next) -#define LL_DELETE2(head,del,next)                                                              \ +#define LL_INSERT_INORDER2(head,add,cmp,next)                                                  \  do {                                                                                           \    LDECLTYPE(head) _tmp;                                                                        \ -  if ((head) == (del)) {                                                                       \ -    (head)=(head)->next;                                                                       \ +  if (head) {                                                                                  \ +    LL_LOWER_BOUND2(head, _tmp, add, cmp, next);                                               \ +    LL_APPEND_ELEM2(head, _tmp, add, next);                                                    \    } else {                                                                                     \ -    _tmp = head;                                                                               \ -    while (_tmp->next && (_tmp->next != (del))) {                                              \ -      _tmp = _tmp->next;                                                                       \ -    }                                                                                          \ -    if (_tmp->next) {                                                                          \ -      _tmp->next = ((del)->next);                                                              \ -    }                                                                                          \ +    (head) = (add);                                                                            \ +    (head)->next = NULL;                                                                       \    }                                                                                            \  } while (0) -/* Here are VS2008 replacements for LL_APPEND and LL_DELETE */ -#define LL_APPEND_VS2008(head,add)                                                             \ -    LL_APPEND2_VS2008(head,add,next) +#define LL_LOWER_BOUND(head,elt,like,cmp)                                                      \ +    LL_LOWER_BOUND2(head,elt,like,cmp,next) -#define LL_APPEND2_VS2008(head,add,next)                                                       \ -do {                                                                                           \ -  if (head) {                                                                                  \ -    (add)->next = head;     /* use add->next as a temp variable */                             \ -    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \ -    (add)->next->next=(add);                                                                   \ -  } else {                                                                                     \ -    (head)=(add);                                                                              \ -  }                                                                                            \ -  (add)->next=NULL;                                                                            \ -} while (0) +#define LL_LOWER_BOUND2(head,elt,like,cmp,next)                                                \ +  do {                                                                                         \ +    if ((head) == NULL || (cmp(head, like)) >= 0) {                                            \ +      (elt) = NULL;                                                                            \ +    } else {                                                                                   \ +      for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) {                         \ +        if (cmp((elt)->next, like) >= 0) {                                                     \ +          break;                                                                               \ +        }                                                                                      \ +      }                                                                                        \ +    }                                                                                          \ +  } while (0) -#define LL_DELETE_VS2008(head,del)                                                             \ -    LL_DELETE2_VS2008(head,del,next) +#define LL_DELETE(head,del)                                                                    \ +    LL_DELETE2(head,del,next) -#define LL_DELETE2_VS2008(head,del,next)                                                       \ +#define LL_DELETE2(head,del,next)                                                              \  do {                                                                                           \ +  LDECLTYPE(head) _tmp;                                                                        \    if ((head) == (del)) {                                                                       \      (head)=(head)->next;                                                                       \    } else {                                                                                     \ -    char *_tmp = (char*)(head);                                                                \ -    while ((head)->next && ((head)->next != (del))) {                                          \ -      head = (head)->next;                                                                     \ -    }                                                                                          \ -    if ((head)->next) {                                                                        \ -      (head)->next = ((del)->next);                                                            \ +    _tmp = (head);                                                                             \ +    while (_tmp->next && (_tmp->next != (del))) {                                              \ +      _tmp = _tmp->next;                                                                       \      }                                                                                          \ -    {                                                                                          \ -      char **_head_alias = (char**)&(head);                                                    \ -      *_head_alias = _tmp;                                                                     \ +    if (_tmp->next) {                                                                          \ +      _tmp->next = (del)->next;                                                                \      }                                                                                          \    }                                                                                            \  } while (0) -#ifdef NO_DECLTYPE -#undef LL_APPEND -#define LL_APPEND LL_APPEND_VS2008 -#undef LL_DELETE -#define LL_DELETE LL_DELETE_VS2008 -#undef LL_DELETE2 -#define LL_DELETE2 LL_DELETE2_VS2008 -#undef LL_APPEND2 -#define LL_APPEND2 LL_APPEND2_VS2008 -#undef LL_CONCAT /* no LL_CONCAT_VS2008 */ -#undef DL_CONCAT /* no DL_CONCAT_VS2008 */ -#endif -/* end VS2008 replacements */  #define LL_COUNT(head,el,counter)                                                              \      LL_COUNT2(head,el,counter,next)                                                            \  #define LL_COUNT2(head,el,counter,next)                                                        \ -{                                                                                              \ -    counter = 0;                                                                               \ -    LL_FOREACH2(head,el,next){ ++counter; }                                                    \ -} +do {                                                                                           \ +  (counter) = 0;                                                                               \ +  LL_FOREACH2(head,el,next) { ++(counter); }                                                   \ +} while (0)  #define LL_FOREACH(head,el)                                                                    \      LL_FOREACH2(head,el,next)  #define LL_FOREACH2(head,el,next)                                                              \ -    for(el=head;el;el=(el)->next) +    for ((el) = (head); el; (el) = (el)->next)  #define LL_FOREACH_SAFE(head,el,tmp)                                                           \      LL_FOREACH_SAFE2(head,el,tmp,next)  #define LL_FOREACH_SAFE2(head,el,tmp,next)                                                     \ -  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) +  for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))  #define LL_SEARCH_SCALAR(head,out,field,val)                                                   \      LL_SEARCH_SCALAR2(head,out,field,val,next) @@ -445,7 +432,7 @@ do {      LL_FOREACH2(head,out,next) {                                                               \        if ((out)->field == (val)) break;                                                        \      }                                                                                          \ -} while(0)  +} while (0)  #define LL_SEARCH(head,out,elt,cmp)                                                            \      LL_SEARCH2(head,out,elt,cmp,next) @@ -455,19 +442,19 @@ do {      LL_FOREACH2(head,out,next) {                                                               \        if ((cmp(out,elt))==0) break;                                                            \      }                                                                                          \ -} while(0)  +} while (0) -#define LL_REPLACE_ELEM(head, el, add)                                                         \ +#define LL_REPLACE_ELEM2(head, el, add, next)                                                  \  do {                                                                                           \   LDECLTYPE(head) _tmp;                                                                         \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ + assert((head) != NULL);                                                                       \ + assert((el) != NULL);                                                                         \ + assert((add) != NULL);                                                                        \   (add)->next = (el)->next;                                                                     \   if ((head) == (el)) {                                                                         \    (head) = (add);                                                                              \   } else {                                                                                      \ -  _tmp = head;                                                                                 \ +  _tmp = (head);                                                                               \    while (_tmp->next && (_tmp->next != (el))) {                                                 \     _tmp = _tmp->next;                                                                          \    }                                                                                            \ @@ -477,26 +464,158 @@ do {   }                                                                                             \  } while (0) +#define LL_REPLACE_ELEM(head, el, add)                                                         \ +    LL_REPLACE_ELEM2(head, el, add, next) + +#define LL_PREPEND_ELEM2(head, el, add, next)                                                  \ +do {                                                                                           \ + if (el) {                                                                                     \ +  LDECLTYPE(head) _tmp;                                                                        \ +  assert((head) != NULL);                                                                      \ +  assert((add) != NULL);                                                                       \ +  (add)->next = (el);                                                                          \ +  if ((head) == (el)) {                                                                        \ +   (head) = (add);                                                                             \ +  } else {                                                                                     \ +   _tmp = (head);                                                                              \ +   while (_tmp->next && (_tmp->next != (el))) {                                                \ +    _tmp = _tmp->next;                                                                         \ +   }                                                                                           \ +   if (_tmp->next) {                                                                           \ +     _tmp->next = (add);                                                                       \ +   }                                                                                           \ +  }                                                                                            \ + } else {                                                                                      \ +  LL_APPEND2(head, add, next);                                                                 \ + }                                                                                             \ +} while (0)                                                                                    \ +  #define LL_PREPEND_ELEM(head, el, add)                                                         \ +    LL_PREPEND_ELEM2(head, el, add, next) + +#define LL_APPEND_ELEM2(head, el, add, next)                                                   \  do {                                                                                           \ - LDECLTYPE(head) _tmp;                                                                         \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ - (add)->next = (el);                                                                           \ - if ((head) == (el)) {                                                                         \ -  (head) = (add);                                                                              \ + if (el) {                                                                                     \ +  assert((head) != NULL);                                                                      \ +  assert((add) != NULL);                                                                       \ +  (add)->next = (el)->next;                                                                    \ +  (el)->next = (add);                                                                          \   } else {                                                                                      \ -  _tmp = head;                                                                                 \ -  while (_tmp->next && (_tmp->next != (el))) {                                                 \ -   _tmp = _tmp->next;                                                                          \ +  LL_PREPEND2(head, add, next);                                                                \ + }                                                                                             \ +} while (0)                                                                                    \ + +#define LL_APPEND_ELEM(head, el, add)                                                          \ +    LL_APPEND_ELEM2(head, el, add, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef LL_CONCAT2 +#define LL_CONCAT2(head1,head2,next)                                                           \ +do {                                                                                           \ +  char *_tmp;                                                                                  \ +  if (head1) {                                                                                 \ +    _tmp = (char*)(head1);                                                                     \ +    while ((head1)->next) { (head1) = (head1)->next; }                                         \ +    (head1)->next = (head2);                                                                   \ +    UTLIST_RS(head1);                                                                          \ +  } else {                                                                                     \ +    (head1)=(head2);                                                                           \    }                                                                                            \ -  if (_tmp->next) {                                                                            \ -    _tmp->next = (add);                                                                        \ +} while (0) + +#undef LL_APPEND2 +#define LL_APPEND2(head,add,next)                                                              \ +do {                                                                                           \ +  if (head) {                                                                                  \ +    (add)->next = head;     /* use add->next as a temp variable */                             \ +    while ((add)->next->next) { (add)->next = (add)->next->next; }                             \ +    (add)->next->next=(add);                                                                   \ +  } else {                                                                                     \ +    (head)=(add);                                                                              \ +  }                                                                                            \ +  (add)->next=NULL;                                                                            \ +} while (0) + +#undef LL_INSERT_INORDER2 +#define LL_INSERT_INORDER2(head,add,cmp,next)                                                  \ +do {                                                                                           \ +  if ((head) == NULL || (cmp(head, add)) >= 0) {                                               \ +    (add)->next = (head);                                                                      \ +    (head) = (add);                                                                            \ +  } else {                                                                                     \ +    char *_tmp = (char*)(head);                                                                \ +    while ((head)->next != NULL && (cmp((head)->next, add)) < 0) {                             \ +      (head) = (head)->next;                                                                   \ +    }                                                                                          \ +    (add)->next = (head)->next;                                                                \ +    (head)->next = (add);                                                                      \ +    UTLIST_RS(head);                                                                           \ +  }                                                                                            \ +} while (0) + +#undef LL_DELETE2 +#define LL_DELETE2(head,del,next)                                                              \ +do {                                                                                           \ +  if ((head) == (del)) {                                                                       \ +    (head)=(head)->next;                                                                       \ +  } else {                                                                                     \ +    char *_tmp = (char*)(head);                                                                \ +    while ((head)->next && ((head)->next != (del))) {                                          \ +      (head) = (head)->next;                                                                   \ +    }                                                                                          \ +    if ((head)->next) {                                                                        \ +      (head)->next = ((del)->next);                                                            \ +    }                                                                                          \ +    UTLIST_RS(head);                                                                           \ +  }                                                                                            \ +} while (0) + +#undef LL_REPLACE_ELEM2 +#define LL_REPLACE_ELEM2(head, el, add, next)                                                  \ +do {                                                                                           \ +  assert((head) != NULL);                                                                      \ +  assert((el) != NULL);                                                                        \ +  assert((add) != NULL);                                                                       \ +  if ((head) == (el)) {                                                                        \ +    (head) = (add);                                                                            \ +  } else {                                                                                     \ +    (add)->next = head;                                                                        \ +    while ((add)->next->next && ((add)->next->next != (el))) {                                 \ +      (add)->next = (add)->next->next;                                                         \ +    }                                                                                          \ +    if ((add)->next->next) {                                                                   \ +      (add)->next->next = (add);                                                               \ +    }                                                                                          \ +  }                                                                                            \ +  (add)->next = (el)->next;                                                                    \ +} while (0) + +#undef LL_PREPEND_ELEM2 +#define LL_PREPEND_ELEM2(head, el, add, next)                                                  \ +do {                                                                                           \ +  if (el) {                                                                                    \ +    assert((head) != NULL);                                                                    \ +    assert((add) != NULL);                                                                     \ +    if ((head) == (el)) {                                                                      \ +      (head) = (add);                                                                          \ +    } else {                                                                                   \ +      (add)->next = (head);                                                                    \ +      while ((add)->next->next && ((add)->next->next != (el))) {                               \ +        (add)->next = (add)->next->next;                                                       \ +      }                                                                                        \ +      if ((add)->next->next) {                                                                 \ +        (add)->next->next = (add);                                                             \ +      }                                                                                        \ +    }                                                                                          \ +    (add)->next = (el);                                                                        \ +  } else {                                                                                     \ +    LL_APPEND2(head, add, next);                                                               \    }                                                                                            \ - }                                                                                             \  } while (0)                                                                                    \ +#endif /* NO_DECLTYPE */  /******************************************************************************   * doubly linked list macros (non-circular)                                   * @@ -506,7 +625,7 @@ do {  #define DL_PREPEND2(head,add,prev,next)                                                        \  do {                                                                                           \ - (add)->next = head;                                                                           \ + (add)->next = (head);                                                                         \   if (head) {                                                                                   \     (add)->prev = (head)->prev;                                                                 \     (head)->prev = (add);                                                                       \ @@ -531,7 +650,39 @@ do {        (head)->prev = (head);                                                                   \        (head)->next = NULL;                                                                     \    }                                                                                            \ -} while (0)  +} while (0) + +#define DL_INSERT_INORDER(head,add,cmp)                                                        \ +    DL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define DL_INSERT_INORDER2(head,add,cmp,prev,next)                                             \ +do {                                                                                           \ +  LDECLTYPE(head) _tmp;                                                                        \ +  if (head) {                                                                                  \ +    DL_LOWER_BOUND2(head, _tmp, add, cmp, next);                                               \ +    DL_APPEND_ELEM2(head, _tmp, add, prev, next);                                              \ +  } else {                                                                                     \ +    (head) = (add);                                                                            \ +    (head)->prev = (head);                                                                     \ +    (head)->next = NULL;                                                                       \ +  }                                                                                            \ +} while (0) + +#define DL_LOWER_BOUND(head,elt,like,cmp)                                                      \ +    DL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define DL_LOWER_BOUND2(head,elt,like,cmp,next)                                                \ +do {                                                                                           \ +  if ((head) == NULL || (cmp(head, like)) >= 0) {                                              \ +    (elt) = NULL;                                                                              \ +  } else {                                                                                     \ +    for ((elt) = (head); (elt)->next != NULL; (elt) = (elt)->next) {                           \ +      if ((cmp((elt)->next, like)) >= 0) {                                                     \ +        break;                                                                                 \ +      }                                                                                        \ +    }                                                                                          \ +  }                                                                                            \ +} while (0)  #define DL_CONCAT(head1,head2)                                                                 \      DL_CONCAT2(head1,head2,prev,next) @@ -541,25 +692,27 @@ do {    LDECLTYPE(head1) _tmp;                                                                       \    if (head2) {                                                                                 \      if (head1) {                                                                               \ -        _tmp = (head2)->prev;                                                                  \ +        UTLIST_CASTASGN(_tmp, (head2)->prev);                                                  \          (head2)->prev = (head1)->prev;                                                         \          (head1)->prev->next = (head2);                                                         \ -        (head1)->prev = _tmp;                                                                  \ +        UTLIST_CASTASGN((head1)->prev, _tmp);                                                  \      } else {                                                                                   \          (head1)=(head2);                                                                       \      }                                                                                          \    }                                                                                            \ -} while (0)  +} while (0)  #define DL_DELETE(head,del)                                                                    \      DL_DELETE2(head,del,prev,next)  #define DL_DELETE2(head,del,prev,next)                                                         \  do {                                                                                           \ +  assert((head) != NULL);                                                                      \    assert((del)->prev != NULL);                                                                 \    if ((del)->prev == (del)) {                                                                  \        (head)=NULL;                                                                             \ -  } else if ((del)==(head)) {                                                                  \ +  } else if ((del) == (head)) {                                                                \ +      assert((del)->next != NULL);                                                             \        (del)->next->prev = (del)->prev;                                                         \        (head) = (del)->next;                                                                    \    } else {                                                                                     \ @@ -570,29 +723,29 @@ do {            (head)->prev = (del)->prev;                                                          \        }                                                                                        \    }                                                                                            \ -} while (0)  +} while (0)  #define DL_COUNT(head,el,counter)                                                              \      DL_COUNT2(head,el,counter,next)                                                            \  #define DL_COUNT2(head,el,counter,next)                                                        \ -{                                                                                              \ -    counter = 0;                                                                               \ -    DL_FOREACH2(head,el,next){ ++counter; }                                                    \ -} +do {                                                                                           \ +  (counter) = 0;                                                                               \ +  DL_FOREACH2(head,el,next) { ++(counter); }                                                   \ +} while (0)  #define DL_FOREACH(head,el)                                                                    \      DL_FOREACH2(head,el,next)  #define DL_FOREACH2(head,el,next)                                                              \ -    for(el=head;el;el=(el)->next) +    for ((el) = (head); el; (el) = (el)->next)  /* this version is safe for deleting the elements during iteration */  #define DL_FOREACH_SAFE(head,el,tmp)                                                           \      DL_FOREACH_SAFE2(head,el,tmp,next)  #define DL_FOREACH_SAFE2(head,el,tmp,next)                                                     \ -  for((el)=(head);(el) && (tmp = (el)->next, 1); (el) = tmp) +  for ((el) = (head); (el) && ((tmp) = (el)->next, 1); (el) = (tmp))  /* these are identical to their singly-linked list counterparts */  #define DL_SEARCH_SCALAR LL_SEARCH_SCALAR @@ -600,11 +753,11 @@ do {  #define DL_SEARCH_SCALAR2 LL_SEARCH_SCALAR2  #define DL_SEARCH2 LL_SEARCH2 -#define DL_REPLACE_ELEM(head, el, add)                                                         \ +#define DL_REPLACE_ELEM2(head, el, add, prev, next)                                            \  do {                                                                                           \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ + assert((head) != NULL);                                                                       \ + assert((el) != NULL);                                                                         \ + assert((add) != NULL);                                                                        \   if ((head) == (el)) {                                                                         \    (head) = (add);                                                                              \    (add)->next = (el)->next;                                                                    \ @@ -626,25 +779,104 @@ do {   }                                                                                             \  } while (0) +#define DL_REPLACE_ELEM(head, el, add)                                                         \ +    DL_REPLACE_ELEM2(head, el, add, prev, next) + +#define DL_PREPEND_ELEM2(head, el, add, prev, next)                                            \ +do {                                                                                           \ + if (el) {                                                                                     \ +  assert((head) != NULL);                                                                      \ +  assert((add) != NULL);                                                                       \ +  (add)->next = (el);                                                                          \ +  (add)->prev = (el)->prev;                                                                    \ +  (el)->prev = (add);                                                                          \ +  if ((head) == (el)) {                                                                        \ +   (head) = (add);                                                                             \ +  } else {                                                                                     \ +   (add)->prev->next = (add);                                                                  \ +  }                                                                                            \ + } else {                                                                                      \ +  DL_APPEND2(head, add, prev, next);                                                           \ + }                                                                                             \ +} while (0)                                                                                    \ +  #define DL_PREPEND_ELEM(head, el, add)                                                         \ +    DL_PREPEND_ELEM2(head, el, add, prev, next) + +#define DL_APPEND_ELEM2(head, el, add, prev, next)                                             \  do {                                                                                           \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ - (add)->next = (el);                                                                           \ - (add)->prev = (el)->prev;                                                                     \ - (el)->prev = (add);                                                                           \ - if ((head) == (el)) {                                                                         \ -  (head) = (add);                                                                              \ + if (el) {                                                                                     \ +  assert((head) != NULL);                                                                      \ +  assert((add) != NULL);                                                                       \ +  (add)->next = (el)->next;                                                                    \ +  (add)->prev = (el);                                                                          \ +  (el)->next = (add);                                                                          \ +  if ((add)->next) {                                                                           \ +   (add)->next->prev = (add);                                                                  \ +  } else {                                                                                     \ +   (head)->prev = (add);                                                                       \ +  }                                                                                            \   } else {                                                                                      \ -  (add)->prev->next = (add);                                                                   \ +  DL_PREPEND2(head, add, prev, next);                                                          \   }                                                                                             \  } while (0)                                                                                    \ +#define DL_APPEND_ELEM(head, el, add)                                                          \ +   DL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ + +#undef DL_INSERT_INORDER2 +#define DL_INSERT_INORDER2(head,add,cmp,prev,next)                                             \ +do {                                                                                           \ +  if ((head) == NULL) {                                                                        \ +    (add)->prev = (add);                                                                       \ +    (add)->next = NULL;                                                                        \ +    (head) = (add);                                                                            \ +  } else if ((cmp(head, add)) >= 0) {                                                          \ +    (add)->prev = (head)->prev;                                                                \ +    (add)->next = (head);                                                                      \ +    (head)->prev = (add);                                                                      \ +    (head) = (add);                                                                            \ +  } else {                                                                                     \ +    char *_tmp = (char*)(head);                                                                \ +    while ((head)->next && (cmp((head)->next, add)) < 0) {                                     \ +      (head) = (head)->next;                                                                   \ +    }                                                                                          \ +    (add)->prev = (head);                                                                      \ +    (add)->next = (head)->next;                                                                \ +    (head)->next = (add);                                                                      \ +    UTLIST_RS(head);                                                                           \ +    if ((add)->next) {                                                                         \ +      (add)->next->prev = (add);                                                               \ +    } else {                                                                                   \ +      (head)->prev = (add);                                                                    \ +    }                                                                                          \ +  }                                                                                            \ +} while (0) +#endif /* NO_DECLTYPE */  /******************************************************************************   * circular doubly linked list macros                                         *   *****************************************************************************/ +#define CDL_APPEND(head,add)                                                                   \ +    CDL_APPEND2(head,add,prev,next) + +#define CDL_APPEND2(head,add,prev,next)                                                        \ +do {                                                                                           \ + if (head) {                                                                                   \ +   (add)->prev = (head)->prev;                                                                 \ +   (add)->next = (head);                                                                       \ +   (head)->prev = (add);                                                                       \ +   (add)->prev->next = (add);                                                                  \ + } else {                                                                                      \ +   (add)->prev = (add);                                                                        \ +   (add)->next = (add);                                                                        \ +   (head) = (add);                                                                             \ + }                                                                                             \ +} while (0) +  #define CDL_PREPEND(head,add)                                                                  \      CDL_PREPEND2(head,add,prev,next) @@ -659,7 +891,39 @@ do {     (add)->prev = (add);                                                                        \     (add)->next = (add);                                                                        \   }                                                                                             \ -(head)=(add);                                                                                  \ + (head) = (add);                                                                               \ +} while (0) + +#define CDL_INSERT_INORDER(head,add,cmp)                                                       \ +    CDL_INSERT_INORDER2(head,add,cmp,prev,next) + +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next)                                            \ +do {                                                                                           \ +  LDECLTYPE(head) _tmp;                                                                        \ +  if (head) {                                                                                  \ +    CDL_LOWER_BOUND2(head, _tmp, add, cmp, next);                                              \ +    CDL_APPEND_ELEM2(head, _tmp, add, prev, next);                                             \ +  } else {                                                                                     \ +    (head) = (add);                                                                            \ +    (head)->next = (head);                                                                     \ +    (head)->prev = (head);                                                                     \ +  }                                                                                            \ +} while (0) + +#define CDL_LOWER_BOUND(head,elt,like,cmp)                                                     \ +    CDL_LOWER_BOUND2(head,elt,like,cmp,next) + +#define CDL_LOWER_BOUND2(head,elt,like,cmp,next)                                               \ +do {                                                                                           \ +  if ((head) == NULL || (cmp(head, like)) >= 0) {                                              \ +    (elt) = NULL;                                                                              \ +  } else {                                                                                     \ +    for ((elt) = (head); (elt)->next != (head); (elt) = (elt)->next) {                         \ +      if ((cmp((elt)->next, like)) >= 0) {                                                     \ +        break;                                                                                 \ +      }                                                                                        \ +    }                                                                                          \ +  }                                                                                            \  } while (0)  #define CDL_DELETE(head,del)                                                                   \ @@ -667,37 +931,37 @@ do {  #define CDL_DELETE2(head,del,prev,next)                                                        \  do {                                                                                           \ -  if ( ((head)==(del)) && ((head)->next == (head))) {                                          \ -      (head) = 0L;                                                                             \ +  if (((head)==(del)) && ((head)->next == (head))) {                                           \ +      (head) = NULL;                                                                           \    } else {                                                                                     \       (del)->next->prev = (del)->prev;                                                          \       (del)->prev->next = (del)->next;                                                          \       if ((del) == (head)) (head)=(del)->next;                                                  \    }                                                                                            \ -} while (0)  +} while (0)  #define CDL_COUNT(head,el,counter)                                                             \      CDL_COUNT2(head,el,counter,next)                                                           \  #define CDL_COUNT2(head, el, counter,next)                                                     \ -{                                                                                              \ -    counter = 0;                                                                               \ -    CDL_FOREACH2(head,el,next){ ++counter; }                                                   \ -} +do {                                                                                           \ +  (counter) = 0;                                                                               \ +  CDL_FOREACH2(head,el,next) { ++(counter); }                                                  \ +} while (0)  #define CDL_FOREACH(head,el)                                                                   \      CDL_FOREACH2(head,el,next)  #define CDL_FOREACH2(head,el,next)                                                             \ -    for(el=head;el;el=((el)->next==head ? 0L : (el)->next))  +    for ((el)=(head);el;(el)=(((el)->next==(head)) ? NULL : (el)->next))  #define CDL_FOREACH_SAFE(head,el,tmp1,tmp2)                                                    \      CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)  #define CDL_FOREACH_SAFE2(head,el,tmp1,tmp2,prev,next)                                         \ -  for((el)=(head), ((tmp1)=(head)?((head)->prev):NULL);                                        \ -      (el) && ((tmp2)=(el)->next, 1);                                                          \ -      ((el) = (((el)==(tmp1)) ? 0L : (tmp2)))) +  for ((el) = (head), (tmp1) = (head) ? (head)->prev : NULL;                                   \ +       (el) && ((tmp2) = (el)->next, 1);                                                       \ +       (el) = ((el) == (tmp1) ? NULL : (tmp2)))  #define CDL_SEARCH_SCALAR(head,out,field,val)                                                  \      CDL_SEARCH_SCALAR2(head,out,field,val,next) @@ -707,7 +971,7 @@ do {      CDL_FOREACH2(head,out,next) {                                                              \        if ((out)->field == (val)) break;                                                        \      }                                                                                          \ -} while(0)  +} while (0)  #define CDL_SEARCH(head,out,elt,cmp)                                                           \      CDL_SEARCH2(head,out,elt,cmp,next) @@ -717,13 +981,13 @@ do {      CDL_FOREACH2(head,out,next) {                                                              \        if ((cmp(out,elt))==0) break;                                                            \      }                                                                                          \ -} while(0)  +} while (0) -#define CDL_REPLACE_ELEM(head, el, add)                                                        \ +#define CDL_REPLACE_ELEM2(head, el, add, prev, next)                                           \  do {                                                                                           \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ + assert((head) != NULL);                                                                       \ + assert((el) != NULL);                                                                         \ + assert((add) != NULL);                                                                        \   if ((el)->next == (el)) {                                                                     \    (add)->next = (add);                                                                         \    (add)->prev = (add);                                                                         \ @@ -739,19 +1003,74 @@ do {   }                                                                                             \  } while (0) +#define CDL_REPLACE_ELEM(head, el, add)                                                        \ +    CDL_REPLACE_ELEM2(head, el, add, prev, next) + +#define CDL_PREPEND_ELEM2(head, el, add, prev, next)                                           \ +do {                                                                                           \ +  if (el) {                                                                                    \ +    assert((head) != NULL);                                                                    \ +    assert((add) != NULL);                                                                     \ +    (add)->next = (el);                                                                        \ +    (add)->prev = (el)->prev;                                                                  \ +    (el)->prev = (add);                                                                        \ +    (add)->prev->next = (add);                                                                 \ +    if ((head) == (el)) {                                                                      \ +      (head) = (add);                                                                          \ +    }                                                                                          \ +  } else {                                                                                     \ +    CDL_APPEND2(head, add, prev, next);                                                        \ +  }                                                                                            \ +} while (0) +  #define CDL_PREPEND_ELEM(head, el, add)                                                        \ +    CDL_PREPEND_ELEM2(head, el, add, prev, next) + +#define CDL_APPEND_ELEM2(head, el, add, prev, next)                                            \  do {                                                                                           \ - assert(head != NULL);                                                                         \ - assert(el != NULL);                                                                           \ - assert(add != NULL);                                                                          \ - (add)->next = (el);                                                                           \ - (add)->prev = (el)->prev;                                                                     \ - (el)->prev = (add);                                                                           \ - (add)->prev->next = (add);                                                                    \ - if ((head) == (el)) {                                                                         \ -  (head) = (add);                                                                              \ + if (el) {                                                                                     \ +  assert((head) != NULL);                                                                      \ +  assert((add) != NULL);                                                                       \ +  (add)->next = (el)->next;                                                                    \ +  (add)->prev = (el);                                                                          \ +  (el)->next = (add);                                                                          \ +  (add)->next->prev = (add);                                                                   \ + } else {                                                                                      \ +  CDL_PREPEND2(head, add, prev, next);                                                         \   }                                                                                             \ -} while (0)                                                                                    \ +} while (0) -#endif /* UTLIST_H */ +#define CDL_APPEND_ELEM(head, el, add)                                                         \ +    CDL_APPEND_ELEM2(head, el, add, prev, next) + +#ifdef NO_DECLTYPE +/* Here are VS2008 / NO_DECLTYPE replacements for a few functions */ +#undef CDL_INSERT_INORDER2 +#define CDL_INSERT_INORDER2(head,add,cmp,prev,next)                                            \ +do {                                                                                           \ +  if ((head) == NULL) {                                                                        \ +    (add)->prev = (add);                                                                       \ +    (add)->next = (add);                                                                       \ +    (head) = (add);                                                                            \ +  } else if ((cmp(head, add)) >= 0) {                                                          \ +    (add)->prev = (head)->prev;                                                                \ +    (add)->next = (head);                                                                      \ +    (add)->prev->next = (add);                                                                 \ +    (head)->prev = (add);                                                                      \ +    (head) = (add);                                                                            \ +  } else {                                                                                     \ +    char *_tmp = (char*)(head);                                                                \ +    while ((char*)(head)->next != _tmp && (cmp((head)->next, add)) < 0) {                      \ +      (head) = (head)->next;                                                                   \ +    }                                                                                          \ +    (add)->prev = (head);                                                                      \ +    (add)->next = (head)->next;                                                                \ +    (add)->next->prev = (add);                                                                 \ +    (head)->next = (add);                                                                      \ +    UTLIST_RS(head);                                                                           \ +  }                                                                                            \ +} while (0) +#endif /* NO_DECLTYPE */ + +#endif /* UTLIST_H */ | 
