diff options
Diffstat (limited to 'contrib')
120 files changed, 2868 insertions, 6079 deletions
diff --git a/contrib/libucl/CMakeLists.txt b/contrib/libucl/CMakeLists.txt deleted file mode 100644 index 5fe772a30f88..000000000000 --- a/contrib/libucl/CMakeLists.txt +++ /dev/null @@ -1,314 +0,0 @@ -PROJECT(libucl C) -CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR) - -SET(LIBUCL_VERSION_MAJOR 0) -SET(LIBUCL_VERSION_MINOR 5) -SET(LIBUCL_VERSION_PATCH 0) - -SET(LIBUCL_VERSION - "${LIBUCL_VERSION_MAJOR}.${LIBUCL_VERSION_MINOR}.${LIBUCL_VERSION_PATCH}") - -INCLUDE(CheckCCompilerFlag) -INCLUDE(CheckCSourceCompiles) -INCLUDE(FindOpenSSL) -INCLUDE(GNUInstallDirs) - -OPTION(ENABLE_URL_INCLUDE "Enable urls in ucl includes (requires libcurl or libfetch) [default: OFF]" OFF) -OPTION(ENABLE_URL_SIGN "Enable signatures check in ucl includes (requires openssl) [default: OFF]" OFF) -OPTION(BUILD_SHARED_LIBS "Build Shared Libraries [default: OFF]" OFF) -OPTION(ENABLE_LUA "Enable lua support [default: OFF]" OFF) -OPTION(ENABLE_LUAJIT "Enable luajit support [default: OFF]" OFF) -OPTION(ENABLE_UTILS "Enable building utility binaries [default: OFF]" OFF) - -# Find lua installation -MACRO(FindLua) - # Find lua libraries - UNSET(LUA_INCLUDE_DIR CACHE) - UNSET(LUA_LIBRARY CACHE) - CMAKE_PARSE_ARGUMENTS(LUA "" "VERSION_MAJOR;VERSION_MINOR;ROOT" "" ${ARGN}) - - IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - MESSAGE(FATAL_ERROR "Invalid FindLua invocation: ${ARGN}") - ENDIF() - - IF(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Check for luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR luajit.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/luajit-2.0" - "include/luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/luajit" - "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES luajit - "luajit-2.0" - "luajit2.0" - "luajit${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "luajit${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "luajit-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - - IF(NOT LUA_LIBRARY OR NOT LUA_INCLUDE_DIR) - MESSAGE(STATUS "Fallback from luajit to plain lua") - SET(ENABLE_LUAJIT "OFF") - MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR lua.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES lua - "lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - ENDIF() - ELSE(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Check for lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - FIND_PATH(LUA_INCLUDE_DIR lua.h - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES "include/lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "include/lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "include/lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - include/lua include - PATHS ${RSPAMD_DEFAULT_INCLUDE_PATHS} - ) - FIND_LIBRARY(LUA_LIBRARY - NAMES lua - "lua${LUA_VERSION_MAJOR}${LUA_VERSION_MINOR}" - "lua${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - "lua-${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}" - HINTS - "${RSPAMD_SEARCH_PATH}" "${LUA_ROOT}" - $ENV{LUA_DIR} - PATH_SUFFIXES lib64 lib - PATHS ${RSPAMD_DEFAULT_LIBRARY_PATHS} - DOC "Lua library" - ) - ENDIF(ENABLE_LUAJIT MATCHES "ON") - - IF(LUA_LIBRARY AND LUA_INCLUDE_DIR) - SET(LUA_FOUND 1) - IF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - SET(LUA_VERSION_MAJOR ${LUA_VERSION_MAJOR}) - SET(LUA_VERSION_MINOR ${LUA_VERSION_MINOR}) - ENDIF(NOT LUA_VERSION_MAJOR OR NOT LUA_VERSION_MINOR) - IF(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Found luajit ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - ELSE(ENABLE_LUAJIT MATCHES "ON") - MESSAGE(STATUS "Found lua ${LUA_VERSION_MAJOR}.${LUA_VERSION_MINOR}") - ENDIF(ENABLE_LUAJIT MATCHES "ON") - ENDIF(LUA_LIBRARY AND LUA_INCLUDE_DIR) -ENDMACRO() - -IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - LIST(APPEND CMAKE_REQUIRED_LIBRARIES rt) -ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") - -IF(ENABLE_URL_INCLUDE MATCHES "ON") - FIND_LIBRARY(LIBFETCH_LIBRARY NAMES fetch PATHS PATH_SUFFIXES lib64 lib - PATHS - ~/Library/Frameworks - /Library/Frameworks - /usr/local - /usr - /sw - /opt/local - /opt/csw - /opt - DOC "Path where the libfetch library can be found") - IF(LIBFETCH_LIBRARY) - FIND_FILE(HAVE_FETCH_H NAMES fetch.h PATHS /usr/include - /opt/include - /usr/local/include - DOC "Path to libfetch header") - ELSE(LIBFETCH_LIBRARY) - # Try to find libcurl - FIND_PACKAGE(CURL) - IF(NOT CURL_FOUND) - MESSAGE(WARNING "Neither libcurl nor libfetch were found, no support of URL includes in configuration") - ENDIF(NOT CURL_FOUND) - ENDIF(LIBFETCH_LIBRARY) -ENDIF(ENABLE_URL_INCLUDE MATCHES "ON") - -set(SYNC_BUILTINS_TEST_SOURCE [====[ -int main() -{ - unsigned long val; - - __sync_bool_compare_and_swap(&val, 0, 1); - __sync_add_and_fetch(&val, 1); - __sync_fetch_and_add(&val, 0); - __sync_sub_and_fetch(&val, 1); - - return 0; -} -]====]) - -CHECK_C_SOURCE_COMPILES("${SYNC_BUILTINS_TEST_SOURCE}" HAVE_ATOMIC_BUILTINS) -IF(NOT HAVE_ATOMIC_BUILTINS) - MESSAGE(WARNING "Libucl references could be thread-unsafe because atomic builtins are missing") -ENDIF(NOT HAVE_ATOMIC_BUILTINS) - -SET(CMAKE_C_WARN_FLAGS "") -CHECK_C_COMPILER_FLAG(-W SUPPORT_W) -CHECK_C_COMPILER_FLAG(-Wno-pointer-sign SUPPORT_WPOINTER_SIGN) -CHECK_C_COMPILER_FLAG(-Wno-unused-parameter SUPPORT_WUNUSED_PARAMETER) -IF(SUPPORT_W) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -W") -ENDIF(SUPPORT_W) -IF(SUPPORT_WPOINTER_SIGN) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-pointer-sign") -ENDIF(SUPPORT_WPOINTER_SIGN) -IF(SUPPORT_WUNUSED_PARAMETER) - SET(CMAKE_C_WARN_FLAGS "${CMAKE_C_WARN_FLAGS} -Wno-unused-parameter") -ENDIF(SUPPORT_WUNUSED_PARAMETER) - -SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_WARN_FLAGS}" ) - -IF(ENABLE_URL_SIGN MATCHES "ON") - IF(OPENSSL_FOUND) - SET(HAVE_OPENSSL 1) - INCLUDE_DIRECTORIES("${OPENSSL_INCLUDE_DIR}") - ENDIF(OPENSSL_FOUND) -ENDIF(ENABLE_URL_SIGN MATCHES "ON") - -SET(UCL_COMPILE_DEFS) -IF(HAVE_FETCH_H) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_FETCH_H=1) -ENDIF(HAVE_FETCH_H) -IF(CURL_FOUND) - LIST(APPEND UCL_COMPILE_DEFS -DCURL_FOUND=1) -ENDIF(CURL_FOUND) -IF(HAVE_OPENSSL) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_OPENSSL=1) -ENDIF(HAVE_OPENSSL) -IF(HAVE_ATOMIC_BUILTINS) - LIST(APPEND UCL_COMPILE_DEFS -DHAVE_ATOMIC_BUILTINS=1) -ENDIF(HAVE_ATOMIC_BUILTINS) - -SET(UCLSRC src/ucl_util.c - src/ucl_parser.c - src/ucl_emitter.c - src/ucl_emitter_streamline.c - src/ucl_emitter_utils.c - src/ucl_hash.c - src/ucl_schema.c - src/ucl_msgpack.c - src/ucl_sexp.c) - -SET(UCLHDR include/ucl.h - include/ucl++.h) - -SET (LIB_TYPE STATIC) -IF (BUILD_SHARED_LIBS) - SET (LIB_TYPE SHARED) -ENDIF (BUILD_SHARED_LIBS) -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) -TARGET_COMPILE_DEFINITIONS(ucl - PRIVATE - ${UCL_COMPILE_DEFS} -) - -IF(ENABLE_LUA MATCHES "ON") - IF(ENABLE_LUAJIT MATCHES "ON") - FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}") - IF(NOT LUA_FOUND) - MESSAGE(FATAL_ERROR "Lua not found, lua support is required") - ELSE(NOT LUA_FOUND) - INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}") - ENDIF(NOT LUA_FOUND) - ELSE(ENABLE_LUAJIT MATCHES "ON") - FindLua(VERSION_MAJOR "5" VERSION_MINOR "2" ROOT "${LUA_ROOT}") - IF(NOT LUA_FOUND) - FindLua(VERSION_MAJOR "5" VERSION_MINOR "1" ROOT "${LUA_ROOT}") - ENDIF(NOT LUA_FOUND) - IF(NOT LUA_FOUND) - MESSAGE(FATAL_ERROR "Lua not found, lua support is required") - ELSE(NOT LUA_FOUND) - INCLUDE_DIRECTORIES("${LUA_INCLUDE_DIR}") - ENDIF(NOT LUA_FOUND) - ENDIF(ENABLE_LUAJIT MATCHES "ON") - SET(UCL_LUA_SRC lua/lua_ucl.c) - ADD_LIBRARY(lua-ucl ${LIB_TYPE} ${UCL_LUA_SRC}) - ADD_LIBRARY(ucl::lua ALIAS lua-ucl) - IF(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl "${LUAJIT_LIBRARY}") - ELSE(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl "${LUA_LIBRARY}") - ENDIF(ENABLE_LUAJIT MATCHES "ON") - TARGET_LINK_LIBRARIES(lua-ucl ucl) - TARGET_INCLUDE_DIRECTORIES(lua-ucl PUBLIC include PRIVATE src uthash) - SET_TARGET_PROPERTIES(lua-ucl PROPERTIES - VERSION ${LIBUCL_VERSION} - SOVERSION ${LIBUCL_VERSION_MAJOR} - PUBLIC_HEADER include/lua_ucl.h) - INSTALL(TARGETS lua-ucl DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -ENDIF() - -IF(HAVE_FETCH_H) - TARGET_LINK_LIBRARIES(ucl fetch) -ELSE(HAVE_FETCH_H) - IF(CURL_FOUND) - TARGET_LINK_LIBRARIES(ucl ${CURL_LIBRARIES}) - ENDIF(CURL_FOUND) -ENDIF(HAVE_FETCH_H) -IF(ENABLE_URL_SIGN MATCHES "ON") - IF(OPENSSL_FOUND) - TARGET_LINK_LIBRARIES(ucl ${OPENSSL_LIBRARIES}) - ENDIF(OPENSSL_FOUND) -ENDIF(ENABLE_URL_SIGN MATCHES "ON") - -IF(UNIX) - TARGET_LINK_LIBRARIES(ucl -lm) -ENDIF(UNIX) - -SET_TARGET_PROPERTIES(ucl PROPERTIES - PUBLIC_HEADER "${UCLHDR}") - -INSTALL(TARGETS ucl DESTINATION ${CMAKE_INSTALL_LIBDIR} - PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) - -IF(ENABLE_UTILS MATCHES "ON") - ADD_SUBDIRECTORY(utils) -ENDIF() - diff --git a/contrib/libucl/ChangeLog.md b/contrib/libucl/ChangeLog.md deleted file mode 100644 index cba29aa9a7b5..000000000000 --- a/contrib/libucl/ChangeLog.md +++ /dev/null @@ -1,103 +0,0 @@ -# Version history - -## Libucl 0.5 - -- Streamline emitter has been added, so it is now possible to output partial `ucl` objects -- Emitter now is more flexible due to emitter_context structure - -### 0.5.1 -- Fixed number of bugs and memory leaks - -### 0.5.2 - -- Allow userdata objects to be emitted and destructed -- Use userdata objects to store lua function references - -### Libucl 0.6 - -- Reworked macro interface - -### Libucl 0.6.1 - -- Various utilities fixes - -### Libucl 0.7.0 - -- Move to klib library from uthash to reduce memory overhead and increase performance - -### Libucl 0.7.1 - -- Added safe iterators API - -### Libucl 0.7.2 - -- Fixed serious bugs in schema and arrays iteration - -### Libucl 0.7.3 - -- Fixed a bug with macros that come after an empty object -- Fixed a bug in include processing when an incorrect variable has been destroyed (use-after-free) - -### Libucl 0.8.0 - -- Allow to save comments and macros when parsing UCL documents -- C++ API -- Python bindings (by Eitan Adler) -- Add msgpack support for parser and emitter -- Add Canonical S-expressions parser for libucl -- CLI interface for parsing and validation (by Maxim Ignatenko) -- Implement include with priority -- Add 'nested' functionality to .include macro (by Allan Jude) -- Allow searching an array of paths for includes (by Allan Jude) -- Add new .load macro (by Allan Jude) -- Implement .inherit macro (#100) -- Add merge strategies -- Add schema validation to lua API -- Add support for external references to schema validation -- Add coveralls integration to libucl -- Implement tests for 80% of libucl code lines -- Fix tonns of minor and major bugs -- Improve documentation -- Rework function names to the common conventions (old names are preserved for backwards compatibility) -- Add Coverity scan integration -- Add fuzz tests - -**Incompatible changes**: - -- `ucl_object_emit_full` now accepts additional argument `comments` that could be used to emit comments with UCL output - -### Libucl 0.8.1 - -- Create ucl_parser_add_file_full() to be able to specify merge mode and parser type (by Allan Jude) -- C++ wrapper improvements (by @ftilde) -- C++ wrapper: add convenience method at() and lookup() (by Yonghee Kim) -- C++ wrapper: add assignment operator to Ucl class (by Yonghee Kim) -- C++ wrapper: support variables in parser (by Yonghee Kim) -- C++ wrapper: refactoring C++ interface (by Yonghee Kim): - - use auto variables (if possible) - - remove dangling expressions - - use std::set::emplace instead of std::set::insert - - not use std::move in return statement; considering copy elision -- C++ wrapper: fix compilation error and warnings (by Zhe Wang) -- C++ wrapper: fix iteration over objects in which the first value is `false` (by Zhe Wang) -- C++ wrapper: Macro helper functions (by Chris Meacham) -- C++ wrapper: Changing the duplicate strategy in the C++ API (by Chris Meacham) -- C++ wrapper: Added access functions for the size of a UCL_ARRAY (by Chris Meacham) -- Fix caseless comparison -- Fix include when EPERM is issued -- Fix Windows build -- Allow to reserve space in arrays and hashes -- Fix bug with including of empty files -- Move to mum_hash from xxhash -- Fix msgpack on non-x86 -- python: Add support to Python 3 (by Denis Volpato Martins) -- python: Add support for Python 2.6 tests (by Denis Volpato Martins) -- python: Implement validation function and tests (by Denis Volpato Martins) -- python: Added UCL_NULL handling and tests (by Denis Volpato Martins) -- Fix schema validation for patternProperties with object data (by Denis Volpato Martins) -- Remove the dependency on NBBY, add missing <strings.h> include (by Ed Schouten) -- Allow to emit msgpack from Lua -- Performance improvements in Lua API -- Allow to pass opaque objects in Lua API for transparent C passthrough -- Various bugs fixed -- Couple of memory leaks plugged
\ No newline at end of file diff --git a/contrib/libucl/FREEBSD-Xlist b/contrib/libucl/FREEBSD-Xlist new file mode 100644 index 000000000000..6d8cb4ff8f5b --- /dev/null +++ b/contrib/libucl/FREEBSD-Xlist @@ -0,0 +1,40 @@ +.github +.gitignore +CMakeLists.txt +ChangeLog.md +Makefile.am +Makefile.unix +Makefile.w32 +README.md +autogen.sh +configure.ac +doc/Makefile.am +doc/api.md +doc/lua_api.md +doc/pandoc.template +examples/ucl_cpp.cc +haskell/hucl.hs +libucl.pc.in +lua/Makefile.am +lua/libucl.rockspec.in +m4/.gitignore +m4/ax_lua.m4 +m4/gcov.m4 +python/MANIFEST.in +python/setup.py +python/src/uclmodule.c +python/tests/__init__.py +python/tests/compat.py +python/tests/test_dump.py +python/tests/test_example.py +python/tests/test_load.py +python/tests/test_validation.py +python/ucl.pyi +src/Makefile.am +stamp-h.in +tests/Makefile.am +utils/CMakeLists.txt +utils/Makefile.am +utils/chargen.c +utils/objdump.c +utils/ucl-tool.c diff --git a/contrib/libucl/FREEBSD-upgrade b/contrib/libucl/FREEBSD-upgrade new file mode 100644 index 000000000000..b80736d7877b --- /dev/null +++ b/contrib/libucl/FREEBSD-upgrade @@ -0,0 +1,39 @@ +# FreeBSD libucl import instruction +# +# At least the following ports are required when importing libucl: +# - devel/autoconf +# - devel/automake +# - devel/git +# - devel/gmake +# - devel/libtool +# +# 1. Vendor import +# +# $ git clone https://github.com/vstakhov/libucl.git /tmp/libucl +# $ cd /tmp/libucl +# $ git checkout <REF_BRANCH_TO_BE_IMPORTED> +# $ cd /usr/src +# $ git checkout vendor/libucl +# $ rsync -va --delete --exclude=.git /tmp/libucl/ /usr/src/contrib/libucl/ +# $ git add . +# $ git commit -m "vendor import libucl <REF_BRANCH_TO_BE_IMPORTED>" +# $ git tag -a vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> -m "vendor import libucl <REF_BRANCH_TO_BE_IMPORTED>" +# $ git push --follow-tags freebsd vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# +# 2. Test +# +# $ cd /usr/src +# $ git checkout vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# $ ./autogen.sh +# $ ./configure +# $ gmake +# $ gmake check +# $ gmake clean +# +# 3. Merge vendor tree +# +# $ git subtree merge -P contrib/libucl vendor/libucl/<REF_BRANCH_TO_BE_IMPORTED> +# $ sh -c 'for F in `cat FREEBSD-Xlist | grep -v FreeBSD`; do rm -rf ./$F ; done' +# +# Recheck if there were any new files were added which are not necessary in the +# contrib tree. If so, remove them and also add them to the FREEBSD-Xlist file. diff --git a/contrib/libucl/Makefile.am b/contrib/libucl/Makefile.am deleted file mode 100644 index 5b51bcc3b468..000000000000 --- a/contrib/libucl/Makefile.am +++ /dev/null @@ -1,81 +0,0 @@ -ACLOCAL_AMFLAGS = -I m4 -EXTRA_DIST = uthash klib README.md - -pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libucl.pc - -if LUA_SUB - LUA_SUBDIR = lua -endif - -COVERAGE_INFO_FILE = $(top_builddir)/coverage.info -COVERAGE_REPORT_DIR = $(top_builddir)/coverage - -.PHONY = coverage-requirement-check clean-coverage-report - -coverage-requirement-check: - @if test ! -e $(GCOV); then \ - echo "Cannot find $(GCOV). Please install gcov."; \ - exit 1; \ - fi - -coverage: coverage-requirement-check clean-coverage coverage-build coverage-check coverage-report - @echo "Please execute 'make clean' before 'make' or 'make check' to remove instrumented object files(compiled with -O0 etc.). Note that 'make clean' also remove coverage data." - -coverage-build: coverage-requirement-check - @if test `find $(top_builddir) -name "*.gcno" | wc -l` -eq 0; then \ - echo "Start to remove old non-instrumented object files..."; \ - $(MAKE) $(AM_MAKEFLAGS) clean; \ - echo "Successfully removed old non-instrumented object files."; \ - fi - @echo "Start to build libraries with coverage options..." - $(MAKE) $(AM_MAKEFLAGS) \ - CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \ - CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \ - LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \ - LIBS="$(LIBS) $(COVERAGE_LIBS)" - @echo "Successfully built libraries with coverage options." - -coverage-check: coverage-requirement-check - @echo "Start to run tests with instrumented libraries..." - $(MAKE) $(AM_MAKEFLAGS) check \ - CFLAGS="$(CFLAGS) $(COVERAGE_CFLAGS) $(COVERAGE_OPTFLAGS)" \ - CXXFLAGS="$(CXXFLAGS) $(COVERAGE_CXXFLAGS) $(COVERAGE_OPTFLAGS)" \ - LDFLAGS="$(LDFLAGS) $(COVERAGE_LDFLAGS)" \ - LIBS="$(LIBS) $(COVERAGE_LIBS)" - @echo "Successfully run tests with instrumented libraries." - -coverage-lcov: coverage-check coverage-requirement-check - $(LCOV) --capture \ - --directory "$(top_builddir)/" \ - --output-file $(COVERAGE_INFO_FILE) \ - --gcov-tool $(GCOV) \ - --compat-libtool --checksum - $(LCOV) --extract $(COVERAGE_INFO_FILE) `pwd`/src/ucl_\* \ - --output-file $(COVERAGE_INFO_FILE) - -coverage-report: coverage-lcov - @echo "Start to create coverage reports..." - $(GENHTML) --prefix "$(top_srcdir)" \ - --output-directory $(COVERAGE_REPORT_DIR) \ - --title $(PACKAGE_NAME) \ - --legend --show-details \ - $(GENHTML_OPTIONS) \ - $(COVERAGE_INFO_FILE) - @echo "Successfully created coverage reports into $(COVERAGE_REPORT_DIR) directory." - -clean-coverage-report: - -rm -rf $(COVERAGE_INFO_FILE) - -rm -rf $(COVERAGE_REPORT_DIR) - -clean-coverage: clean-coverage-report - -$(LCOV) --gcov-tool $(GCOV) --zerocounters --directory $(top_builddir) - @if xargs --version 2>/dev/null; then \ - find $(top_builddir) -name "*.gcno" | xargs --no-run-if-empty rm; \ - else \ - find $(top_builddir) -name "*.gcno" | xargs rm; \ - fi - -clean-local: clean-coverage - -SUBDIRS = src tests utils doc $(LUA_SUBDIR) diff --git a/contrib/libucl/Makefile.unix b/contrib/libucl/Makefile.unix deleted file mode 100644 index 0653d4843f7e..000000000000 --- a/contrib/libucl/Makefile.unix +++ /dev/null @@ -1,89 +0,0 @@ -CC ?= gcc -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 -VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)" -SONAME = libucl.so -SONAME_FULL = $(SONAME).$(MAJOR_VERSION) -OBJDIR ?= .obj -TESTDIR ?= tests -SRCDIR ?= src -INCLUDEDIR ?= include -MKDIR ?= mkdir -INSTALL ?= install -RM ?= rm -RMDIR ?= rmdir -LN ?= ln -LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm -LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl -LD_ADD ?= -lrt -COPT_FLAGS ?= -O2 -HDEPS = $(SRCDIR)/ucl_hash.h \ - $(SRCDIR)/ucl_chartable.h \ - $(SRCDIR)/ucl_internal.h \ - $(INCLUDEDIR)/ucl.h \ - $(SRCDIR)/mum.h -OBJECTS = $(OBJDIR)/ucl_hash.o \ - $(OBJDIR)/ucl_util.o \ - $(OBJDIR)/ucl_parser.o \ - $(OBJDIR)/ucl_emitter.o \ - $(OBJDIR)/ucl_schema.o - -all: $(OBJDIR) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME): $(OBJDIR)/$(SONAME_FULL) - $(LN) -sf $(SONAME_FULL) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME_FULL): $(OBJECTS) - $(CC) -o $(OBJDIR)/$(SONAME_FULL) $(OBJECTS) $(LD_SHARED_FLAGS) $(LDFLAGS) $(SSL_LIBS) $(FETCH_LIBS) - -$(OBJDIR): - @$(MKDIR) -p $(OBJDIR) - -# Compile rules -$(OBJDIR)/ucl_util.o: $(SRCDIR)/ucl_util.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_util.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_util.c -$(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c -$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c -$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c -$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c - -clean: - $(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME_FULL) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate $(OBJDIR)/test_schema || true - $(RMDIR) $(OBJDIR) - -# Utils - -chargen: utils/chargen.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/chargen $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/chargen.c -objdump: utils/objdump.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/objdump $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/objdump.c $(LD_UCL_FLAGS) - -# Tests - -test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema - -run-test: test - TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate $(OBJDIR)/test_schema - -$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_schema: $(TESTDIR)/test_schema.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_schema $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_schema.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD) -$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_generate $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_generate.c $(LD_UCL_FLAGS) $(LD_ADD) - -install: $(OBJDIR)/$(SONAME) - $(INSTALL) -m0755 $(SONAME) $(DESTDIR)/lib/$(SONAME) - $(INSTALL) -m0644 include/ucl.h $(DESTDIR)/include/ucl.h - -.PHONY: clean $(OBJDIR) diff --git a/contrib/libucl/Makefile.w32 b/contrib/libucl/Makefile.w32 deleted file mode 100644 index 5d9398bf1988..000000000000 --- a/contrib/libucl/Makefile.w32 +++ /dev/null @@ -1,92 +0,0 @@ -CC ?= gcc -DESTDIR ?= /usr/local -LD ?= gcc -C_COMMON_FLAGS ?= -fPIC -Wall -W -Wno-unused-parameter -Wno-pointer-sign -I./include -I./uthash -I./src -MAJOR_VERSION = 0 -MINOR_VERSION = 2 -PATCH_VERSION = 9 -VERSION = "$(MAJOR_VERSION).$(MINOR_VERSION).$(PATCH_VERSION)" -SONAME = libucl.dll -OBJDIR ?= .obj -TESTDIR ?= tests -SRCDIR ?= src -INCLUDEDIR ?= include -MKDIR ?= mkdir -INSTALL ?= install -RM ?= rm -RMDIR ?= rmdir -ifeq (Windows_NT, $(OS)) -LN ?= ln -else -LN ?= rem ln -endif -LD_SHARED_FLAGS ?= -Wl,-soname,$(SONAME) -shared -lm -LD_UCL_FLAGS ?= -L$(OBJDIR) -Wl,-rpath,$(OBJDIR) -lucl -LD_ADD ?= -lrt -COPT_FLAGS ?= -O2 -HDEPS = $(SRCDIR)/ucl_hash.h \ - $(SRCDIR)/ucl_chartable.h \ - $(SRCDIR)/ucl_internal.h \ - $(INCLUDEDIR)/ucl.h \ - $(SRCDIR)/mum.h -OBJECTS = $(OBJDIR)/ucl_hash.o \ - $(OBJDIR)/ucl_util.o \ - $(OBJDIR)/ucl_parser.o \ - $(OBJDIR)/ucl_emitter.o \ - $(OBJDIR)/ucl_emitter_utils.o \ - $(OBJDIR)/ucl_schema.o - -all: $(OBJDIR) $(OBJDIR)/$(SONAME) - -$(OBJDIR)/$(SONAME): $(OBJECTS) - $(CC) -o $(OBJDIR)/$(SONAME) $(OBJECTS) $(LD_SHARED_FLAGS) $(LDFLAGS) $(SSL_LIBS) $(FETCH_LIBS) - -$(OBJDIR): - @$(MKDIR) -p $(OBJDIR) - -# Compile rules -$(OBJDIR)/ucl_util.o: $(SRCDIR)/ucl_util.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_util.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_util.c -$(OBJDIR)/ucl_parser.o: $(SRCDIR)/ucl_parser.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_parser.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_parser.c -$(OBJDIR)/ucl_emitter.o: $(SRCDIR)/ucl_emitter.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter.c -$(OBJDIR)/ucl_emitter_utils.o: $(SRCDIR)/ucl_emitter_utils.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_emitter_utils.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_emitter_utils.c -$(OBJDIR)/ucl_hash.o: $(SRCDIR)/ucl_hash.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_hash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_hash.c -$(OBJDIR)/ucl_schema.o: $(SRCDIR)/ucl_schema.c $(HDEPS) - $(CC) -o $(OBJDIR)/ucl_schema.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/ucl_schema.c -$(OBJDIR)/xxhash.o: $(SRCDIR)/xxhash.c $(HDEPS) - $(CC) -o $(OBJDIR)/xxhash.o $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) -c $(SRCDIR)/xxhash.c - -clean: - $(RM) $(OBJDIR)/*.o $(OBJDIR)/$(SONAME) $(OBJDIR)/$(SONAME) $(OBJDIR)/chargen $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/objdump $(OBJDIR)/test_generate - $(RMDIR) $(OBJDIR) - -# Utils - -chargen: utils/chargen.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/chargen $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/chargen.c -objdump: utils/objdump.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/objdump $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) utils/objdump.c $(LD_UCL_FLAGS) - -# Tests - -test: $(OBJDIR) $(OBJDIR)/$(SONAME) $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate - -run-test: test - TEST_DIR=$(TESTDIR) $(TESTDIR)/run_tests.sh $(OBJDIR)/test_basic $(OBJDIR)/test_speed $(OBJDIR)/test_generate - -$(OBJDIR)/test_basic: $(TESTDIR)/test_basic.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_basic $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_basic.c $(LD_UCL_FLAGS) -$(OBJDIR)/test_speed: $(TESTDIR)/test_speed.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_speed $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_speed.c $(LD_UCL_FLAGS) $(LD_ADD) -$(OBJDIR)/test_generate: $(TESTDIR)/test_generate.c $(OBJDIR)/$(SONAME) - $(CC) -o $(OBJDIR)/test_generate $(CPPFLAGS) $(COPT_FLAGS) $(CFLAGS) $(C_COMMON_FLAGS) $(SSL_CFLAGS) $(FETCH_FLAGS) $(LDFLAGS) $(TESTDIR)/test_generate.c $(LD_UCL_FLAGS) $(LD_ADD) - -install: $(OBJDIR)/$(SONAME) - $(INSTALL) -m0755 $(SONAME) $(DESTDIR)/lib/$(SONAME) - $(INSTALL) -m0644 include/ucl.h $(DESTDIR)/include/ucl.h - -.PHONY: clean $(OBJDIR) diff --git a/contrib/libucl/README.md b/contrib/libucl/README.md deleted file mode 100644 index 53d8a651d73b..000000000000 --- a/contrib/libucl/README.md +++ /dev/null @@ -1,418 +0,0 @@ -# LIBUCL - -[](https://circleci.com/gh/vstakhov/libucl) -[](https://scan.coverity.com/projects/4138) -[](https://coveralls.io/github/vstakhov/libucl?branch=master) - -**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* - -- [Introduction](#introduction) -- [Basic structure](#basic-structure) -- [Improvements to the json notation](#improvements-to-the-json-notation) - - [General syntax sugar](#general-syntax-sugar) - - [Automatic arrays creation](#automatic-arrays-creation) - - [Named keys hierarchy](#named-keys-hierarchy) - - [Convenient numbers and booleans](#convenient-numbers-and-booleans) -- [General improvements](#general-improvements) - - [Comments](#comments) - - [Macros support](#macros-support) - - [Variables support](#variables-support) - - [Multiline strings](#multiline-strings) - - [Single quoted strings](#single-quoted-strings) -- [Emitter](#emitter) -- [Validation](#validation) -- [Performance](#performance) -- [Conclusion](#conclusion) - -## Introduction - -This document describes the main features and principles of the configuration -language called `UCL` - universal configuration language. - -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. -For example, you can write the same configuration in the following ways: - -* in nginx like: - -```nginx -param = value; -section { - param = value; - param1 = value1; - flag = true; - number = 10k; - time = 0.2s; - string = "something"; - subsection { - host = { - host = "hostname"; - port = 900; - } - host = { - host = "hostname"; - port = 901; - } - } -} -``` - -* or in JSON: - -```json -{ - "param": "value", - "section": { - "param": "value", - "param1": "value1", - "flag": true, - "number": 10000, - "time": "0.2s", - "string": "something", - "subsection": { - "host": [ - { - "host": "hostname", - "port": 900 - }, - { - "host": "hostname", - "port": 901 - } - ] - } - } -} -``` - -## Improvements to the json notation. - -There are various things that make ucl configuration more convenient for editing than strict json: - -### General syntax sugar - -* Braces are not necessary to enclose a top object: it is automatically treated as an object: - -```json -"key": "value" -``` -is equal to: -```json -{"key": "value"} -``` - -* There is no requirement of quotes for strings and keys, moreover, `:` may be replaced `=` or even be skipped for objects: - -```nginx -key = value; -section { - key = value; -} -``` -is equal to: -```json -{ - "key": "value", - "section": { - "key": "value" - } -} -``` - -* No commas mess: you can safely place a comma or semicolon for the last element in an array or an object: - -```json -{ - "key1": "value", - "key2": "value", -} -``` -### Automatic arrays creation - -* Non-unique keys in an object are allowed and are automatically converted to the arrays internally: - -```json -{ - "key": "value1", - "key": "value2" -} -``` -is converted to: -```json -{ - "key": ["value1", "value2"] -} -``` - -### Named keys hierarchy - -UCL accepts named keys and organize them into objects hierarchy internally. Here is an example of this process: -```nginx -section "blah" { - key = value; -} -section foo { - key = value; -} -``` - -is converted to the following object: - -```nginx -section { - blah { - key = value; - } - foo { - key = value; - } -} -``` - -Plain definitions may be more complex and contain more than a single level of nested objects: - -```nginx -section "blah" "foo" { - key = value; -} -``` - -is presented as: - -```nginx -section { - blah { - foo { - key = value; - } - } -} -``` - -### Convenient numbers and booleans - -* Numbers can have suffixes to specify standard multipliers: - + `[kKmMgG]` - standard 10 base multipliers (so `1k` is translated to 1000) - + `[kKmMgG]b` - 2 power multipliers (so `1kb` is translated to 1024) - + `[s|min|d|w|y]` - time multipliers, all time values are translated to float number of seconds, for example `10min` is translated to 600.0 and `10ms` is translated to 0.01 -* Hexadecimal integers can be used by `0x` prefix, for example `key = 0xff`. However, floating point values can use decimal base only. -* Booleans can be specified as `true` or `yes` or `on` and `false` or `no` or `off`. -* It is still possible to treat numbers and booleans as strings by enclosing them in double quotes. - -## General improvements - -### Comments - -UCL supports different style of comments: - -* single line: `#` -* multiline: `/* ... */` - -Multiline comments may be nested: -```c -# Sample single line comment -/* - some comment - /* nested comment */ - end of comment -*/ -``` - -### Macros support - -UCL supports external macros both multiline and single line ones: -```nginx -.macro_name "sometext"; -.macro_name { - Some long text - .... -}; -``` - -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 -options: - -```nginx -.macro_name(param=value) "something"; -.macro_name(param={key=value}) "something"; -.macro_name(.include "params.conf") "something"; -.macro_name(#this is multiline macro -param = [value1, value2]) "something"; -.macro_name(key="()") "something"; -``` - -UCL also provide a convenient `include` macro to load content from another files -to the current UCL object. This macro accepts either path to file: - -```nginx -.include "/full/path.conf" -.include "./relative/path.conf" -.include "${CURDIR}/path.conf" -``` - -or URL (if ucl is built with url support provided by either `libcurl` or `libfetch`): - - .include "http://example.com/file.conf" - -`.include` macro supports a set of options: - -* `try` (default: **false**) - if this option is `true` than UCL treats errors on loading of -this file as non-fatal. For example, such a file can be absent but it won't stop the parsing -of the top-level document. -* `sign` (default: **false**) - if this option is `true` UCL loads and checks the signature for -a file from path named `<FILEPATH>.sig`. Trusted public keys should be provided for UCL API after -parser is created but before any configurations are parsed. -* `glob` (default: **false**) - if this option is `true` UCL treats the filename as GLOB pattern and load -all files that matches the specified pattern (normally the format of patterns is defined in `glob` manual page -for your operating system). This option is meaningless for URL includes. -* `url` (default: **true**) - allow URL includes. -* `path` (default: empty) - A UCL_ARRAY of directories to search for the include file. -Search ends after the first match, unless `glob` is true, then all matches are included. -* `prefix` (default false) - Put included contents inside an object, instead -of loading them into the root. If no `key` is provided, one is automatically generated based on each files basename() -* `key` (default: <empty string>) - Key to load contents of include into. If -the key already exists, it must be the correct type -* `target` (default: object) - Specify if the `prefix` `key` should be an -object or an array. -* `priority` (default: 0) - specify priority for the include (see below). -* `duplicate` (default: 'append') - specify policy of duplicates resolving: - - `append` - default strategy, if we have new object of higher priority then it replaces old one, if we have new object with less priority it is ignored completely, and if we have two duplicate objects with the same priority then we have a multi-value key (implicit array) - - `merge` - if we have object or array, then new keys are merged inside, if we have a plain object then an implicit array is formed (regardless of priorities) - - `error` - create error on duplicate keys and stop parsing - - `rewrite` - always rewrite an old value with new one (ignoring priorities) - -Priorities are used by UCL parser to manage the policy of objects rewriting during including other files -as following: - -* If we have two objects with the same priority then we form an implicit array -* If a new object has bigger priority then we overwrite an old one -* If a new object has lower priority then we ignore it - -By default, the priority of top-level object is set to zero (lowest priority). Currently, -you can define up to 16 priorities (from 0 to 15). Includes with bigger priorities will -rewrite keys from the objects with lower priorities as specified by the policy. The priority -of the top-level or any other object can be changed with the `.priority` macro, which has no -options and takes the new priority: - -``` -# Default priority: 0. -foo = 6 -.priority 5 -# The following will have priority 5. -bar = 6 -baz = 7 -# The following will be included with a priority of 3, 5, and 6 respectively. -.include(priority=3) "path.conf" -.include(priority=5) "equivalent-path.conf" -.include(priority=6) "highpriority-path.conf" -``` - -### Variables support - -UCL supports variables in input. Variables are registered by a user of the UCL parser and can be presented in the following forms: - -* `${VARIABLE}` -* `$VARIABLE` - -UCL currently does not support nested variables. To escape variables one could use double dollar signs: - -* `$${VARIABLE}` is converted to `${VARIABLE}` -* `$$VARIABLE` is converted to `$VARIABLE` - -However, if no valid variables are found in a string, no expansion will be performed (and `$$` thus remains unchanged). This may be a subject -to change in future libucl releases. - -### Multiline strings - -UCL can handle multiline strings as well as single line ones. It uses shell/perl like notation for such objects: -``` -key = <<EOD -some text -splitted to -lines -EOD -``` - -In this example `key` will be interpreted as the following string: `some text\nsplitted to\nlines`. -Here are some rules for this syntax: - -* Multiline terminator must start just after `<<` symbols and it must consist of capital letters only (e.g. `<<eof` or `<< EOF` won't work); -* Terminator must end with a single newline character (and no spaces are allowed between terminator and newline character); -* To finish multiline string you need to include a terminator string just after newline and followed by a newline (no spaces or other characters are allowed as well); -* The initial and the final newlines are not inserted to the resulting string, but you can still specify newlines at the beginning and at the end of a value, for example: - -``` -key <<EOD - -some -text - -EOD -``` - -### Single quoted strings - -It is possible to use single quoted strings to simplify escaping rules. All values passed in single quoted strings are *NOT* escaped, with two exceptions: a single `'` character just before `\` character, and a newline character just after `\` character that is ignored. - -``` -key = 'value'; # Read as value -key = 'value\n\'; # Read as value\n\ -key = 'value\''; # Read as value' -key = 'value\ -bla'; # Read as valuebla -``` - -## Emitter - -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. - -## Validation - -UCL allows validation of objects. It uses the same schema that is used for json: [json schema v4](http://json-schema.org). UCL supports the full set of json schema with the exception of remote references. This feature is unlikely useful for configuration objects. Of course, a schema definition can be in UCL format instead of JSON that simplifies schemas writing. Moreover, since UCL supports multiple values for keys in an object it is possible to specify generic integer constraints `maxValues` and `minValues` to define the limits of values count in a single key. UCL currently is not absolutely strict about validation schemas themselves, therefore UCL users should supply valid schemas (as it is defined in json-schema draft v4) to ensure that the input objects are validated properly. - -## Performance - -Are UCL parser and emitter fast enough? Well, there are some numbers. -I got a 19Mb file that consist of ~700 thousand lines of json (obtained via -http://www.json-generator.com/). Then I checked jansson library that performs json -parsing and emitting and compared it with UCL. Here are results: - -``` -jansson: parsed json in 1.3899 seconds -jansson: emitted object in 0.2609 seconds - -ucl: parsed input in 0.6649 seconds -ucl: emitted config in 0.2423 seconds -ucl: emitted json in 0.2329 seconds -ucl: emitted compact json in 0.1811 seconds -ucl: emitted yaml in 0.2489 seconds -``` - -So far, UCL seems to be significantly faster than jansson on parsing and slightly faster on emitting. Moreover, -UCL compiled with optimizations (-O3) performs significantly faster: -``` -ucl: parsed input in 0.3002 seconds -ucl: emitted config in 0.1174 seconds -ucl: emitted json in 0.1174 seconds -ucl: emitted compact json in 0.0991 seconds -ucl: emitted yaml in 0.1354 seconds -``` - -You can do your own benchmarks by running `make check` in libucl top directory. - -## Conclusion - -UCL has clear design that should be very convenient for reading and writing. At the same time it is compatible with -JSON language and therefore can be used as a simple JSON parser. Macro logic provides an ability to extend configuration -language (for example by including some lua code) and comments allow to disable or enable the parts of a configuration -quickly. diff --git a/contrib/libucl/autogen.sh b/contrib/libucl/autogen.sh deleted file mode 100755 index 68f4a174b46e..000000000000 --- a/contrib/libucl/autogen.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -autoreconf -i diff --git a/contrib/libucl/configure.ac b/contrib/libucl/configure.ac deleted file mode 100644 index 731b7113e689..000000000000 --- a/contrib/libucl/configure.ac +++ /dev/null @@ -1,188 +0,0 @@ -m4_define([maj_ver], [0]) -m4_define([med_ver], [8]) -m4_define([min_ver], [1]) -m4_define([so_version], [6:0:1]) -m4_define([ucl_version], [maj_ver.med_ver.min_ver]) - -AC_INIT([libucl],[ucl_version],[https://github.com/vstakhov/libucl],[libucl]) -AC_CONFIG_SRCDIR([configure.ac]) -AM_INIT_AUTOMAKE([1.11 foreign -Wall -Wportability no-dist-gzip dist-xz]) -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -UCL_VERSION=ucl_version -SO_VERSION=so_version - -AC_SUBST(UCL_VERSION) -AC_SUBST(SO_VERSION) - -AC_PROG_CC_C99 -AM_PROG_CC_C_O -AM_PROG_AR -LT_INIT -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([config.h]) - -AC_C_CONST -AC_TYPE_SIZE_T - -AC_CHECK_HEADERS_ONCE([fcntl.h unistd.h]) -AC_TYPE_OFF_T -AC_FUNC_MMAP -AC_CHECK_HEADERS_ONCE([fcntl.h]) -AC_CHECK_HEADERS_ONCE([sys/types.h]) -AC_CHECK_HEADERS_ONCE([sys/stat.h]) -AC_CHECK_HEADERS_ONCE([sys/param.h]) -AC_CHECK_HEADERS_ONCE([sys/mman.h]) -AC_CHECK_HEADERS_ONCE([stdlib.h]) -AC_CHECK_HEADERS_ONCE([stddef.h]) -AC_CHECK_HEADERS_ONCE([stdarg.h]) -AC_CHECK_HEADERS_ONCE([stdbool.h]) -AC_CHECK_HEADERS_ONCE([stdint.h]) -AC_CHECK_HEADERS_ONCE([string.h]) -AC_CHECK_HEADERS_ONCE([strings.h]) -AC_CHECK_HEADERS_ONCE([unistd.h]) -AC_CHECK_HEADERS_ONCE([ctype.h]) -AC_CHECK_HEADERS_ONCE([errno.h]) -AC_CHECK_HEADERS_ONCE([limits.h]) -AC_CHECK_HEADERS_ONCE([libgen.h]) -AC_CHECK_HEADERS_ONCE([stdio.h]) -AC_CHECK_HEADERS_ONCE([float.h]) -AC_CHECK_HEADERS_ONCE([math.h]) -AC_CHECK_HEADERS_ONCE([endian.h sys/endian.h machine/endian.h]) - -dnl Example of default-disabled feature -AC_ARG_ENABLE([urls], AS_HELP_STRING([--enable-urls], - [Enable URLs fetch (requires libfetch or libcurl) @<:@default=no@:>@]), [], - [enable_urls=no]) -AC_ARG_ENABLE([regex], AS_HELP_STRING([--enable-regex], - [Enable regex checking for schema @<:@default=yes@:>@]), [], - [enable_regex=yes]) -AC_ARG_ENABLE([signatures], AS_HELP_STRING([--enable-signatures], - [Enable signatures check (requires openssl) @<:@default=no@:>@]), [], - [enable_signatures=no]) -AC_ARG_ENABLE([lua], AS_HELP_STRING([--enable-lua], - [Enable lua API build (requires lua libraries and headers) @<:@default=no@:>@]), [], - [enable_lua=no]) -AC_ARG_ENABLE([utils], - AS_HELP_STRING([--enable-utils], [Build and install utils @<:@default=no@:>@]), - [case "${enableval}" in - yes) utils=true ;; - no) utils=false ;; - *) AC_MSG_ERROR([bad value ${enableval} for --enable-utils]) ;; - esac],[utils=false]) -AM_CONDITIONAL([UTILS], [test x$utils = xtrue]) - -AS_IF([test "x$enable_signatures" = "xyes"], [ - AC_SEARCH_LIBS([CRYPTO_new_ex_data], [crypto], [ - AC_DEFINE(HAVE_OPENSSL, 1, [Define to 1 if you have the 'crypto' library (-lcrypto).]) - LIBCRYPTO_LIB="-lcrypto" - LIBS_EXTRA="${LIBS_EXTRA} -lcrypto" - ], [AC_MSG_ERROR([unable to find the CRYPTO_new_ex_data() function])]) -]) -AC_SUBST(LIBCRYPTO_LIB) -AC_PATH_PROG(PANDOC, pandoc, [/non/existent]) - -AC_SEARCH_LIBS([clock_gettime], [rt], [], [ - AC_CHECK_HEADER([mach/mach_time.h], [ - AC_DEFINE(HAVE_MACH_MACH_TIME_H, 1, [Define to 1 on Darwin]) - ], [AC_MSG_ERROR([unable to find clock_gettime or mach_absolute_time])]) -]) -AC_SEARCH_LIBS([remainder], [m], [], [AC_MSG_ERROR([unable to find remainder() function])]) - -AS_IF([test "x$enable_regex" = "xyes"], [ - AC_CHECK_HEADER([regex.h], [ - AC_DEFINE(HAVE_REGEX_H, 1, [Define to 1 if you have the <regex.h> header file.]) - AC_SEARCH_LIBS([regexec], [regex], [ - AS_IF([test "x$ac_cv_search_regexec" = "x-lregex"], [ - LIBREGEX_LIB="-lregex" - LIBS_EXTRA="${LIBS_EXTRA} -lregex" - ] - )], - [AC_MSG_ERROR([unable to find the regexec() function])])], - [AC_MSG_ERROR([unable to find the regex.h header]) - ], - [#include <sys/types.h>]) -]) -AC_SUBST(LIBREGEX_LIB) - -AS_IF([test "x$enable_lua" = "xyes"], [ - AX_PROG_LUA([5.1], [], [ - AX_LUA_HEADERS([ - AX_LUA_LIBS([ - AC_DEFINE(HAVE_LUA, 1, [Define to 1 for lua support.]) - with_lua="yes" - ], [AC_MSG_ERROR([unable to find the lua libraries]) - ]) - ], [AC_MSG_ERROR([unable to find the lua header files]) - ]) - ], [AC_MSG_ERROR([unable to find the lua interpreter])]) -], [with_lua="no"]) - -AM_CONDITIONAL([LUA_SUB], [test "$with_lua" = "yes"]) - -AS_IF([test "x$enable_urls" = "xyes"], [ - AC_CHECK_HEADER([fetch.h], [ - AC_DEFINE(HAVE_FETCH_H, 1, [Define to 1 if you have the <fetch.h> header file.]) - AC_CHECK_LIB(fetch, fetchXGet, [ - AC_DEFINE(HAVE_LIBFETCH, 1, [Define to 1 if you have the 'fetch' library (-lfetch).]) - LIBFETCH_LIBS="-lfetch" - have_libfetch="yes" - LIBS_EXTRA="${LIBS_EXTRA} -lfetch" - ]) - ], [],[ - #include <stdio.h> - #ifdef HAVE_SYS_PARAM_H - #include <sys/param.h> - #endif - ]) - AC_SUBST(LIBFETCH_LIBS) - - AS_IF([ test "x$have_libfetch" != "xyes"], [ - dnl Fallback to libcurl - PKG_CHECK_MODULES([CURL], [libcurl], [ - AC_DEFINE(CURL_FOUND, 1, [Use libcurl]) - LIBS_EXTRA="${LIBS_EXTRA} -lcurl"], - [AC_MSG_ERROR([unable to find neither libfetch nor libcurl])]) - ]) - AC_SUBST(CURL_FOUND) - AC_SUBST(CURL_LIBS) - AC_SUBST(CURL_CFLAGS) -]) - -AC_SUBST(LIBS_EXTRA) - -AC_MSG_CHECKING(for GCC atomic builtins) -AC_LINK_IFELSE([ - AC_LANG_SOURCE([[ - int main() { - volatile unsigned long val = 1; - __sync_synchronize(); - __sync_val_compare_and_swap(&val, 1, 0); - __sync_add_and_fetch(&val, 1); - __sync_sub_and_fetch(&val, 1); - return 0; - } - ]]) -], -[ - AC_MSG_RESULT([yes]) - AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], [Has gcc/MSVC atomic intrinsics]) -], -[ - AC_MSG_RESULT([no]) - AC_DEFINE([HAVE_ATOMIC_BUILTINS], [0], [Has gcc/MSVC atomic intrinsics]) - AC_MSG_WARN([Libucl references could be thread-unsafe because atomic builtins are missing]) -]) - -AX_CODE_COVERAGE - -AC_CONFIG_FILES(Makefile \ - src/Makefile \ - lua/Makefile - tests/Makefile \ - utils/Makefile \ - doc/Makefile \ - lua/libucl.rockspec \ - libucl.pc) -AC_CONFIG_FILES([stamp-h], [echo timestamp > stamp-h]) -AC_OUTPUT diff --git a/contrib/libucl/doc/Makefile.am b/contrib/libucl/doc/Makefile.am deleted file mode 100644 index dcfacf6a9a25..000000000000 --- a/contrib/libucl/doc/Makefile.am +++ /dev/null @@ -1,9 +0,0 @@ -EXTRA_DIST = api.md - -dist_man_MANS = libucl.3 - -gen-man: @PANDOC@ - tail -n +$$(grep -n '# Synopsis' api.md | cut -d':' -f1) api.md | \ - cat pandoc.template - | sed -e 's/^# \(.*\)/# \U\1/' \ - -e "s/%%date%%/$$(LANG=C date +'%d %B, %Y')/" | \ - @PANDOC@ -s -f markdown -t man -o libucl.3 diff --git a/contrib/libucl/doc/api.md b/contrib/libucl/doc/api.md deleted file mode 100644 index a0d33c0e68a9..000000000000 --- a/contrib/libucl/doc/api.md +++ /dev/null @@ -1,506 +0,0 @@ -# API documentation - -**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)* - -- [Synopsis](#synopsis) -- [Description](#description) - - [Parser functions](#parser-functions) - - [Emitting functions](#emitting-functions) - - [Conversion functions](#conversion-functions) - - [Generation functions](#generation-functions) - - [Iteration functions](#iteration-functions) - - [Validation functions](#validation-functions) - - [Utility functions](#utility-functions) -- [Parser functions](#parser-functions-1) - - [ucl_parser_new](#ucl_parser_new) - - [ucl_parser_register_macro](#ucl_parser_register_macro) - - [ucl_parser_register_variable](#ucl_parser_register_variable) - - [ucl_parser_add_chunk](#ucl_parser_add_chunk) - - [ucl_parser_add_string](#ucl_parser_add_string) - - [ucl_parser_add_file](#ucl_parser_add_file) - - [ucl_parser_get_object](#ucl_parser_get_object) - - [ucl_parser_get_error](#ucl_parser_get_error) - - [ucl_parser_free](#ucl_parser_free) - - [ucl_pubkey_add](#ucl_pubkey_add) - - [ucl_parser_set_filevars](#ucl_parser_set_filevars) - - [Parser usage example](#parser-usage-example) -- [Emitting functions](#emitting-functions-1) - - [ucl_object_emit](#ucl_object_emit) - - [ucl_object_emit_full](#ucl_object_emit_full) -- [Conversion functions](#conversion-functions-1) -- [Generation functions](#generation-functions-1) - - [ucl_object_new](#ucl_object_new) - - [ucl_object_typed_new](#ucl_object_typed_new) - - [Primitive objects generation](#primitive-objects-generation) - - [ucl_object_fromstring_common](#ucl_object_fromstring_common) -- [Iteration functions](#iteration-functions-1) - - [ucl_iterate_object](#ucl_iterate_object) -- [Validation functions](#validation-functions-1) - - [ucl_object_validate](#ucl_object_validate) - -# Synopsis - -`#include <ucl.h>` - -# Description - -Libucl is a parser and `C` API to parse and generate `ucl` objects. Libucl consist of several groups of functions: - -### Parser functions -Used to parse `ucl` files and provide interface to extract `ucl` object. Currently, `libucl` can parse only full `ucl` documents, for instance, it is impossible to parse a part of document and therefore it is impossible to use `libucl` as a streaming parser. In future, this limitation can be removed. - -### Emitting functions -Convert `ucl` objects to some textual or binary representation. Currently, libucl supports the following exports: - -- `JSON` - valid json format (can possibly lose some original data, such as implicit arrays) -- `Config` - human-readable configuration format (lossless) -- `YAML` - embedded yaml format (has the same limitations as `json` output) - -### Conversion functions -Help to convert `ucl` objects to C types. These functions are used to convert `ucl_object_t` to C primitive types, such as numbers, strings or boolean values. - -### Generation functions -Allow creation of `ucl` objects from C types and creating of complex `ucl` objects, such as hashes or arrays from primitive `ucl` objects, such as numbers or strings. - -### Iteration functions -Iterate over `ucl` complex objects or over a chain of values, for example when a key in an object has multiple values (that can be treated as implicit array or implicit consolidation). - -### Validation functions -Validation functions are used to validate some object `obj` using json-schema compatible object `schema`. Both input and schema must be UCL objects to perform validation. - -### Utility functions -Provide basic utilities to manage `ucl` objects: creating, removing, retaining and releasing reference count and so on. - -# Parser functions - -Parser functions operates with `struct ucl_parser`. - -### ucl_parser_new - -~~~C -struct ucl_parser* ucl_parser_new (int flags); -~~~ - -Creates new parser with the specified flags: - -- `UCL_PARSER_KEY_LOWERCASE` - lowercase keys parsed -- `UCL_PARSER_ZEROCOPY` - try to use zero-copy mode when reading files (in zero-copy mode text chunk being parsed without copying strings so it should exist till any object parsed is used) -- `UCL_PARSER_NO_TIME` - treat time values as strings without parsing them as floats - -### ucl_parser_register_macro - -~~~C -void ucl_parser_register_macro (struct ucl_parser *parser, - const char *macro, ucl_macro_handler handler, void* ud); -~~~ - -Register new macro with name .`macro` parsed by handler `handler` that accepts opaque data pointer `ud`. Macro handler should be of the following type: - -~~~C -bool (*ucl_macro_handler) (const unsigned char *data, - size_t len, void* ud);` -~~~ - -Handler function accepts macro text `data` of length `len` and the opaque pointer `ud`. If macro is parsed successfully the handler should return `true`. `false` indicates parsing failure and the parser can be terminated. - -### ucl_parser_register_variable - -~~~C -void ucl_parser_register_variable (struct ucl_parser *parser, - const char *var, const char *value); -~~~ - -Register new variable $`var` that should be replaced by the parser to the `value` string. - -### ucl_parser_add_chunk - -~~~C -bool ucl_parser_add_chunk (struct ucl_parser *parser, - const unsigned char *data, size_t len); -~~~ - -Add new text chunk with `data` of length `len` to the parser. At the moment, `libucl` parser is not a streamlined parser and chunk *must* contain the *valid* ucl object. For example, this object should be valid: - -~~~json -{ "var": "value" } -~~~ - -while this one won't be parsed correctly: - -~~~json -{ "var": -~~~ - -This limitation may possible be removed in future. - -### ucl_parser_add_string -~~~C -bool ucl_parser_add_string (struct ucl_parser *parser, - const char *data, size_t len); -~~~ - -This function acts exactly like `ucl_parser_add_chunk` does but if `len` argument is zero, then the string `data` must be zero-terminated and the actual length is calculated up to `\0` character. - -### ucl_parser_add_file - -~~~C -bool ucl_parser_add_file (struct ucl_parser *parser, - const char *filename); -~~~ - -Load file `filename` and parse it with the specified `parser`. This function uses `mmap` call to load file, therefore, it should not be `shrunk` during parsing. Otherwise, `libucl` can cause memory corruption and terminate the calling application. This function is also used by the internal handler of `include` macro, hence, this macro has the same limitation. - -### ucl_parser_get_object - -~~~C -ucl_object_t* ucl_parser_get_object (struct ucl_parser *parser); -~~~ - -If the `ucl` data has been parsed correctly this function returns the top object for the parser. Otherwise, this function returns the `NULL` pointer. The reference count for `ucl` object returned is increased by one, therefore, a caller should decrease reference by using `ucl_object_unref` to free object after usage. - -### ucl_parser_get_error - -~~~C -const char *ucl_parser_get_error(struct ucl_parser *parser); -~~~ - -Returns the constant error string for the parser object. If no error occurred during parsing a `NULL` object is returned. A caller should not try to free or modify this string. - -### ucl_parser_free - -~~~C -void ucl_parser_free (struct ucl_parser *parser); -~~~ - -Frees memory occupied by the parser object. The reference count for top object is decreased as well, however if the function `ucl_parser_get_object` was called previously then the top object won't be freed. - -### ucl_pubkey_add - -~~~C -bool ucl_pubkey_add (struct ucl_parser *parser, - const unsigned char *key, size_t len); -~~~ - -This function adds a public key from text blob `key` of length `len` to the `parser` object. This public key should be in the `PEM` format and can be used by `.includes` macro for checking signatures of files included. `Openssl` support should be enabled to make this function working. If a key cannot be added (e.g. due to format error) or `openssl` was not linked to `libucl` then this function returns `false`. - -### ucl_parser_set_filevars - -~~~C -bool ucl_parser_set_filevars (struct ucl_parser *parser, - const char *filename, bool need_expand); -~~~ - -Add the standard file variables to the `parser` based on the `filename` specified: - -- `$FILENAME` - a filename of `ucl` input -- `$CURDIR` - a current directory of the input - -For example, if a `filename` param is `../something.conf` then the variables will have the following values: - -- `$FILENAME` - "../something.conf" -- `$CURDIR` - ".." - -if `need_expand` parameter is `true` then all relative paths are expanded using `realpath` call. In this example if `..` is `/etc/dir` then variables will have these values: - -- `$FILENAME` - "/etc/something.conf" -- `$CURDIR` - "/etc" - -## Parser usage example - -The following example loads, parses and extracts `ucl` object from stdin using `libucl` parser functions (the length of input is limited to 8K): - -~~~C -char inbuf[8192]; -struct ucl_parser *parser = NULL; -int ret = 0, r = 0; -ucl_object_t *obj = NULL; -FILE *in; - -in = stdin; -parser = ucl_parser_new (0); -while (!feof (in) && r < (int)sizeof (inbuf)) { - r += fread (inbuf + r, 1, sizeof (inbuf) - r, in); -} -ucl_parser_add_chunk (parser, inbuf, r); -fclose (in); - -if (ucl_parser_get_error (parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error (parser)); - ret = 1; -} -else { - obj = ucl_parser_get_object (parser); -} - -if (parser != NULL) { - ucl_parser_free (parser); -} -if (obj != NULL) { - ucl_object_unref (obj); -} -return ret; -~~~ - -# Emitting functions - -Libucl can transform UCL objects to a number of textual formats: - -- configuration (`UCL_EMIT_CONFIG`) - nginx like human readable configuration file where implicit arrays are transformed to the duplicate keys -- compact json: `UCL_EMIT_JSON_COMPACT` - single line valid json without spaces -- formatted json: `UCL_EMIT_JSON` - pretty formatted JSON with newlines and spaces -- compact yaml: `UCL_EMIT_YAML` - compact YAML output - -Moreover, libucl API allows to select a custom set of emitting functions allowing -efficient and zero-copy output of libucl objects. Libucl uses the following structure to support this feature: - -~~~C -struct ucl_emitter_functions { - /** Append a single character */ - int (*ucl_emitter_append_character) (unsigned char c, size_t nchars, void *ud); - /** Append a string of a specified length */ - int (*ucl_emitter_append_len) (unsigned const char *str, size_t len, void *ud); - /** Append a 64 bit integer */ - int (*ucl_emitter_append_int) (int64_t elt, void *ud); - /** Append floating point element */ - int (*ucl_emitter_append_double) (double elt, void *ud); - /** Opaque userdata pointer */ - void *ud; -}; -~~~ - -This structure defines the following callbacks: - -- `ucl_emitter_append_character` - a function that is called to append `nchars` characters equal to `c` -- `ucl_emitter_append_len` - used to append a string of length `len` starting from pointer `str` -- `ucl_emitter_append_int` - this function applies to integer numbers -- `ucl_emitter_append_double` - this function is intended to output floating point variable - -The set of these functions could be used to output text formats of `UCL` objects to different structures or streams. - -Libucl provides the following functions for emitting UCL objects: - -### ucl_object_emit - -~~~C -unsigned char *ucl_object_emit (const ucl_object_t *obj, enum ucl_emitter emit_type); -~~~ - -Allocate a string that is suitable to fit the underlying UCL object `obj` and fill it with the textual representation of the object `obj` according to style `emit_type`. The caller should free the returned string after using. - -### ucl_object_emit_full - -~~~C -bool ucl_object_emit_full (const ucl_object_t *obj, enum ucl_emitter emit_type, - struct ucl_emitter_functions *emitter); -~~~ - -This function is similar to the previous with the exception that it accepts the additional argument `emitter` that defines the concrete set of output functions. This emit function could be useful for custom structures or streams emitters (including C++ ones, for example). - -# Conversion functions - -Conversion functions are used to convert UCL objects to primitive types, such as strings, numbers, or boolean values. There are two types of conversion functions: - -- safe: try to convert an ucl object to a primitive type and fail if such a conversion is not possible -- unsafe: return primitive type without additional checks, if the object cannot be converted then some reasonable default is returned (NULL for strings and 0 for numbers) - -Also there is a single `ucl_object_tostring_forced` function that converts any UCL object (including compound types - arrays and objects) to a string representation. For objects, arrays, booleans and numeric types this function performs emitting to a compact json format actually. - -Here is a list of all conversion functions: - -- `ucl_object_toint` - returns `int64_t` of UCL object -- `ucl_object_todouble` - returns `double` of UCL object -- `ucl_object_toboolean` - returns `bool` of UCL object -- `ucl_object_tostring` - returns `const char *` of UCL object (this string is NULL terminated) -- `ucl_object_tolstring` - returns `const char *` and `size_t` len of UCL object (string does not need to be NULL terminated) -- `ucl_object_tostring_forced` - returns string representation of any UCL object - -Strings returned by these pointers are associated with the UCL object and exist over its lifetime. A caller should not free this memory. - -# Generation functions - -It is possible to generate UCL objects from C primitive types. Moreover, libucl allows creation and modifying complex UCL objects, such as arrays or associative objects. - -## ucl_object_new -~~~C -ucl_object_t * ucl_object_new (void) -~~~ - -Creates new object of type `UCL_NULL`. This object should be released by caller. - -## ucl_object_typed_new -~~~C -ucl_object_t * ucl_object_typed_new (unsigned int type) -~~~ - -Create an object of a specified type: -- `UCL_OBJECT` - UCL object - key/value pairs -- `UCL_ARRAY` - UCL array -- `UCL_INT` - integer number -- `UCL_FLOAT` - floating point number -- `UCL_STRING` - NULL terminated string -- `UCL_BOOLEAN` - boolean value -- `UCL_TIME` - time value (floating point number of seconds) -- `UCL_USERDATA` - opaque userdata pointer (may be used in macros) -- `UCL_NULL` - null value - -This object should be released by caller. - -## Primitive objects generation -Libucl provides the functions similar to inverse conversion functions called with the specific C type: -- `ucl_object_fromint` - converts `int64_t` to UCL object -- `ucl_object_fromdouble` - converts `double` to UCL object -- `ucl_object_frombool` - converts `bool` to UCL object -- `ucl_object_fromstring` - converts `const char *` to UCL object (this string should be NULL terminated) -- `ucl_object_fromlstring` - converts `const char *` and `size_t` len to UCL object (string does not need to be NULL terminated) - -Also there is a function to generate UCL object from a string performing various parsing or conversion operations called `ucl_object_fromstring_common`. - -## ucl_object_fromstring_common -~~~C -ucl_object_t * ucl_object_fromstring_common (const char *str, - size_t len, enum ucl_string_flags flags) -~~~ - -This function is used to convert a string `str` of size `len` to a UCL object applying `flags` conversions. If `len` is equal to zero then a `str` is assumed as NULL-terminated. This function supports the following flags (a set of flags can be specified using logical `OR` operation): - -- `UCL_STRING_ESCAPE` - perform JSON escape -- `UCL_STRING_TRIM` - trim leading and trailing whitespaces -- `UCL_STRING_PARSE_BOOLEAN` - parse passed string and detect boolean -- `UCL_STRING_PARSE_INT` - parse passed string and detect integer number -- `UCL_STRING_PARSE_DOUBLE` - parse passed string and detect integer or float number -- `UCL_STRING_PARSE_TIME` - parse time values as floating point numbers -- `UCL_STRING_PARSE_NUMBER` - parse passed string and detect number (both float, integer and time types) -- `UCL_STRING_PARSE` - parse passed string (and detect booleans, numbers and time values) -- `UCL_STRING_PARSE_BYTES` - assume that numeric multipliers are in bytes notation, for example `10k` means `10*1024` and not `10*1000` as assumed without this flag - -If parsing operations fail then the resulting UCL object will be a `UCL_STRING`. A caller should always check the type of the returned object and release it after using. - -# Iteration functions - -Iteration are used to iterate over UCL compound types: arrays and objects. Moreover, iterations could be performed over the keys with multiple values (implicit arrays). -There are two types of iterators API: old and unsafe one via `ucl_iterate_object` and the proposed interface of safe iterators. - - -## ucl_iterate_object -~~~C -const ucl_object_t* ucl_iterate_object (const ucl_object_t *obj, - ucl_object_iter_t *iter, bool expand_values); -~~~ - -This function accepts opaque iterator pointer `iter`. In the first call this iterator *must* be initialized to `NULL`. Iterator is changed by this function call. `ucl_iterate_object` returns the next UCL object in the compound object `obj` or `NULL` if all objects have been iterated. The reference count of the object returned is not increased, so a caller should not unref the object or modify its content (e.g. by inserting to another compound object). The object `obj` should not be changed during the iteration process as well. `expand_values` flag speicifies whether `ucl_iterate_object` should expand keys with multiple values. The general rule is that if you need to iterate through the *object* or *explicit array*, then you always need to set this flag to `true`. However, if you get some key in the object and want to extract all its values then you should set `expand_values` to `false`. Mixing of iteration types is not permitted since the iterator is set according to the iteration type and cannot be reused. Here is an example of iteration over the objects using libucl API (assuming that `top` is `UCL_OBJECT` in this example): - -~~~C -ucl_object_iter_t it = NULL, it_obj = NULL; -const ucl_object_t *cur, *tmp; - -/* Iterate over the object */ -while ((obj = ucl_iterate_object (top, &it, true))) { - printf ("key: \"%s\"\n", ucl_object_key (obj)); - /* Iterate over the values of a key */ - while ((cur = ucl_iterate_object (obj, &it_obj, false))) { - printf ("value: \"%s\"\n", - ucl_object_tostring_forced (cur)); - } -} -~~~ - -## Safe iterators API - -Safe iterators are defined to clarify iterating over UCL objects and simplify flattening of UCL objects in non-trivial cases. -For example, if there is an implicit array that contains another array and a boolean value it is extremely unclear how to iterate over -such an object. Safe iterators are desinged to define two sorts of iteration: - -1. Iteration over complex objects with expanding all values -2. Iteration over complex objects without expanding of values - -The following example demonstrates the difference between these two types of iteration: - -~~~ -key = 1; -key = [2, 3, 4]; - -Iteration with expansion: - -1, 2, 3, 4 - -Iteration without expansion: - -1, [2, 3, 4] -~~~ - -UCL defines the following functions to manage safe iterators: - -- `ucl_object_iterate_new` - creates new safe iterator -- `ucl_object_iterate_reset` - resets iterator to a new object -- `ucl_object_iterate_safe` - safely iterate the object inside iterator. Note: function may allocate and free memory during its operation. Therefore it returns `NULL` either while trying to access item after the last one or when exception (such as memory allocation failure) happens. -- `ucl_object_iter_chk_excpn` - check if the last call to `ucl_object_iterate_safe` ended up in unrecoverable exception (e.g. `ENOMEM`). -- `ucl_object_iterate_free` - free memory associated with the safe iterator - -Please note that unlike unsafe iterators, safe iterators *must* be explicitly initialized and freed. -An assert is likely generated if you use uninitialized or `NULL` iterator in all safe iterators functions. - -~~~C -ucl_object_iter_t it; -const ucl_object_t *cur; - -it = ucl_object_iterate_new (obj); - -while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { - /* Do something */ -} -/* Check error condition */ -if (ucl_object_iter_chk_excpn (it)) { - ucl_object_iterate_free (it); - exit (1); -} - -/* Switch to another object */ -it = ucl_object_iterate_reset (it, another_obj); - -while ((cur = ucl_object_iterate_safe (it, true)) != NULL) { - /* Do something else */ -} -/* Check error condition */ -if (ucl_object_iter_chk_excpn (it)) { - ucl_object_iterate_free (it); - exit (1); -} - -ucl_object_iterate_free (it); -~~~ - -# Validation functions - -Currently, there is only one validation function called `ucl_object_validate`. It performs validation of object using the specified schema. This function is defined as following: - -## ucl_object_validate -~~~C -bool ucl_object_validate (const ucl_object_t *schema, - const ucl_object_t *obj, struct ucl_schema_error *err); -~~~ - -This function uses ucl object `schema`, that must be valid in terms of `json-schema` draft v4, to validate input object `obj`. If this function returns `true` then validation procedure has been succeed. Otherwise, `false` is returned and `err` is set to a specific value. If a caller sets `err` to NULL then this function does not set any error just returning `false`. Error is the structure defined as following: - -~~~C -struct ucl_schema_error { - enum ucl_schema_error_code code; /* error code */ - char msg[128]; /* error message */ - ucl_object_t *obj; /* object where error occurred */ -}; -~~~ - -Caller may use `code` field to get a numeric error code: - -~~~C -enum ucl_schema_error_code { - UCL_SCHEMA_OK = 0, /* no error */ - UCL_SCHEMA_TYPE_MISMATCH, /* type of object is incorrect */ - UCL_SCHEMA_INVALID_SCHEMA, /* schema is invalid */ - UCL_SCHEMA_MISSING_PROPERTY,/* missing properties */ - UCL_SCHEMA_CONSTRAINT, /* constraint found */ - UCL_SCHEMA_MISSING_DEPENDENCY, /* missing dependency */ - UCL_SCHEMA_UNKNOWN /* generic error */ -}; -~~~ - -`msg` is a string description of an error and `obj` is an object where error has occurred. Error object is not allocated by libucl, so there is no need to free it after validation (a static object should thus be used). diff --git a/contrib/libucl/doc/lua_api.md b/contrib/libucl/doc/lua_api.md deleted file mode 100644 index 7da414903b01..000000000000 --- a/contrib/libucl/doc/lua_api.md +++ /dev/null @@ -1,196 +0,0 @@ -## Module `ucl` - -This lua module allows to parse objects from strings and to store data into -ucl objects. It uses `libucl` C library to parse and manipulate with ucl objects. - -Example: - -~~~lua -local ucl = require("ucl") - -local parser = ucl.parser() -local res,err = parser:parse_string('{key=value}') - -if not res then - print('parser error: ' .. err) -else - local obj = parser:get_object() - local got = ucl.to_format(obj, 'json') -end - -local table = { - str = 'value', - num = 100500, - null = ucl.null, - func = function () - return 'huh' - end -} - - -print(ucl.to_format(table, 'ucl')) --- Output: ---[[ -num = 100500; -str = "value"; -null = null; -func = "huh"; ---]] -~~~ - -###Brief content: - -**Functions**: - -> [`ucl_object_push_lua(L, obj, allow_array)`](#function-ucl_object_push_lual-obj-allow_array) - -> [`ucl.to_format(var, format)`](#function-uclto_formatvar-format) - - - -**Methods**: - -> [`parser:parse_file(name)`](#method-parserparse_filename) - -> [`parser:parse_string(input)`](#method-parserparse_stringinput) - -> [`parser:get_object()`](#method-parserget_object) - - -## Functions - -The module `ucl` defines the following functions. - -### Function `ucl_object_push_lua(L, obj, allow_array)` - -This is a `C` function to push `UCL` object as lua variable. This function -converts `obj` to lua representation using the following conversions: - -- *scalar* values are directly presented by lua objects -- *userdata* values are converted to lua function objects using `LUA_REGISTRYINDEX`, -this can be used to pass functions from lua to c and vice-versa -- *arrays* are converted to lua tables with numeric indices suitable for `ipairs` iterations -- *objects* are converted to lua tables with string indices - -**Parameters:** - -- `L {lua_State}`: lua state pointer -- `obj {ucl_object_t}`: object to push -- `allow_array {bool}`: expand implicit arrays (should be true for all but partial arrays) - -**Returns:** - -- `{int}`: `1` if an object is pushed to lua - -Back to [module description](#module-ucl). - -### Function `ucl.to_format(var, format)` - -Converts lua variable `var` to the specified `format`. Formats supported are: - -- `json` - fine printed json -- `json-compact` - compacted json -- `config` - fine printed configuration -- `ucl` - same as `config` -- `yaml` - embedded yaml - -If `var` contains function, they are called during output formatting and if -they return string value, then this value is used for ouptut. - -**Parameters:** - -- `var {variant}`: any sort of lua variable (if userdata then metafield `__to_ucl` is searched for output) -- `format {string}`: any available format - -**Returns:** - -- `{string}`: string representation of `var` in the specific `format`. - -Example: - -~~~lua -local table = { - str = 'value', - num = 100500, - null = ucl.null, - func = function () - return 'huh' - end -} - - -print(ucl.to_format(table, 'ucl')) --- Output: ---[[ -num = 100500; -str = "value"; -null = null; -func = "huh"; ---]] -~~~ - -Back to [module description](#module-ucl). - - -## Methods - -The module `ucl` defines the following methods. - -### Method `parser:parse_file(name)` - -Parse UCL object from file. - -**Parameters:** - -- `name {string}`: filename to parse - -**Returns:** - -- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned - -Example: - -~~~lua -local parser = ucl.parser() -local res,err = parser:parse_file('/some/file.conf') - -if not res then - print('parser error: ' .. err) -else - -- Do something with object -end -~~~ - -Back to [module description](#module-ucl). - -### Method `parser:parse_string(input)` - -Parse UCL object from file. - -**Parameters:** - -- `input {string}`: string to parse - -**Returns:** - -- `{bool[, string]}`: if res is `true` then file has been parsed successfully, otherwise an error string is also returned - -Back to [module description](#module-ucl). - -### Method `parser:get_object()` - -Get top object from parser and export it to lua representation. - -**Parameters:** - - nothing - -**Returns:** - -- `{variant or nil}`: ucl object as lua native variable - -Back to [module description](#module-ucl). - - -Back to [top](#). - diff --git a/contrib/libucl/doc/pandoc.template b/contrib/libucl/doc/pandoc.template deleted file mode 100644 index 2effe1a157ef..000000000000 --- a/contrib/libucl/doc/pandoc.template +++ /dev/null @@ -1,12 +0,0 @@ -% LIBUCL(3) Libucl manual -% Vsevolod Stakhov <vsevolod@highsecure.ru> -% %%date%% - -# Name - -**ucl_parser_new**, **ucl_parser_register_macro**, **ucl_parser_register_variable**, **ucl_parser_add_chunk**, **ucl_parser_add_string**, **ucl_parser_add_file**, **ucl_parser_get_object**, **ucl_parser_get_error**, **ucl_parser_free**, **ucl_pubkey_add**, **ucl_parser_set_filevars** - universal configuration library parser and utility functions - -# Library - -UCL library (libucl, -lucl) - diff --git a/contrib/libucl/examples/ucl_cpp.cc b/contrib/libucl/examples/ucl_cpp.cc deleted file mode 100644 index 2d15d84a6c8d..000000000000 --- a/contrib/libucl/examples/ucl_cpp.cc +++ /dev/null @@ -1,26 +0,0 @@ -#include <iostream> -#include <string> -#include "ucl++.h" - -int main(int argc, char **argv) -{ - std::string input, err; - - input.assign((std::istreambuf_iterator<char>(std::cin)), - std::istreambuf_iterator<char>()); - - auto obj = ucl::Ucl::parse(input, err); - - if (obj) { - std::cout << obj.dump(UCL_EMIT_CONFIG) << std::endl; - - for (const auto &o : obj) { - std::cout << o.dump(UCL_EMIT_CONFIG) << std::endl; - } - } - else { - std::cerr << "Error: " << err << std::endl; - - return 1; - } -} diff --git a/contrib/libucl/haskell/hucl.hs b/contrib/libucl/haskell/hucl.hs deleted file mode 100644 index 2dd3ac01e4c0..000000000000 --- a/contrib/libucl/haskell/hucl.hs +++ /dev/null @@ -1,123 +0,0 @@ -{-# LANGUAGE ForeignFunctionInterface #-} - --- an example UCL FFI module: --- uses the Object Model from Messagepack to emit --- - -module Data.UCL ( unpack ) where -import Foreign.C -import Foreign.Ptr -import System.IO.Unsafe ( unsafePerformIO ) -import qualified Data.Text as T -import qualified Data.Vector as V -import qualified Data.MessagePack as MSG - -type ParserHandle = Ptr () -type UCLObjectHandle = Ptr () -type UCLIterHandle = Ptr () -type UCLEmitterType = CInt -type ErrorString = String - - -foreign import ccall "ucl_parser_new" ucl_parser_new :: CInt -> ParserHandle -foreign import ccall "ucl_parser_add_string" ucl_parser_add_string :: ParserHandle -> CString -> CUInt -> IO Bool -foreign import ccall "ucl_parser_add_file" ucl_parser_add_file :: ParserHandle -> CString -> IO Bool -foreign import ccall "ucl_parser_get_object" ucl_parser_get_object :: ParserHandle -> UCLObjectHandle -foreign import ccall "ucl_parser_get_error" ucl_parser_get_error :: ParserHandle -> CString - -foreign import ccall "ucl_object_iterate_new" ucl_object_iterate_new :: UCLObjectHandle -> UCLIterHandle -foreign import ccall "ucl_object_iterate_safe" ucl_object_iterate_safe :: UCLIterHandle -> Bool -> UCLObjectHandle -foreign import ccall "ucl_object_type" ucl_object_type :: UCLObjectHandle -> CUInt -foreign import ccall "ucl_object_key" ucl_object_key :: UCLObjectHandle -> CString -foreign import ccall "ucl_object_toint" ucl_object_toint :: UCLObjectHandle -> CInt -foreign import ccall "ucl_object_todouble" ucl_object_todouble :: UCLObjectHandle -> CDouble -foreign import ccall "ucl_object_tostring" ucl_object_tostring :: UCLObjectHandle -> CString -foreign import ccall "ucl_object_toboolean" ucl_object_toboolean :: UCLObjectHandle -> Bool - -foreign import ccall "ucl_object_emit" ucl_object_emit :: UCLObjectHandle -> UCLEmitterType -> CString -foreign import ccall "ucl_object_emit_len" ucl_object_emit_len :: UCLObjectHandle -> UCLEmitterType -> Ptr CSize -> IO CString - -type UCL_TYPE = CUInt -ucl_OBJECT :: UCL_TYPE -ucl_OBJECT = 0 -ucl_ARRAY :: UCL_TYPE -ucl_ARRAY = 1 -ucl_INT :: UCL_TYPE -ucl_INT = 2 -ucl_FLOAT :: UCL_TYPE -ucl_FLOAT = 3 -ucl_STRING :: UCL_TYPE -ucl_STRING = 4 -ucl_BOOLEAN :: UCL_TYPE -ucl_BOOLEAN = 5 -ucl_TIME :: UCL_TYPE -ucl_TIME = 6 -ucl_USERDATA :: UCL_TYPE -ucl_USERDATA = 7 -ucl_NULL :: UCL_TYPE -ucl_NULL = 8 - -ucl_emit_json :: UCLEmitterType -ucl_emit_json = 0 -ucl_emit_json_compact :: UCLEmitterType -ucl_emit_json_compact = 1 :: UCLEmitterType -ucl_emit_msgpack :: UCLEmitterType -ucl_emit_msgpack = 4 :: UCLEmitterType - -ucl_parser_parse_string_pure :: String -> Either UCLObjectHandle ErrorString -ucl_parser_parse_string_pure s = unsafePerformIO $ do - cs <- newCString s - let p = ucl_parser_new 0x4 - didParse <- ucl_parser_add_string p cs (toEnum $ length s) - if didParse - then return $ Left $ ucl_parser_get_object p - else Right <$> peekCString ( ucl_parser_get_error p) - -ucl_parser_add_file_pure :: String -> Either UCLObjectHandle ErrorString -ucl_parser_add_file_pure s = unsafePerformIO $ do - cs <- newCString s - let p = ucl_parser_new 0x4 - didParse <- ucl_parser_add_file p cs - if didParse - then return $ Left $ ucl_parser_get_object p - else Right <$> peekCString ( ucl_parser_get_error p) - -unpack :: MSG.MessagePack a => String -> Either a ErrorString -unpack s = case ucl_parser_parse_string_pure s of - (Right err) -> Right err - (Left obj) -> case MSG.fromObject (ucl_to_msgpack_object obj) of - Nothing -> Right "MessagePack fromObject Error" - (Just a) -> Left a - -ucl_to_msgpack_object :: UCLObjectHandle -> MSG.Object -ucl_to_msgpack_object o = toMsgPackObj (ucl_object_type o) o - where - toMsgPackObj n obj - |n==ucl_OBJECT = MSG.ObjectMap $ uclObjectToVector obj - |n==ucl_ARRAY = MSG.ObjectArray undefined - |n==ucl_INT = MSG.ObjectInt $ fromEnum $ ucl_object_toint obj - |n==ucl_FLOAT = MSG.ObjectDouble $ realToFrac $ ucl_object_todouble obj - |n==ucl_STRING = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_tostring obj - |n==ucl_BOOLEAN = MSG.ObjectBool $ ucl_object_toboolean obj - |n==ucl_TIME = error "time undefined" - |n==ucl_USERDATA = error "userdata undefined" - |n==ucl_NULL = error "null undefined" - |otherwise = error "\"Unknown Type\" Error" - -uclObjectToVector :: UCLObjectHandle -> V.Vector (MSG.Object,MSG.Object) -uclObjectToVector o = iterateObject (ucl_object_iterate_safe iter True ) iter V.empty - where - iter = ucl_object_iterate_new o - iterateObject obj it vec = if ucl_object_type obj == ucl_NULL - then vec - else iterateObject (ucl_object_iterate_safe it True) it (V.snoc vec ( getUclKey obj , ucl_to_msgpack_object obj)) - getUclKey obj = MSG.ObjectStr $ T.pack $ unsafePerformIO $ peekCString $ ucl_object_key obj - -uclArrayToVector :: UCLObjectHandle -> V.Vector MSG.Object -uclArrayToVector o = iterateArray (ucl_object_iterate_safe iter True ) iter V.empty - where - iter = ucl_object_iterate_new o - iterateArray obj it vec = if ucl_object_type obj == ucl_NULL - then vec - else iterateArray (ucl_object_iterate_safe it True) it (V.snoc vec (ucl_to_msgpack_object obj)) - diff --git a/contrib/libucl/include/ucl.h b/contrib/libucl/include/ucl.h index 39da2593648d..b8625b9fce2f 100644 --- a/contrib/libucl/include/ucl.h +++ b/contrib/libucl/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/contrib/libucl/libucl.pc b/contrib/libucl/libucl.pc deleted file mode 100644 index 4878bebafcdd..000000000000 --- a/contrib/libucl/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/contrib/libucl/libucl.pc.in b/contrib/libucl/libucl.pc.in deleted file mode 100644 index 3433fa9d8b1c..000000000000 --- a/contrib/libucl/libucl.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: LibUCL -Description: Universal configuration library -Version: @UCL_VERSION@ -Libs: -L${libdir} -lucl -Libs.private: @LIBS_EXTRA@ @LUA_LIB@ -Cflags: -I${includedir}/ diff --git a/contrib/libucl/lua/Makefile.am b/contrib/libucl/lua/Makefile.am deleted file mode 100644 index 95beafbfc94e..000000000000 --- a/contrib/libucl/lua/Makefile.am +++ /dev/null @@ -1,26 +0,0 @@ -ucl_common_cflags= -I$(top_srcdir)/src \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/uthash \ - -Wall -W -Wno-unused-parameter -Wno-pointer-sign -luaexec_LTLIBRARIES= ucl.la -ucl_la_SOURCES= lua_ucl.c -ucl_la_CFLAGS= $(ucl_common_cflags) \ - @LUA_INCLUDE@ -ucl_la_LDFLAGS = -module -export-dynamic -avoid-version -ucl_la_LIBADD= $(top_srcdir)/src/libucl.la \ - @LIBFETCH_LIBS@ \ - @LIBCRYPTO_LIB@ \ - @LIBREGEX_LIB@ \ - @CURL_LIBS@ \ - @LUA_LIB@ - -include_HEADERS= $(top_srcdir)/include/lua_ucl.h - -ROCKSPEC = $(PACKAGE)-$(VERSION)-1.rockspec -EXTRA_DIST = $(PACKAGE).rockspec.in \ - test.lua -DISTCLEANFILES = $(PACKAGE).rockspec - -$(ROCKSPEC): $(PACKAGE).rockspec dist - sed -e 's/@MD5@/'`$(MD5SUM) $(distdir).tar.gz | \ - cut -d " " -f 1`'/g' < $(PACKAGE).rockspec > $@
\ No newline at end of file diff --git a/contrib/libucl/lua/libucl.rockspec.in b/contrib/libucl/lua/libucl.rockspec.in deleted file mode 100644 index 52f39176a7bd..000000000000 --- a/contrib/libucl/lua/libucl.rockspec.in +++ /dev/null @@ -1,26 +0,0 @@ -package="@PACKAGE@" -version="@VERSION@-1" -source = { - url = "https://github.com/downloads/vstakhov/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz", - md5 = "@MD5@", - dir = "@PACKAGE@-@VERSION@" -} -description = { - summary = "UCL - json like configuration language", - detailed = [[ - 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. - ]], - homepage = "http://github.com/vstakhov/@PACKAGE@/", - license = "" -} -dependencies = { - "lua >= 5.1" -} -build = { - type = "command", - build_command = "LUA=$(LUA) CPPFLAGS=-I$(LUA_INCDIR) ./configure --prefix=$(PREFIX) --libdir=$(LIBDIR) --datadir=$(LUADIR) && make clean && make", - install_command = "make install" -} diff --git a/contrib/libucl/lua/lua_ucl.c b/contrib/libucl/lua/lua_ucl.c index b34fd56878b8..d6be69e42a71 100644 --- a/contrib/libucl/lua/lua_ucl.c +++ b/contrib/libucl/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/contrib/libucl/m4/ax_lua.m4 b/contrib/libucl/m4/ax_lua.m4 deleted file mode 100644 index f8e2fd4c85ce..000000000000 --- a/contrib/libucl/m4/ax_lua.m4 +++ /dev/null @@ -1,664 +0,0 @@ -# =========================================================================== -# http://www.gnu.org/software/autoconf-archive/ax_lua.html -# =========================================================================== -# -# SYNOPSIS -# -# AX_PROG_LUA[([MINIMUM-VERSION], [TOO-BIG-VERSION], [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_HEADERS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_LIBS[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# AX_LUA_READLINE[([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])] -# -# DESCRIPTION -# -# Detect a Lua interpreter, optionally specifying a minimum and maximum -# version number. Set up important Lua paths, such as the directories in -# which to install scripts and modules (shared libraries). -# -# Also detect Lua headers and libraries. The Lua version contained in the -# header is checked to match the Lua interpreter version exactly. When -# searching for Lua libraries, the version number is used as a suffix. -# This is done with the goal of supporting multiple Lua installs (5.1, -# 5.2, and 5.3 side-by-side). -# -# A note on compatibility with previous versions: This file has been -# mostly rewritten for serial 18. Most developers should be able to use -# these macros without needing to modify configure.ac. Care has been taken -# to preserve each macro's behavior, but there are some differences: -# -# 1) AX_WITH_LUA is deprecated; it now expands to the exact same thing as -# AX_PROG_LUA with no arguments. -# -# 2) AX_LUA_HEADERS now checks that the version number defined in lua.h -# matches the interpreter version. AX_LUA_HEADERS_VERSION is therefore -# unnecessary, so it is deprecated and does not expand to anything. -# -# 3) The configure flag --with-lua-suffix no longer exists; the user -# should instead specify the LUA precious variable on the command line. -# See the AX_PROG_LUA description for details. -# -# Please read the macro descriptions below for more information. -# -# This file was inspired by Andrew Dalke's and James Henstridge's -# python.m4 and Tom Payne's, Matthieu Moy's, and Reuben Thomas's ax_lua.m4 -# (serial 17). Basically, this file is a mash-up of those two files. I -# like to think it combines the best of the two! -# -# AX_PROG_LUA: Search for the Lua interpreter, and set up important Lua -# paths. Adds precious variable LUA, which may contain the path of the Lua -# interpreter. If LUA is blank, the user's path is searched for an -# suitable interpreter. -# -# If MINIMUM-VERSION is supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION will be accepted. If -# TOO-BIG-VERSION is also supplied, then only Lua interpreters with a -# version number greater or equal to MINIMUM-VERSION and less than -# TOO-BIG-VERSION will be accepted. -# -# The Lua version number, LUA_VERSION, is found from the interpreter, and -# substituted. LUA_PLATFORM is also found, but not currently supported (no -# standard representation). -# -# Finally, the macro finds four paths: -# -# luadir Directory to install Lua scripts. -# pkgluadir $luadir/$PACKAGE -# luaexecdir Directory to install Lua modules. -# pkgluaexecdir $luaexecdir/$PACKAGE -# -# These paths are found based on $prefix, $exec_prefix, Lua's -# package.path, and package.cpath. The first path of package.path -# beginning with $prefix is selected as luadir. The first path of -# package.cpath beginning with $exec_prefix is used as luaexecdir. This -# should work on all reasonable Lua installations. If a path cannot be -# determined, a default path is used. Of course, the user can override -# these later when invoking make. -# -# luadir Default: $prefix/share/lua/$LUA_VERSION -# luaexecdir Default: $exec_prefix/lib/lua/$LUA_VERSION -# -# These directories can be used by Automake as install destinations. The -# variable name minus 'dir' needs to be used as a prefix to the -# appropriate Automake primary, e.g. lua_SCRIPS or luaexec_LIBRARIES. -# -# If an acceptable Lua interpreter is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is preformed. If ACTION-IF-NOT- -# FOUND is blank, then it will default to printing an error. To prevent -# the default behavior, give ':' as an action. -# -# AX_LUA_HEADERS: Search for Lua headers. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_INCLUDE, which -# may contain Lua specific include flags, e.g. -I/usr/include/lua5.1. If -# LUA_INCLUDE is blank, then this macro will attempt to find suitable -# flags. -# -# LUA_INCLUDE can be used by Automake to compile Lua modules or -# executables with embedded interpreters. The *_CPPFLAGS variables should -# be used for this purpose, e.g. myprog_CPPFLAGS = $(LUA_INCLUDE). -# -# This macro searches for the header lua.h (and others). The search is -# performed with a combination of CPPFLAGS, CPATH, etc, and LUA_INCLUDE. -# If the search is unsuccessful, then some common directories are tried. -# If the headers are then found, then LUA_INCLUDE is set accordingly. -# -# The paths automatically searched are: -# -# * /usr/include/luaX.Y -# * /usr/include/lua/X.Y -# * /usr/include/luaXY -# * /usr/local/include/luaX.Y -# * /usr/local/include/lua-X.Y -# * /usr/local/include/lua/X.Y -# * /usr/local/include/luaXY -# -# (Where X.Y is the Lua version number, e.g. 5.1.) -# -# The Lua version number found in the headers is always checked to match -# the Lua interpreter's version number. Lua headers with mismatched -# version numbers are not accepted. -# -# If headers are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_LIBS: Search for Lua libraries. Requires that AX_PROG_LUA be -# expanded before this macro. Adds precious variable LUA_LIB, which may -# contain Lua specific linker flags, e.g. -llua5.1. If LUA_LIB is blank, -# then this macro will attempt to find suitable flags. -# -# LUA_LIB can be used by Automake to link Lua modules or executables with -# embedded interpreters. The *_LIBADD and *_LDADD variables should be used -# for this purpose, e.g. mymod_LIBADD = $(LUA_LIB). -# -# This macro searches for the Lua library. More technically, it searches -# for a library containing the function lua_load. The search is performed -# with a combination of LIBS, LIBRARY_PATH, and LUA_LIB. -# -# If the search determines that some linker flags are missing, then those -# flags will be added to LUA_LIB. -# -# If libraries are found, then ACTION-IF-FOUND is performed, otherwise -# ACTION-IF-NOT-FOUND is performed. If ACTION-IF-NOT-FOUND is blank, then -# it will default to printing an error. To prevent the default behavior, -# set the action to ':'. -# -# AX_LUA_READLINE: Search for readline headers and libraries. Requires the -# AX_LIB_READLINE macro, which is provided by ax_lib_readline.m4 from the -# Autoconf Archive. -# -# If a readline compatible library is found, then ACTION-IF-FOUND is -# performed, otherwise ACTION-IF-NOT-FOUND is performed. -# -# LICENSE -# -# Copyright (c) 2015 Reuben Thomas <rrt@sc3d.org> -# Copyright (c) 2014 Tim Perkins <tprk77@gmail.com> -# -# This program is free software: you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation, either version 3 of the License, or (at your -# option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program. If not, see <http://www.gnu.org/licenses/>. -# -# As a special exception, the respective Autoconf Macro's copyright owner -# gives unlimited permission to copy, distribute and modify the configure -# scripts that are the output of Autoconf when processing the Macro. You -# need not follow the terms of the GNU General Public License when using -# or distributing such scripts, even though portions of the text of the -# Macro appear in them. The GNU General Public License (GPL) does govern -# all other use of the material that constitutes the Autoconf Macro. -# -# This special exception to the GPL applies to versions of the Autoconf -# Macro released by the Autoconf Archive. When you make and distribute a -# modified version of the Autoconf Macro, you may extend this special -# exception to the GPL to apply to your modified version as well. - -#serial 39 - -dnl ========================================================================= -dnl AX_PROG_LUA([MINIMUM-VERSION], [TOO-BIG-VERSION], -dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_PROG_LUA], -[ - dnl Check for required tools. - AC_REQUIRE([AC_PROG_GREP]) - AC_REQUIRE([AC_PROG_SED]) - - dnl Make LUA a precious variable. - AC_ARG_VAR([LUA], [The Lua interpreter, e.g. /usr/bin/lua5.1]) - - dnl Find a Lua interpreter. - m4_define_default([_AX_LUA_INTERPRETER_LIST], - [lua lua5.3 lua53 lua5.2 lua52 lua5.1 lua51 lua50]) - - m4_if([$1], [], - [ dnl No version check is needed. Find any Lua interpreter. - AS_IF([test "x$LUA" = 'x'], - [AC_PATH_PROGS([LUA], [_AX_LUA_INTERPRETER_LIST], [:])]) - ax_display_LUA='lua' - - AS_IF([test "x$LUA" != 'x:'], - [ dnl At least check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - ]) - ], - [ dnl A version check is needed. - AS_IF([test "x$LUA" != 'x'], - [ dnl Check if this is a Lua interpreter. - AC_MSG_CHECKING([if $LUA is a Lua interpreter]) - _AX_LUA_CHK_IS_INTRP([$LUA], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([not a Lua interpreter]) - ]) - dnl Check the version. - m4_if([$2], [], - [_ax_check_text="whether $LUA version >= $1"], - [_ax_check_text="whether $LUA version >= $1, < $2"]) - AC_MSG_CHECKING([$_ax_check_text]) - _AX_LUA_CHK_VER([$LUA], [$1], [$2], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([version is out of range for specified LUA])]) - ax_display_LUA=$LUA - ], - [ dnl Try each interpreter until we find one that satisfies VERSION. - m4_if([$2], [], - [_ax_check_text="for a Lua interpreter with version >= $1"], - [_ax_check_text="for a Lua interpreter with version >= $1, < $2"]) - AC_CACHE_CHECK([$_ax_check_text], - [ax_cv_pathless_LUA], - [ for ax_cv_pathless_LUA in _AX_LUA_INTERPRETER_LIST none; do - test "x$ax_cv_pathless_LUA" = 'xnone' && break - _AX_LUA_CHK_IS_INTRP([$ax_cv_pathless_LUA], [], [continue]) - _AX_LUA_CHK_VER([$ax_cv_pathless_LUA], [$1], [$2], [break]) - done - ]) - dnl Set $LUA to the absolute path of $ax_cv_pathless_LUA. - AS_IF([test "x$ax_cv_pathless_LUA" = 'xnone'], - [LUA=':'], - [AC_PATH_PROG([LUA], [$ax_cv_pathless_LUA])]) - ax_display_LUA=$ax_cv_pathless_LUA - ]) - ]) - - AS_IF([test "x$LUA" = 'x:'], - [ dnl Run any user-specified action, or abort. - m4_default([$4], [AC_MSG_ERROR([cannot find suitable Lua interpreter])]) - ], - [ dnl Query Lua for its version number. - AC_CACHE_CHECK([for $ax_display_LUA version], - [ax_cv_lua_version], - [ dnl Get the interpreter version in X.Y format. This should work for - dnl interpreters version 5.0 and beyond. - ax_cv_lua_version=[`$LUA -e ' - -- return a version number in X.Y format - local _, _, ver = string.find(_VERSION, "^Lua (%d+%.%d+)") - print(ver)'`] - ]) - AS_IF([test "x$ax_cv_lua_version" = 'x'], - [AC_MSG_ERROR([invalid Lua version number])]) - AC_SUBST([LUA_VERSION], [$ax_cv_lua_version]) - AC_SUBST([LUA_SHORT_VERSION], [`echo "$LUA_VERSION" | $SED 's|\.||'`]) - - dnl The following check is not supported: - dnl At times (like when building shared libraries) you may want to know - dnl which OS platform Lua thinks this is. - AC_CACHE_CHECK([for $ax_display_LUA platform], - [ax_cv_lua_platform], - [ax_cv_lua_platform=[`$LUA -e 'print("unknown")'`]]) - AC_SUBST([LUA_PLATFORM], [$ax_cv_lua_platform]) - - dnl Use the values of $prefix and $exec_prefix for the corresponding - dnl values of LUA_PREFIX and LUA_EXEC_PREFIX. These are made distinct - dnl variables so they can be overridden if need be. However, the general - dnl consensus is that you shouldn't need this ability. - AC_SUBST([LUA_PREFIX], ['${prefix}']) - AC_SUBST([LUA_EXEC_PREFIX], ['${exec_prefix}']) - - dnl Lua provides no way to query the script directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $prefix, then we can store scripts there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA script directory], - [ax_cv_lua_luadir], - [ AS_IF([test "x$prefix" = 'xNONE'], - [ax_lua_prefix=$ac_default_prefix], - [ax_lua_prefix=$prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luadir="$LUA_PREFIX/share/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], [$ax_lua_prefix], [script]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_prefix" | $SED 's|.|.|g'` - ax_cv_lua_luadir=`echo "$ax_lua_prefixed_path" | \ - $SED "s|^$_ax_strip_prefix|$LUA_PREFIX|"` - ]) - ]) - AC_SUBST([luadir], [$ax_cv_lua_luadir]) - AC_SUBST([pkgluadir], [\${luadir}/$PACKAGE]) - - dnl Lua provides no way to query the module directory, and instead - dnl provides LUA_PATH. However, we should be able to make a safe educated - dnl guess. If the built-in search path contains a directory which is - dnl prefixed by $exec_prefix, then we can store modules there. The first - dnl matching path will be used. - AC_CACHE_CHECK([for $ax_display_LUA module directory], - [ax_cv_lua_luaexecdir], - [ AS_IF([test "x$exec_prefix" = 'xNONE'], - [ax_lua_exec_prefix=$ax_lua_prefix], - [ax_lua_exec_prefix=$exec_prefix]) - - dnl Initialize to the default path. - ax_cv_lua_luaexecdir="$LUA_EXEC_PREFIX/lib/lua/$LUA_VERSION" - - dnl Try to find a path with the prefix. - _AX_LUA_FND_PRFX_PTH([$LUA], - [$ax_lua_exec_prefix], [module]) - AS_IF([test "x$ax_lua_prefixed_path" != 'x'], - [ dnl Fix the prefix. - _ax_strip_prefix=`echo "$ax_lua_exec_prefix" | $SED 's|.|.|g'` - ax_cv_lua_luaexecdir=`echo "$ax_lua_prefixed_path" | \ - $SED "s|^$_ax_strip_prefix|$LUA_EXEC_PREFIX|"` - ]) - ]) - AC_SUBST([luaexecdir], [$ax_cv_lua_luaexecdir]) - AC_SUBST([pkgluaexecdir], [\${luaexecdir}/$PACKAGE]) - - dnl Run any user specified action. - $3 - ]) -]) - -dnl AX_WITH_LUA is now the same thing as AX_PROG_LUA. -AC_DEFUN([AX_WITH_LUA], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_PROG_LUA instead]]) - AX_PROG_LUA -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_IS_INTRP(PROG, [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_IS_INTRP], -[ - dnl A minimal Lua factorial to prove this is an interpreter. This should work - dnl for Lua interpreters version 5.0 and beyond. - _ax_lua_factorial=[`$1 2>/dev/null -e ' - -- a simple factorial - function fact (n) - if n == 0 then - return 1 - else - return n * fact(n-1) - end - end - print("fact(5) is " .. fact(5))'`] - AS_IF([test "$_ax_lua_factorial" = 'fact(5) is 120'], - [$2], [$3]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_CHK_VER(PROG, MINIMUM-VERSION, [TOO-BIG-VERSION], -dnl [ACTION-IF-TRUE], [ACTION-IF-FALSE]) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_CHK_VER], -[ - dnl Check that the Lua version is within the bounds. Only the major and minor - dnl version numbers are considered. This should work for Lua interpreters - dnl version 5.0 and beyond. - _ax_lua_good_version=[`$1 -e ' - -- a script to compare versions - function verstr2num(verstr) - local _, _, majorver, minorver = string.find(verstr, "^(%d+)%.(%d+)") - if majorver and minorver then - return tonumber(majorver) * 100 + tonumber(minorver) - end - end - local minver = verstr2num("$2") - local _, _, trimver = string.find(_VERSION, "^Lua (.*)") - local ver = verstr2num(trimver) - local maxver = verstr2num("$3") or 1e9 - if minver <= ver and ver < maxver then - print("yes") - else - print("no") - end'`] - AS_IF([test "x$_ax_lua_good_version" = "xyes"], - [$4], [$5]) -]) - - -dnl ========================================================================= -dnl _AX_LUA_FND_PRFX_PTH(PROG, PREFIX, SCRIPT-OR-MODULE-DIR) -dnl ========================================================================= -AC_DEFUN([_AX_LUA_FND_PRFX_PTH], -[ - dnl Get the script or module directory by querying the Lua interpreter, - dnl filtering on the given prefix, and selecting the shallowest path. If no - dnl path is found matching the prefix, the result will be an empty string. - dnl The third argument determines the type of search, it can be 'script' or - dnl 'module'. Supplying 'script' will perform the search with package.path - dnl and LUA_PATH, and supplying 'module' will search with package.cpath and - dnl LUA_CPATH. This is done for compatibility with Lua 5.0. - - ax_lua_prefixed_path=[`$1 -e ' - -- get the path based on search type - local searchtype = "$3" - local paths = "" - if searchtype == "script" then - paths = (package and package.path) or LUA_PATH - elseif searchtype == "module" then - paths = (package and package.cpath) or LUA_CPATH - end - -- search for the prefix - local prefix = "'$2'" - local minpath = "" - local mindepth = 1e9 - string.gsub(paths, "(@<:@^;@:>@+)", - function (path) - path = string.gsub(path, "%?.*$", "") - path = string.gsub(path, "/@<:@^/@:>@*$", "") - if string.find(path, prefix) then - local depth = string.len(string.gsub(path, "@<:@^/@:>@", "")) - if depth < mindepth then - minpath = path - mindepth = depth - end - end - end) - print(minpath)'`] -]) - - -dnl ========================================================================= -dnl AX_LUA_HEADERS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_HEADERS], -[ - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua headers without knowing LUA_VERSION]) - ]) - - dnl Make LUA_INCLUDE a precious variable. - AC_ARG_VAR([LUA_INCLUDE], [The Lua includes, e.g. -I/usr/include/lua5.1]) - - dnl Some default directories to search. - LUA_SHORT_VERSION=`echo "$LUA_VERSION" | $SED 's|\.||'` - m4_define_default([_AX_LUA_INCLUDE_LIST], - [ /usr/include/lua$LUA_VERSION \ - /usr/include/lua-$LUA_VERSION \ - /usr/include/lua/$LUA_VERSION \ - /usr/include/lua$LUA_SHORT_VERSION \ - /usr/local/include/lua$LUA_VERSION \ - /usr/local/include/lua-$LUA_VERSION \ - /usr/local/include/lua/$LUA_VERSION \ - /usr/local/include/lua$LUA_SHORT_VERSION \ - ]) - - dnl Try to find the headers. - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - dnl Try some other directories if LUA_INCLUDE was not set. - AS_IF([test "x$LUA_INCLUDE" = 'x' && - test "x$ac_cv_header_lua_h" != 'xyes'], - [ dnl Try some common include paths. - for _ax_include_path in _AX_LUA_INCLUDE_LIST; do - test ! -d "$_ax_include_path" && continue - - AC_MSG_CHECKING([for Lua headers in]) - AC_MSG_RESULT([$_ax_include_path]) - - AS_UNSET([ac_cv_header_lua_h]) - AS_UNSET([ac_cv_header_lualib_h]) - AS_UNSET([ac_cv_header_lauxlib_h]) - AS_UNSET([ac_cv_header_luaconf_h]) - - _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS -I$_ax_include_path" - AC_CHECK_HEADERS([lua.h lualib.h lauxlib.h luaconf.h]) - CPPFLAGS=$_ax_lua_saved_cppflags - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ LUA_INCLUDE="-I$_ax_include_path" - break - ]) - done - ]) - - AS_IF([test "x$ac_cv_header_lua_h" = 'xyes'], - [ dnl Make a program to print LUA_VERSION defined in the header. - dnl TODO It would be really nice if we could do this without compiling a - dnl program, then it would work when cross compiling. But I'm not sure how - dnl to do this reliably. For now, assume versions match when cross compiling. - - AS_IF([test "x$cross_compiling" != 'xyes'], - [ AC_CACHE_CHECK([for Lua header version], - [ax_cv_lua_header_version], - [ _ax_lua_saved_cppflags=$CPPFLAGS - CPPFLAGS="$CPPFLAGS $LUA_INCLUDE" - AC_RUN_IFELSE( - [ AC_LANG_SOURCE([[ -#include <lua.h> -#include <stdlib.h> -#include <stdio.h> -int main(int argc, char ** argv) -{ - if(argc > 1) printf("%s", LUA_VERSION); - exit(EXIT_SUCCESS); -} -]]) - ], - [ ax_cv_lua_header_version=`./conftest$EXEEXT p | \ - $SED -n "s|^Lua \(@<:@0-9@:>@\{1,\}\.@<:@0-9@:>@\{1,\}\).\{0,\}|\1|p"` - ], - [ax_cv_lua_header_version='unknown']) - CPPFLAGS=$_ax_lua_saved_cppflags - ]) - - dnl Compare this to the previously found LUA_VERSION. - AC_MSG_CHECKING([if Lua header version matches $LUA_VERSION]) - AS_IF([test "x$ax_cv_lua_header_version" = "x$LUA_VERSION"], - [ AC_MSG_RESULT([yes]) - ax_header_version_match='yes' - ], - [ AC_MSG_RESULT([no]) - ax_header_version_match='no' - ]) - ], - [ AC_MSG_WARN([cross compiling so assuming header version number matches]) - ax_header_version_match='yes' - ]) - ]) - - dnl Was LUA_INCLUDE specified? - AS_IF([test "x$ax_header_version_match" != 'xyes' && - test "x$LUA_INCLUDE" != 'x'], - [AC_MSG_ERROR([cannot find headers for specified LUA_INCLUDE])]) - - dnl Test the final result and run user code. - AS_IF([test "x$ax_header_version_match" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua includes])])]) -]) - -dnl AX_LUA_HEADERS_VERSION no longer exists, use AX_LUA_HEADERS. -AC_DEFUN([AX_LUA_HEADERS_VERSION], -[ - AC_MSG_WARN([[$0 is deprecated, please use AX_LUA_HEADERS instead]]) -]) - - -dnl ========================================================================= -dnl AX_LUA_LIBS([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_LIBS], -[ - dnl TODO Should this macro also check various -L flags? - - dnl Check for LUA_VERSION. - AC_MSG_CHECKING([if LUA_VERSION is defined]) - AS_IF([test "x$LUA_VERSION" != 'x'], - [AC_MSG_RESULT([yes])], - [ AC_MSG_RESULT([no]) - AC_MSG_ERROR([cannot check Lua libs without knowing LUA_VERSION]) - ]) - - dnl Make LUA_LIB a precious variable. - AC_ARG_VAR([LUA_LIB], [The Lua library, e.g. -llua5.1]) - - AS_IF([test "x$LUA_LIB" != 'x'], - [ dnl Check that LUA_LIBS works. - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([lua_load], [], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no']) - LIBS=$_ax_lua_saved_libs - - dnl Check the result. - AS_IF([test "x$_ax_found_lua_libs" != 'xyes'], - [AC_MSG_ERROR([cannot find libs for specified LUA_LIB])]) - ], - [ dnl First search for extra libs. - _ax_lua_extra_libs='' - - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([exp], [m]) - AC_SEARCH_LIBS([dlopen], [dl]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_exp" != 'xno' && - test "x$ac_cv_search_exp" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_exp"]) - - AS_IF([test "x$ac_cv_search_dlopen" != 'xno' && - test "x$ac_cv_search_dlopen" != 'xnone required'], - [_ax_lua_extra_libs="$_ax_lua_extra_libs $ac_cv_search_dlopen"]) - - dnl Try to find the Lua libs. - _ax_lua_saved_libs=$LIBS - LIBS="$LUA_LIB $LIBS" - AC_SEARCH_LIBS([lua_load], - [ lua$LUA_VERSION \ - lua$LUA_SHORT_VERSION \ - lua-$LUA_VERSION \ - lua-$LUA_SHORT_VERSION \ - lua \ - ], - [_ax_found_lua_libs='yes'], - [_ax_found_lua_libs='no'], - [$_ax_lua_extra_libs]) - LIBS=$_ax_lua_saved_libs - - AS_IF([test "x$ac_cv_search_lua_load" != 'xno' && - test "x$ac_cv_search_lua_load" != 'xnone required'], - [LUA_LIB="$ac_cv_search_lua_load $_ax_lua_extra_libs"]) - ]) - - dnl Test the result and run user code. - AS_IF([test "x$_ax_found_lua_libs" = 'xyes'], [$1], - [m4_default([$2], [AC_MSG_ERROR([cannot find Lua libs])])]) -]) - - -dnl ========================================================================= -dnl AX_LUA_READLINE([ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) -dnl ========================================================================= -AC_DEFUN([AX_LUA_READLINE], -[ - AX_LIB_READLINE - AS_IF([test "x$ac_cv_header_readline_readline_h" != 'x' && - test "x$ac_cv_header_readline_history_h" != 'x'], - [ LUA_LIBS_CFLAGS="-DLUA_USE_READLINE $LUA_LIBS_CFLAGS" - $1 - ], - [$2]) -]) diff --git a/contrib/libucl/m4/gcov.m4 b/contrib/libucl/m4/gcov.m4 deleted file mode 100644 index a1359a0de64b..000000000000 --- a/contrib/libucl/m4/gcov.m4 +++ /dev/null @@ -1,89 +0,0 @@ -# SYNOPSIS -# -# Add code coverage support with gcov/lcov. -# -# AX_CODE_COVERAGE() -# -# DESCRIPTION -# -# Provides a --enable-coverage option which checks for available -# gcov/lcov binaries and provides ENABLE_CODE_COVERAGE conditional. -# -# LAST MODIFICATION -# -# $Id: coverage.m4 40881 2013-08-20 17:54:39Z damon $ -# -# COPYLEFT -# -# Copyright (c) 2012 Roy H. Stogner <roystgnr@ices.utexas.edu> -# Copyright (c) 2010 Karl W. Schulz <karl@ices.utexas.edu> -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. - -AC_DEFUN([AX_CODE_COVERAGE], -[ - -AC_ARG_ENABLE(coverage, AC_HELP_STRING([--enable-coverage],[configure code coverage analysis tools])) - -HAVE_GCOV_TOOLS=0 - -GCOV_FLAGS="" - -if test "x$enable_coverage" = "xyes"; then - - # ---------------------------- - # Check for gcov/lcov binaries - # ---------------------------- - - AC_ARG_VAR([GCOV], [Coverage testing command]) - if test "x$GCOV" = "x"; then - AC_PATH_PROG(GCOV, gcov, no) - else - AC_PATH_PROG(GCOV, $GCOV, no) - fi - - AC_PATH_PROG(LCOV, lcov, no) - AC_PATH_PROG(GENHTML, genhtml) - - # ---------------------------------- - # include coverage compiler options - # ---------------------------------- - AC_MSG_CHECKING([for clang]) - - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM([], [[ - #ifndef __clang__ - not clang - #endif - ]])], - [CLANG=yes], [CLANG=no]) - - AC_MSG_RESULT([$CLANG]) - HAVE_GCOV_TOOLS=1 - COVERAGE_CFLAGS="-fprofile-arcs -ftest-coverage" - COVERAGE_LDFLAGS="--coverage -fprofile-arcs -ftest-coverage" - COVERAGE_OPTFLAGS="-O0" - - # Test for C... - CFLAGS="${GCOV_FLAGS} ${CFLAGS}" - CXXFLAGS="${GCOV_FLAGS} ${CXXFLAGS}" - if test "x$GCC" = "xyes" -a "x$CLANG" = "xno"; then - COVERAGE_LIBS="-lgcov" - else - COVERAGE_LIBS="" - fi -fi - -AC_SUBST([GCOV]) -AC_SUBST([LCOV]) -AC_SUBST([GENHTML]) -AC_SUBST([GENHTML_OPTIONS]) -AC_SUBST([COVERAGE_CFLAGS]) -AC_SUBST([COVERAGE_OPTFLAGS]) -AC_SUBST([COVERAGE_LDFLAGS]) -AC_SUBST([COVERAGE_LIBS]) -AM_CONDITIONAL(CODE_COVERAGE_ENABLED,test x$HAVE_GCOV_TOOLS = x1) - -]) diff --git a/contrib/libucl/python/MANIFEST.in b/contrib/libucl/python/MANIFEST.in deleted file mode 100644 index 336a4b3a7a07..000000000000 --- a/contrib/libucl/python/MANIFEST.in +++ /dev/null @@ -1,5 +0,0 @@ -include COPYING -recursive-include include *.h -recursive-include src *.h -recursive-include klib *.h -recursive-include uthash *.h diff --git a/contrib/libucl/python/setup.py b/contrib/libucl/python/setup.py deleted file mode 100644 index 8da832bac381..000000000000 --- a/contrib/libucl/python/setup.py +++ /dev/null @@ -1,75 +0,0 @@ -try: - from setuptools import setup, Extension - # setuptools doesn't support template param for MANIFEST.in - from setuptools.command.egg_info import manifest_maker - manifest_maker.template = 'python/MANIFEST.in' -except ImportError: - from distutils.core import setup, Extension - -import os -import sys - -LIB_ROOT = os.path.abspath(os.path.join(__file__, os.pardir, os.pardir)) -if os.getcwd() != LIB_ROOT: - os.chdir(LIB_ROOT) -if LIB_ROOT not in sys.path: - sys.path.append(LIB_ROOT) - -tests_require = [] - -if sys.version < '2.7': - tests_require.append('unittest2') - -uclmodule = Extension( - 'ucl', - libraries=['ucl', 'curl'], - sources=['python/src/uclmodule.c'], - include_dirs=['include'], - language='c', -) - -ucl_lib = { - 'sources': ['src/' + fn for fn in os.listdir('src') if fn.endswith('.c')], - 'include_dirs': ['include', 'src', 'uthash', 'klib'], - 'macros': [('CURL_FOUND', '1')], -} - -# sdist setup() will pull in the *.c files automatically, but not headers -# MANIFEST.in will include the headers for sdist only -template = 'python/MANIFEST.in' - -# distutils assume setup.py is in the root of the project -# we need to include C source from the parent so trick it -in_ucl_root = 'setup.py' in os.listdir('python') -if in_ucl_root: - os.link('python/setup.py', 'setup.py') - -setup( - name = 'ucl', - version = '0.8.1', - description = 'ucl parser and emitter', - ext_modules = [uclmodule], - template=template, # no longer supported with setuptools but doesn't hurt - libraries = [('ucl', ucl_lib)], - test_suite = 'tests', - tests_require = tests_require, - author = "Eitan Adler, Denis Volpato Martins", - author_email = "lists@eitanadler.com", - url = "https://github.com/vstakhov/libucl/", - license = "MIT", - classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: DFSG approved", - "License :: OSI Approved :: MIT License", - "Programming Language :: C", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: Implementation :: CPython", - "Topic :: Software Development :: Libraries", - ] -) - -# clean up the trick after the build -if in_ucl_root: - os.unlink("setup.py") diff --git a/contrib/libucl/python/src/uclmodule.c b/contrib/libucl/python/src/uclmodule.c deleted file mode 100644 index d1051fbb0d12..000000000000 --- a/contrib/libucl/python/src/uclmodule.c +++ /dev/null @@ -1,335 +0,0 @@ -// Attempts to load a UCL structure from a string -#include <ucl.h> -#include <Python.h> - -static PyObject *SchemaError; - -static PyObject * -_basic_ucl_type (ucl_object_t const *obj) -{ - switch (obj->type) { - case UCL_INT: - return Py_BuildValue ("L", (long long)ucl_object_toint (obj)); - case UCL_FLOAT: - return Py_BuildValue ("d", ucl_object_todouble (obj)); - case UCL_STRING: - return Py_BuildValue ("s", ucl_object_tostring (obj)); - case UCL_BOOLEAN: - return PyBool_FromLong (ucl_object_toboolean (obj)); - case UCL_TIME: - return Py_BuildValue ("d", ucl_object_todouble (obj)); - case UCL_NULL: - Py_RETURN_NONE; - } - return NULL; -} - -static PyObject * -_iterate_valid_ucl (ucl_object_t const *obj) -{ - const ucl_object_t *tmp; - ucl_object_iter_t it = NULL; - - tmp = obj; - - while ((obj = ucl_object_iterate (tmp, &it, false))) { - PyObject *val; - - val = _basic_ucl_type(obj); - if (!val) { - PyObject *key = NULL; - - if (obj->key != NULL) { - key = Py_BuildValue("s", ucl_object_key(obj)); - } - - if (obj->type == UCL_OBJECT) { - const ucl_object_t *cur; - ucl_object_iter_t it_obj = NULL; - - val = PyDict_New(); - - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - PyObject *keyobj = Py_BuildValue("s",ucl_object_key(cur)); - PyDict_SetItem(val, keyobj, _iterate_valid_ucl(cur)); - } - } else if (obj->type == UCL_ARRAY) { - const ucl_object_t *cur; - ucl_object_iter_t it_obj = NULL; - - val = PyList_New(0); - - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - PyList_Append(val, _iterate_valid_ucl(cur)); - } - } else if (obj->type == UCL_USERDATA) { - // XXX: this should be - // PyBytes_FromStringAndSize; where is the - // length from? - val = PyBytes_FromString(obj->value.ud); - } - } - return val; - } - - PyErr_SetString(PyExc_SystemError, "unhandled type"); - return NULL; -} - -static PyObject * -_internal_load_ucl (char *uclstr) -{ - PyObject *ret; - struct ucl_parser *parser = - ucl_parser_new (UCL_PARSER_NO_TIME|UCL_PARSER_NO_IMPLICIT_ARRAYS); - bool r = ucl_parser_add_string(parser, uclstr, 0); - - if (r) { - if (ucl_parser_get_error (parser)) { - PyErr_SetString(PyExc_ValueError, ucl_parser_get_error(parser)); - ucl_parser_free(parser); - ret = NULL; - goto return_with_parser; - } else { - ucl_object_t *uclobj = ucl_parser_get_object(parser); - ret = _iterate_valid_ucl(uclobj); - ucl_object_unref(uclobj); - goto return_with_parser; - } - } - else { - PyErr_SetString(PyExc_ValueError, ucl_parser_get_error (parser)); - ret = NULL; - goto return_with_parser; - } - -return_with_parser: - ucl_parser_free(parser); - return ret; -} - -static PyObject* -ucl_load (PyObject *self, PyObject *args) -{ - char *uclstr; - - if (PyArg_ParseTuple(args, "z", &uclstr)) { - if (!uclstr) { - Py_RETURN_NONE; - } - - return _internal_load_ucl(uclstr); - } - - return NULL; -} - -static ucl_object_t * -_iterate_python (PyObject *obj) -{ - if (obj == Py_None) { - return ucl_object_new(); - } - else if (PyBool_Check (obj)) { - return ucl_object_frombool (obj == Py_True); - } -#if PY_MAJOR_VERSION < 3 - else if (PyInt_Check (obj)) { - return ucl_object_fromint (PyInt_AsLong (obj)); - } -#endif - else if (PyLong_Check (obj)) { - return ucl_object_fromint (PyLong_AsLong (obj)); - } - else if (PyFloat_Check (obj)) { - return ucl_object_fromdouble (PyFloat_AsDouble (obj)); - } - else if (PyUnicode_Check (obj)) { - ucl_object_t *ucl_str; - PyObject *str = PyUnicode_AsASCIIString(obj); - ucl_str = ucl_object_fromstring (PyBytes_AsString (str)); - Py_DECREF(str); - return ucl_str; - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check (obj)) { - return ucl_object_fromstring (PyString_AsString (obj)); - } -#endif - else if (PyDict_Check(obj)) { - PyObject *key, *value; - Py_ssize_t pos = 0; - ucl_object_t *top, *elm; - char *keystr = NULL; - - top = ucl_object_typed_new (UCL_OBJECT); - - while (PyDict_Next(obj, &pos, &key, &value)) { - elm = _iterate_python(value); - - if (PyUnicode_Check(key)) { - PyObject *keyascii = PyUnicode_AsASCIIString(key); - keystr = PyBytes_AsString(keyascii); - Py_DECREF(keyascii); - } -#if PY_MAJOR_VERSION < 3 - else if (PyString_Check(key)) { - keystr = PyString_AsString(key); - } -#endif - else { - PyErr_SetString(PyExc_TypeError, "Unknown key type"); - return NULL; - } - - ucl_object_insert_key (top, elm, keystr, 0, true); - } - - return top; - } - else if (PySequence_Check(obj)) { - PyObject *value; - Py_ssize_t len, pos; - ucl_object_t *top, *elm; - - len = PySequence_Length(obj); - top = ucl_object_typed_new (UCL_ARRAY); - - for (pos = 0; pos < len; pos++) { - value = PySequence_GetItem(obj, pos); - elm = _iterate_python(value); - ucl_array_append(top, elm); - } - - return top; - } - else { - PyErr_SetString(PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - return NULL; -} - -static PyObject * -ucl_dump (PyObject *self, PyObject *args) -{ - PyObject *obj; - ucl_emitter_t emitter; - ucl_object_t *root = NULL; - - emitter = UCL_EMIT_CONFIG; - - if (!PyArg_ParseTuple(args, "O|i", &obj, &emitter)) { - PyErr_SetString(PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - if (emitter >= UCL_EMIT_MAX) { - PyErr_SetString(PyExc_TypeError, "Invalid emitter type"); - return NULL; - } - - if (obj == Py_None) { - Py_RETURN_NONE; - } - - root = _iterate_python(obj); - if (root) { - PyObject *ret; - char *buf; - - buf = (char *) ucl_object_emit (root, emitter); - ucl_object_unref (root); -#if PY_MAJOR_VERSION < 3 - ret = PyString_FromString (buf); -#else - ret = PyUnicode_FromString (buf); -#endif - free(buf); - - return ret; - } - - return NULL; -} - -static PyObject * -ucl_validate (PyObject *self, PyObject *args) -{ - PyObject *dataobj, *schemaobj; - ucl_object_t *data, *schema; - bool r; - struct ucl_schema_error err; - - if (!PyArg_ParseTuple (args, "OO", &schemaobj, &dataobj)) { - PyErr_SetString (PyExc_TypeError, "Unhandled object type"); - return NULL; - } - - schema = _iterate_python(schemaobj); - if (!schema) - return NULL; - - data = _iterate_python(dataobj); - if (!data) - return NULL; - - // validation - r = ucl_object_validate (schema, data, &err); - ucl_object_unref (schema); - ucl_object_unref (data); - - if (!r) { - PyErr_SetString (SchemaError, err.msg); - return NULL; - } - - Py_RETURN_TRUE; -} - -static PyMethodDef uclMethods[] = { - {"load", ucl_load, METH_VARARGS, "Load UCL from stream"}, - {"dump", ucl_dump, METH_VARARGS, "Dump UCL to stream"}, - {"validate", ucl_validate, METH_VARARGS, "Validate ucl stream against schema"}, - {NULL, NULL, 0, NULL} -}; - -static void -init_macros(PyObject *mod) -{ - PyModule_AddIntMacro(mod, UCL_EMIT_JSON); - PyModule_AddIntMacro(mod, UCL_EMIT_JSON_COMPACT); - PyModule_AddIntMacro(mod, UCL_EMIT_CONFIG); - PyModule_AddIntMacro(mod, UCL_EMIT_YAML); - PyModule_AddIntMacro(mod, UCL_EMIT_MSGPACK); - - SchemaError = PyErr_NewException("ucl.SchemaError", NULL, NULL); - Py_INCREF(SchemaError); - PyModule_AddObject(mod, "SchemaError", SchemaError); -} - -#if PY_MAJOR_VERSION >= 3 -static struct PyModuleDef uclmodule = { - PyModuleDef_HEAD_INIT, - "ucl", - NULL, - -1, - uclMethods -}; - -PyMODINIT_FUNC -PyInit_ucl (void) -{ - PyObject *mod = PyModule_Create (&uclmodule); - init_macros (mod); - - return mod; -} -#else -void initucl (void) -{ - PyObject *mod = Py_InitModule ("ucl", uclMethods); - init_macros (mod); -} -#endif diff --git a/contrib/libucl/python/tests/__init__.py b/contrib/libucl/python/tests/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 --- a/contrib/libucl/python/tests/__init__.py +++ /dev/null diff --git a/contrib/libucl/python/tests/compat.py b/contrib/libucl/python/tests/compat.py deleted file mode 100644 index 50138262e9b7..000000000000 --- a/contrib/libucl/python/tests/compat.py +++ /dev/null @@ -1,8 +0,0 @@ -try: - import unittest2 as unittest -except ImportError: - import unittest - -# Python 2.7 - 3.1 -if not hasattr(unittest.TestCase, 'assertRaisesRegex'): - unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp diff --git a/contrib/libucl/python/tests/test_dump.py b/contrib/libucl/python/tests/test_dump.py deleted file mode 100644 index 369241468509..000000000000 --- a/contrib/libucl/python/tests/test_dump.py +++ /dev/null @@ -1,66 +0,0 @@ -from .compat import unittest -import ucl -import sys - -class DumpTest(unittest.TestCase): - def test_no_args(self): - with self.assertRaises(TypeError): - ucl.dump() - - def test_none(self): - self.assertEqual(ucl.dump(None), None) - - def test_null(self): - data = { "a" : None } - valid = "a = null;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_int(self): - data = { "a" : 1 } - valid = "a = 1;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_nested_int(self): - data = { "a" : { "b" : 1 } } - valid = "a {\n b = 1;\n}\n" - self.assertEqual(ucl.dump(data), valid) - - def test_int_array(self): - data = { "a" : [1,2,3,4] } - valid = "a [\n 1,\n 2,\n 3,\n 4,\n]\n" - self.assertEqual(ucl.dump(data), valid) - - def test_str(self): - data = { "a" : "b" } - valid = "a = \"b\";\n" - self.assertEqual(ucl.dump(data), valid) - - @unittest.skipIf(sys.version_info[0] > 2, "Python3 uses unicode only") - def test_unicode(self): - data = { unicode("a") : unicode("b") } - valid = unicode("a = \"b\";\n") - self.assertEqual(ucl.dump(data), valid) - - def test_float(self): - data = { "a" : 1.1 } - valid = "a = 1.100000;\n" - self.assertEqual(ucl.dump(data), valid) - - def test_boolean(self): - data = { "a" : True, "b" : False } - valid = [ - "a = true;\nb = false;\n", - "b = false;\na = true;\n" - ] - self.assertIn(ucl.dump(data), valid) - - def test_empty_ucl(self): - self.assertEqual(ucl.dump({}), "") - - def test_json(self): - data = { "a" : 1, "b": "bleh;" } - valid = [ - '{\n "a": 1,\n "b": "bleh;"\n}', - '{\n "b": "bleh;",\n "a": 1\n}' - ] - self.assertIn(ucl.dump(data, ucl.UCL_EMIT_JSON), valid) diff --git a/contrib/libucl/python/tests/test_example.py b/contrib/libucl/python/tests/test_example.py deleted file mode 100644 index f0785531f4e2..000000000000 --- a/contrib/libucl/python/tests/test_example.py +++ /dev/null @@ -1,59 +0,0 @@ -from .compat import unittest -import json -import ucl - -_ucl_inp = ''' -param = value; -section { - param = value; - param1 = value1; - flag = true; - number = 10k; - time = 0.2s; - string = "something"; - subsection { - host = { - host = "hostname"; - port = 900; - } - host = { - host = "hostname"; - port = 901; - } - } -} -''' - -_json_res = { - 'param': 'value', - 'section': { - 'param': 'value', - 'param1': 'value1', - 'flag': True, - 'number': 10000, - 'time': '0.2s', - 'string': 'something', - 'subsection': { - 'host': [ - { - 'host': 'hostname', - 'port': 900, - }, - { - 'host': 'hostname', - 'port': 901, - } - ] - } - } -} - -class TestExample(unittest.TestCase): - def test_example(self): - # load in sample UCL - u = ucl.load(_ucl_inp) - - # Output and read back the JSON - uj = json.loads(json.dumps(u)) - - self.assertEqual(uj, _json_res) diff --git a/contrib/libucl/python/tests/test_load.py b/contrib/libucl/python/tests/test_load.py deleted file mode 100644 index 73d43188f3d5..000000000000 --- a/contrib/libucl/python/tests/test_load.py +++ /dev/null @@ -1,122 +0,0 @@ -from .compat import unittest -import ucl - -class LoadTest(unittest.TestCase): - def test_no_args(self): - with self.assertRaises(TypeError): - ucl.load() - - def test_multi_args(self): - with self.assertRaises(TypeError): - ucl.load(0,0) - - def test_none(self): - self.assertEqual(ucl.load(None), None) - - def test_null(self): - data = "a: null" - valid = { "a" : None } - self.assertEqual(ucl.load(data), valid) - - def test_int(self): - data = "a : 1" - valid = { "a" : 1 } - self.assertEqual(ucl.load(data), valid) - - def test_braced_int(self): - data = "{a : 1}" - valid = { "a" : 1 } - self.assertEqual(ucl.load(data), valid) - - def test_nested_int(self): - data = "a : { b : 1 }" - valid = { "a" : { "b" : 1 } } - self.assertEqual(ucl.load(data), valid) - - def test_str(self): - data = "a : b" - valid = { "a" : "b" } - self.assertEqual(ucl.load(data), valid) - - def test_float(self): - data = "a : 1.1" - valid = {"a" : 1.1} - self.assertEqual(ucl.load(data), valid) - - def test_boolean(self): - data = ( - "a : True;" \ - "b : False" - ) - valid = { "a" : True, "b" : False } - self.assertEqual(ucl.load(data), valid) - - def test_empty_ucl(self): - self.assertEqual(ucl.load("{}"), {}) - - def test_single_brace(self): - self.assertEqual(ucl.load("{"), {}) - - def test_single_back_brace(self): - self.assertEqual(ucl.load("}"), {}) - - def test_single_square_forward(self): - self.assertEqual(ucl.load("["), []) - - def test_invalid_ucl(self): - with self.assertRaisesRegex(ValueError, "unfinished key$"): - ucl.load('{ "var"') - - def test_comment_ignored(self): - self.assertEqual(ucl.load("{/*1*/}"), {}) - - def test_1_in(self): - valid = { - 'key1': [ - 'value', - 'value2', - 'value;', - 1.0, - -0xdeadbeef, - '0xdeadbeef.1', - '0xreadbeef', - -1e-10, - 1, - True, - False, - True, - ] - } - with open("../tests/basic/1.in", "r") as in1: - self.assertEqual(ucl.load(in1.read()), valid) - - def test_every_type(self): - data = ("""{ - "key1": value; - "key2": value2; - "key3": "value;" - "key4": 1.0, - "key5": -0xdeadbeef - "key6": 0xdeadbeef.1 - "key7": 0xreadbeef - "key8": -1e-10, - "key9": 1 - "key10": true - "key11": no - "key12": yes - }""") - valid = { - 'key1': 'value', - 'key2': 'value2', - 'key3': 'value;', - 'key4': 1.0, - 'key5': -3735928559, - 'key6': '0xdeadbeef.1', - 'key7': '0xreadbeef', - 'key8': -1e-10, - 'key9': 1, - 'key10': True, - 'key11': False, - 'key12': True, - } - self.assertEqual(ucl.load(data), valid) diff --git a/contrib/libucl/python/tests/test_validation.py b/contrib/libucl/python/tests/test_validation.py deleted file mode 100644 index f7c853ad69a7..000000000000 --- a/contrib/libucl/python/tests/test_validation.py +++ /dev/null @@ -1,50 +0,0 @@ -from .compat import unittest -import ucl -import json -import os.path -import glob -import re - -TESTS_SCHEMA_FOLDER = '../tests/schema/*.json' - -comment_re = re.compile('\/\*((?!\*\/).)*?\*\/', re.DOTALL | re.MULTILINE) -def json_remove_comments(content): - return comment_re.sub('', content) - -class ValidationTest(unittest.TestCase): - def validate(self, jsonfile): - def perform_test(schema, data, valid, description): - msg = '%s (valid=%r)' % (description, valid) - if valid: - self.assertTrue(ucl.validate(schema, data), msg) - else: - with self.assertRaises(ucl.SchemaError): - ucl.validate(schema, data) - self.fail(msg) # fail() will be called only if SchemaError is not raised - - with open(jsonfile) as f: - try: - # data = json.load(f) - data = json.loads(json_remove_comments(f.read())) - except ValueError as e: - raise self.skipTest('Failed to load JSON: %s' % str(e)) - - for testgroup in data: - for test in testgroup['tests']: - perform_test(testgroup['schema'], test['data'], - test['valid'], test['description']) - - @classmethod - def setupValidationTests(cls): - """Creates each test dynamically from a folder""" - def test_gen(filename): - def run_test(self): - self.validate(filename) - return run_test - - for jsonfile in glob.glob(TESTS_SCHEMA_FOLDER): - testname = os.path.splitext(os.path.basename(jsonfile))[0] - setattr(cls, 'test_%s' % testname, test_gen(jsonfile)) - - -ValidationTest.setupValidationTests() diff --git a/contrib/libucl/python/ucl.pyi b/contrib/libucl/python/ucl.pyi deleted file mode 100644 index 79fa2901ba9f..000000000000 --- a/contrib/libucl/python/ucl.pyi +++ /dev/null @@ -1,15 +0,0 @@ -# Stubs for ucl (Python 3.6) -# -# NOTE: This dynamically typed stub was automatically generated by stubgen. - -UCL_EMIT_CONFIG = ... # type: int -UCL_EMIT_JSON = ... # type: int -UCL_EMIT_JSON_COMPACT = ... # type: int -UCL_EMIT_MSGPACK = ... # type: int -UCL_EMIT_YAML = ... # type: int - -def dump(*args, **kwargs): ... -def load(*args, **kwargs): ... -def validate(*args, **kwargs): ... - -class SchemaError(Exception): ... diff --git a/contrib/libucl/src/Makefile.am b/contrib/libucl/src/Makefile.am deleted file mode 100644 index 80ce5b185b83..000000000000 --- a/contrib/libucl/src/Makefile.am +++ /dev/null @@ -1,30 +0,0 @@ -libucl_common_cflags= -I$(top_srcdir)/src \ - -I$(top_srcdir)/include \ - -I$(top_srcdir)/uthash \ - -I$(top_srcdir)/klib \ - -Wall -W -Wno-unused-parameter -Wno-pointer-sign -lib_LTLIBRARIES= libucl.la -libucl_la_SOURCES= ucl_emitter.c \ - ucl_emitter_streamline.c \ - ucl_emitter_utils.c \ - ucl_hash.c \ - ucl_parser.c \ - ucl_schema.c \ - ucl_util.c \ - ucl_msgpack.c \ - ucl_sexp.c -libucl_la_CFLAGS= $(libucl_common_cflags) \ - @CURL_CFLAGS@ -libucl_la_LDFLAGS = -version-info @SO_VERSION@ -libucl_la_LIBADD= @LIBFETCH_LIBS@ \ - @LIBCRYPTO_LIB@ \ - @LIBREGEX_LIB@ \ - @CURL_LIBS@ - -include_HEADERS= $(top_srcdir)/include/ucl.h \ - $(top_srcdir)/include/ucl++.h -noinst_HEADERS= ucl_internal.h \ - mum.h \ - ucl_hash.h \ - ucl_chartable.h \ - tree.h diff --git a/contrib/libucl/src/mum.h b/contrib/libucl/src/mum.h index 148161a3ec58..318efea50268 100644 --- a/contrib/libucl/src/mum.h +++ b/contrib/libucl/src/mum.h @@ -69,11 +69,9 @@ typedef unsigned __int64 uint64_t; #endif #endif -#if 0 #if defined(__GNUC__) && ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 9) || (__GNUC__ > 4)) #define _MUM_FRESH_GCC #endif -#endif #if defined(__GNUC__) && !defined(__llvm__) && defined(_MUM_FRESH_GCC) #define _MUM_ATTRIBUTE_UNUSED __attribute__((unused)) diff --git a/contrib/libucl/src/ucl_emitter.c b/contrib/libucl/src/ucl_emitter.c index 4f4465dfbf4a..97d8f618021f 100644 --- a/contrib/libucl/src/ucl_emitter.c +++ b/contrib/libucl/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/contrib/libucl/src/ucl_emitter_streamline.c b/contrib/libucl/src/ucl_emitter_streamline.c index a7178c5d74b0..8ca86fa081c9 100644 --- a/contrib/libucl/src/ucl_emitter_streamline.c +++ b/contrib/libucl/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/contrib/libucl/src/ucl_hash.c b/contrib/libucl/src/ucl_hash.c index a74dfcdee68e..0208cfd29c9a 100644 --- a/contrib/libucl/src/ucl_hash.c +++ b/contrib/libucl/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/contrib/libucl/src/ucl_msgpack.c b/contrib/libucl/src/ucl_msgpack.c index 08e690a4728a..628ed2be993d 100644 --- a/contrib/libucl/src/ucl_msgpack.c +++ b/contrib/libucl/src/ucl_msgpack.c @@ -1246,8 +1246,8 @@ ucl_msgpack_consume (struct ucl_parser *parser) /* Empty container at the end */ if (len != 0) { ucl_create_err (&parser->err, - "invalid non-empty container at the end; len=%zu", - (size_t)len); + "invalid non-empty container at the end; len=%ju", + (uintmax_t)len); return false; } diff --git a/contrib/libucl/src/ucl_parser.c b/contrib/libucl/src/ucl_parser.c index 23f5bce3056f..6be16d12169c 100644 --- a/contrib/libucl/src/ucl_parser.c +++ b/contrib/libucl/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/contrib/libucl/src/ucl_schema.c b/contrib/libucl/src/ucl_schema.c index 68f01187e375..f4ec0ed3284a 100644 --- a/contrib/libucl/src/ucl_schema.c +++ b/contrib/libucl/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/contrib/libucl/src/ucl_util.c b/contrib/libucl/src/ucl_util.c index b00a34787e5a..8f97c20db503 100644 --- a/contrib/libucl/src/ucl_util.c +++ b/contrib/libucl/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/contrib/libucl/stamp-h.in b/contrib/libucl/stamp-h.in deleted file mode 100644 index 9788f70238c9..000000000000 --- a/contrib/libucl/stamp-h.in +++ /dev/null @@ -1 +0,0 @@ -timestamp diff --git a/contrib/libucl/tests/.gitignore b/contrib/libucl/tests/.gitignore new file mode 100644 index 000000000000..464482434f22 --- /dev/null +++ b/contrib/libucl/tests/.gitignore @@ -0,0 +1,10 @@ +*.log +*.trs +*.plist + +test_basic +test_generate +test_msgpack +test_schema +test_speed +test_streamline diff --git a/contrib/libucl/tests/Makefile.am b/contrib/libucl/tests/Makefile.am deleted file mode 100644 index 055eb8bd85b0..000000000000 --- a/contrib/libucl/tests/Makefile.am +++ /dev/null @@ -1,45 +0,0 @@ -EXTRA_DIST = $(TESTS) basic schema generate.res \ - streamline.res rcl_test.json.xz - -TESTS = basic.test \ - generate.test \ - schema.test \ - msgpack.test \ - speed.test \ - msgpack.test -TESTS_ENVIRONMENT = $(SH) \ - TEST_DIR=$(top_srcdir)/tests \ - TEST_OUT_DIR=$(top_builddir)/tests \ - TEST_BINARY_DIR=$(top_builddir)/tests - -common_test_cflags = -I$(top_srcdir)/include \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/uthash -common_test_ldadd = $(top_builddir)/src/libucl.la - -test_basic_SOURCES = test_basic.c -test_basic_LDADD = $(common_test_ldadd) -test_basic_CFLAGS = $(common_test_cflags) - -test_speed_SOURCES = test_speed.c -test_speed_LDADD = $(common_test_ldadd) -test_speed_CFLAGS = $(common_test_cflags) - -test_generate_SOURCES = test_generate.c -test_generate_LDADD = $(common_test_ldadd) -test_generate_CFLAGS = $(common_test_cflags) - -test_schema_SOURCES = test_schema.c -test_schema_LDADD = $(common_test_ldadd) -test_schema_CFLAGS = $(common_test_cflags) - -test_streamline_SOURCES = test_streamline.c -test_streamline_LDADD = $(common_test_ldadd) -test_streamline_CFLAGS = $(common_test_cflags) - -test_msgpack_SOURCES = test_msgpack.c -test_msgpack_LDADD = $(common_test_ldadd) -test_msgpack_CFLAGS = $(common_test_cflags) - -check_PROGRAMS = test_basic test_speed test_generate test_schema test_streamline \ - test_msgpack
\ No newline at end of file diff --git a/contrib/libucl/tests/schema/definitions.json b/contrib/libucl/tests/schema/definitions.json deleted file mode 100644 index 1ab9b2163c44..000000000000 --- a/contrib/libucl/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/contrib/libucl/tests/schema/ref.json b/contrib/libucl/tests/schema/ref.json index 1767769cd845..d8214bc2b30c 100644 --- a/contrib/libucl/tests/schema/ref.json +++ b/contrib/libucl/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/contrib/libucl/tests/schema/refRemote.json b/contrib/libucl/tests/schema/refRemote.json deleted file mode 100644 index 067c666b0ec8..000000000000 --- a/contrib/libucl/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/contrib/libucl/tests/test_speed.c b/contrib/libucl/tests/test_speed.c index 56f2e5abc6c7..51476c94940b 100644 --- a/contrib/libucl/tests/test_speed.c +++ b/contrib/libucl/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/contrib/libucl/tests/test_streamline.c b/contrib/libucl/tests/test_streamline.c index 4c56c4cdcffd..37fe14f9fb97 100644 --- a/contrib/libucl/tests/test_streamline.c +++ b/contrib/libucl/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/contrib/libucl/uthash/utlist.h b/contrib/libucl/uthash/utlist.h index c82dd916e2ed..7cda1ca0ecac 100644 --- a/contrib/libucl/uthash/utlist.h +++ b/contrib/libucl/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 */ diff --git a/contrib/libucl/utils/CMakeLists.txt b/contrib/libucl/utils/CMakeLists.txt deleted file mode 100644 index 4de95fd7b4b0..000000000000 --- a/contrib/libucl/utils/CMakeLists.txt +++ /dev/null @@ -1,12 +0,0 @@ - -PROJECT(libucl-utils C) - -FUNCTION(MAKE_UTIL UTIL_NAME UTIL_SRCS) - ADD_EXECUTABLE(${UTIL_NAME} ${UTIL_SRCS}) - TARGET_LINK_LIBRARIES(${UTIL_NAME} ucl) - INSTALL(TARGETS ${UTIL_NAME} DESTINATION bin) -ENDFUNCTION() - -MAKE_UTIL(ucl_chargen chargen.c) -MAKE_UTIL(ucl_objdump objdump.c) -MAKE_UTIL(ucl_tool ucl-tool.c) diff --git a/contrib/libucl/utils/Makefile.am b/contrib/libucl/utils/Makefile.am deleted file mode 100644 index ec85aaa5e372..000000000000 --- a/contrib/libucl/utils/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -common_utils_cflags = -I$(top_srcdir)/include \ - -I$(top_srcdir)/src \ - -I$(top_srcdir)/uthash -common_utils_ldadd = $(top_builddir)/src/libucl.la - -ucl_chargen_SOURCES = chargen.c -ucl_chargen_LDADD = $(common_utils_ldadd) -ucl_chargen_CFLAGS = $(common_utils_cflags) - -ucl_objdump_SOURCES = objdump.c -ucl_objdump_LDADD = $(common_utils_ldadd) -ucl_objdump_CFLAGS = $(common_utils_cflags) - -ucl_tool_SOURCES = ucl-tool.c -ucl_tool_LDADD = $(common_utils_ldadd) -ucl_tool_CFLAGS = $(common_utils_cflags) - -if UTILS -UTL = ucl_chargen ucl_objdump ucl_tool -else -UTL = -endif -bin_PROGRAMS = $(UTL) diff --git a/contrib/libucl/utils/chargen.c b/contrib/libucl/utils/chargen.c deleted file mode 100644 index 398134054c21..000000000000 --- a/contrib/libucl/utils/chargen.c +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013, Vsevolod Stakhov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file this utility generates character table for ucl - */ - -#include <stdio.h> -#include <ctype.h> -#include <stdbool.h> - -static inline int -print_flag (const char *flag, bool *need_or, char *val) -{ - int res; - res = sprintf (val, "%s%s", *need_or ? "|" : "", flag); - - *need_or |= true; - - return res; -} - -int -main (int argc, char **argv) -{ - int i, col, r; - const char *name = "ucl_chartable"; - bool need_or; - char valbuf[2048]; - - col = 0; - - if (argc > 1) { - name = argv[1]; - } - - printf ("static const unsigned int %s[256] = {\n", name); - - for (i = 0; i < 256; i ++) { - need_or = false; - r = 0; - /* UCL_CHARACTER_VALUE_END */ - - if (i == ' ' || i == '\t') { - r += print_flag ("UCL_CHARACTER_WHITESPACE", &need_or, valbuf + r); - } - if (isspace (i)) { - r += print_flag ("UCL_CHARACTER_WHITESPACE_UNSAFE", &need_or, valbuf + r); - } - if (isalnum (i) || i >= 0x80 || i == '/' || i == '_') { - r += print_flag ("UCL_CHARACTER_KEY_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '-' || i == '_' || i == '/' || i == '.' || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_KEY", &need_or, valbuf + r); - } - if (i == 0 || i == '\r' || i == '\n' || i == ']' || i == '}' || i == ';' || i == ',' || i == '#') { - r += print_flag ("UCL_CHARACTER_VALUE_END", &need_or, valbuf + r); - } - else { - if (isprint (i) || i >= 0x80) { - r += print_flag ("UCL_CHARACTER_VALUE_STR", &need_or, valbuf + r); - } - if (isdigit (i) || i == '-') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT_START", &need_or, valbuf + r); - } - if (isalnum (i) || i == '.' || i == '-' || i == '+') { - r += print_flag ("UCL_CHARACTER_VALUE_DIGIT", &need_or, valbuf + r); - } - } - if (i == '"' || i == '\\' || i == '/' || i == 'b' || - i == 'f' || i == 'n' || i == 'r' || i == 't' || i == 'u') { - r += print_flag ("UCL_CHARACTER_ESCAPE", &need_or, valbuf + r); - } - if (i == ' ' || i == '\t' || i == ':' || i == '=') { - r += print_flag ("UCL_CHARACTER_KEY_SEP", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f') { - r += print_flag ("UCL_CHARACTER_JSON_UNSAFE", &need_or, valbuf + r); - } - if (i == '\n' || i == '\r' || i == '\\' || i == '\b' || i == '\t' || - i == '"' || i == '\f' || i == '=' || i == ':' || i == '{' || i == '[' || i == ' ') { - r += print_flag ("UCL_CHARACTER_UCL_UNSAFE", &need_or, valbuf + r); - } - - if (!need_or) { - r += print_flag ("UCL_CHARACTER_DENIED", &need_or, valbuf + r); - } - - if (isprint (i)) { - r += sprintf (valbuf + r, " /* %c */", i); - } - if (i != 255) { - r += sprintf (valbuf + r, ", "); - } - col += r; - if (col > 80) { - printf ("\n%s", valbuf); - col = r; - } - else { - printf ("%s", valbuf); - } - } - printf ("\n}\n"); - - return 0; -} diff --git a/contrib/libucl/utils/objdump.c b/contrib/libucl/utils/objdump.c deleted file mode 100644 index 416eca7c87e0..000000000000 --- a/contrib/libucl/utils/objdump.c +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright (c) 2013, Dmitriy V. Reshetnikov - * Copyright (c) 2013, Vsevolod Stakhov - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if defined(_MSC_VER) - #include <BaseTsd.h> - - typedef SSIZE_T ssize_t; -#endif - -#include "ucl.h" - -void -ucl_obj_dump (const ucl_object_t *obj, unsigned int shift) -{ - int num = shift * 4 + 5; - char *pre = (char *) malloc (num * sizeof(char)); - const ucl_object_t *cur, *tmp; - ucl_object_iter_t it = NULL, it_obj = NULL; - - pre[--num] = 0x00; - while (num--) - pre[num] = 0x20; - - tmp = obj; - - while ((obj = ucl_object_iterate (tmp, &it, false))) { - printf ("%sucl object address: %p\n", pre + 4, obj); - if (obj->key != NULL) { - printf ("%skey: \"%s\"\n", pre, ucl_object_key (obj)); - } - printf ("%sref: %u\n", pre, obj->ref); - printf ("%slen: %u\n", pre, obj->len); - printf ("%sprev: %p\n", pre, obj->prev); - printf ("%snext: %p\n", pre, obj->next); - if (obj->type == UCL_OBJECT) { - printf ("%stype: UCL_OBJECT\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ov); - it_obj = NULL; - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - ucl_obj_dump (cur, shift + 2); - } - } - else if (obj->type == UCL_ARRAY) { - printf ("%stype: UCL_ARRAY\n", pre); - printf ("%svalue: %p\n", pre, obj->value.av); - it_obj = NULL; - while ((cur = ucl_object_iterate (obj, &it_obj, true))) { - ucl_obj_dump (cur, shift + 2); - } - } - else if (obj->type == UCL_INT) { - printf ("%stype: UCL_INT\n", pre); - printf ("%svalue: %jd\n", pre, (intmax_t)ucl_object_toint (obj)); - } - else if (obj->type == UCL_FLOAT) { - printf ("%stype: UCL_FLOAT\n", pre); - printf ("%svalue: %f\n", pre, ucl_object_todouble (obj)); - } - else if (obj->type == UCL_STRING) { - printf ("%stype: UCL_STRING\n", pre); - printf ("%svalue: \"%s\"\n", pre, ucl_object_tostring (obj)); - } - else if (obj->type == UCL_BOOLEAN) { - printf ("%stype: UCL_BOOLEAN\n", pre); - printf ("%svalue: %s\n", pre, ucl_object_tostring_forced (obj)); - } - else if (obj->type == UCL_TIME) { - printf ("%stype: UCL_TIME\n", pre); - printf ("%svalue: %f\n", pre, ucl_object_todouble (obj)); - } - else if (obj->type == UCL_USERDATA) { - printf ("%stype: UCL_USERDATA\n", pre); - printf ("%svalue: %p\n", pre, obj->value.ud); - } - } - - free (pre); -} - -int -main(int argc, char **argv) -{ - const char *fn = NULL; - unsigned char *inbuf; - struct ucl_parser *parser; - int k, ret = 0; - ssize_t bufsize, r = 0; - ucl_object_t *obj = NULL; - const ucl_object_t *par; - FILE *in; - - if (argc > 1) { - fn = argv[1]; - } - - if (fn != NULL) { - in = fopen (fn, "r"); - if (in == NULL) { - exit (EXIT_FAILURE); - } - } - else { - in = stdin; - } - - parser = ucl_parser_new (0); - inbuf = malloc (BUFSIZ); - bufsize = BUFSIZ; - r = 0; - - while (!feof (in) && !ferror (in)) { - if (r == bufsize) { - inbuf = realloc (inbuf, bufsize * 2); - bufsize *= 2; - if (inbuf == NULL) { - perror ("realloc"); - exit (EXIT_FAILURE); - } - } - r += fread (inbuf + r, 1, bufsize - r, in); - } - - if (ferror (in)) { - fprintf (stderr, "Failed to read the input file.\n"); - exit (EXIT_FAILURE); - } - - ucl_parser_add_chunk (parser, inbuf, r); - fclose (in); - if (ucl_parser_get_error(parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - obj = ucl_parser_get_object (parser); - if (ucl_parser_get_error (parser)) { - printf ("Error occurred: %s\n", ucl_parser_get_error(parser)); - ret = 1; - goto end; - } - - if (argc > 2) { - for (k = 2; k < argc; k++) { - printf ("search for \"%s\"... ", argv[k]); - par = ucl_object_lookup (obj, argv[k]); - printf ("%sfound\n", (par == NULL )?"not ":""); - ucl_obj_dump (par, 0); - } - } - else { - ucl_obj_dump (obj, 0); - } - -end: - if (parser != NULL) { - ucl_parser_free (parser); - } - if (obj != NULL) { - ucl_object_unref (obj); - } - - return ret; -} diff --git a/contrib/libucl/utils/ucl-tool.c b/contrib/libucl/utils/ucl-tool.c deleted file mode 100644 index 9b807d35c092..000000000000 --- a/contrib/libucl/utils/ucl-tool.c +++ /dev/null @@ -1,170 +0,0 @@ -/* Copyright (c) 2015, Cesanta Software - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "ucl.h" - -void usage(const char *name, FILE *out) { - fprintf(out, "Usage: %s [--help] [-i|--in file] [-o|--out file]\n", name); - fprintf(out, " [-s|--schema file] [-f|--format format]\n\n"); - fprintf(out, " --help - print this message and exit\n"); - fprintf(out, " --in - specify input filename " - "(default: standard input)\n"); - fprintf(out, " --out - specify output filename " - "(default: standard output)\n"); - fprintf(out, " --schema - specify schema file for validation\n"); - fprintf(out, " --format - output format. Options: ucl (default), " - "json, compact_json, yaml, msgpack\n"); -} - -int main(int argc, char **argv) { - int i; - char ch; - FILE *in = stdin, *out = stdout; - const char *schema = NULL, *parm, *val; - unsigned char *buf = NULL; - size_t size = 0, r = 0; - struct ucl_parser *parser = NULL; - ucl_object_t *obj = NULL; - ucl_emitter_t emitter = UCL_EMIT_CONFIG; - - for (i = 1; i < argc; ++i) { - parm = argv[i]; - val = ((i + 1) < argc) ? argv[++i] : NULL; - - if ((strcmp(parm, "--help") == 0) || (strcmp(parm, "-h") == 0)) { - usage(argv[0], stdout); - exit(0); - - } else if ((strcmp(parm, "--in") == 0) || (strcmp(parm, "-i") == 0)) { - if (!val) - goto err_val; - - in = fopen(val, "r"); - if (in == NULL) { - perror("fopen on input file"); - exit(EXIT_FAILURE); - } - } else if ((strcmp(parm, "--out") == 0) || (strcmp(parm, "-o") == 0)) { - if (!val) - goto err_val; - - out = fopen(val, "w"); - if (out == NULL) { - perror("fopen on output file"); - exit(EXIT_FAILURE); - } - } else if ((strcmp(parm, "--schema") == 0) || (strcmp(parm, "-s") == 0)) { - if (!val) - goto err_val; - schema = val; - - } else if ((strcmp(parm, "--format") == 0) || (strcmp(parm, "-f") == 0)) { - if (!val) - goto err_val; - - if (strcmp(val, "ucl") == 0) { - emitter = UCL_EMIT_CONFIG; - } else if (strcmp(val, "json") == 0) { - emitter = UCL_EMIT_JSON; - } else if (strcmp(val, "yaml") == 0) { - emitter = UCL_EMIT_YAML; - } else if (strcmp(val, "compact_json") == 0) { - emitter = UCL_EMIT_JSON_COMPACT; - } else if (strcmp(val, "msgpack") == 0) { - emitter = UCL_EMIT_MSGPACK; - } else { - fprintf(stderr, "Unknown output format: %s\n", val); - exit(EXIT_FAILURE); - } - } else { - usage(argv[0], stderr); - exit(EXIT_FAILURE); - } - } - - parser = ucl_parser_new(0); - buf = malloc(BUFSIZ); - size = BUFSIZ; - while (!feof(in) && !ferror(in)) { - if (r == size) { - buf = realloc(buf, size*2); - size *= 2; - if (buf == NULL) { - perror("realloc"); - exit(EXIT_FAILURE); - } - } - r += fread(buf + r, 1, size - r, in); - } - if (ferror(in)) { - fprintf(stderr, "Failed to read the input file.\n"); - exit(EXIT_FAILURE); - } - fclose(in); - if (!ucl_parser_add_chunk(parser, buf, r)) { - fprintf(stderr, "Failed to parse input file: %s\n", - ucl_parser_get_error(parser)); - exit(EXIT_FAILURE); - } - if ((obj = ucl_parser_get_object(parser)) == NULL) { - fprintf(stderr, "Failed to get root object: %s\n", - ucl_parser_get_error(parser)); - exit(EXIT_FAILURE); - } - if (schema != NULL) { - struct ucl_parser *schema_parser = ucl_parser_new(0); - ucl_object_t *schema_obj = NULL; - struct ucl_schema_error error; - - if (!ucl_parser_add_file(schema_parser, schema)) { - fprintf(stderr, "Failed to parse schema file: %s\n", - ucl_parser_get_error(schema_parser)); - exit(EXIT_FAILURE); - } - if ((schema_obj = ucl_parser_get_object(schema_parser)) == NULL) { - fprintf(stderr, "Failed to get root object: %s\n", - ucl_parser_get_error(schema_parser)); - exit(EXIT_FAILURE); - } - if (!ucl_object_validate(schema_obj, obj, &error)) { - fprintf(stderr, "Validation failed: %s\n", error.msg); - exit(EXIT_FAILURE); - } - } - - if (emitter != UCL_EMIT_MSGPACK) { - fprintf(out, "%s\n", ucl_object_emit(obj, emitter)); - } else { - size_t len; - unsigned char *res; - - res = ucl_object_emit_len(obj, emitter, &len); - fwrite(res, 1, len, out); - } - - return 0; - -err_val: - fprintf(stderr, "Parameter %s is missing mandatory value\n", parm); - usage(argv[0], stderr); - exit(EXIT_FAILURE); -} diff --git a/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp b/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp index 075455c03415..7de9b4dd2ea1 100644 --- a/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp +++ b/contrib/llvm-project/llvm/lib/ObjCopy/ELF/ELFObjcopy.cpp @@ -368,7 +368,7 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config, // (like GroupSection or RelocationSection). This way, we know which // symbols are still 'needed' and which are not. if (Config.StripUnneeded || !Config.UnneededSymbolsToRemove.empty() || - !Config.OnlySection.empty()) { + !Config.OnlySection.empty() || Config.DiscardMode != DiscardType::None) { for (SectionBase &Sec : Obj.sections()) Sec.markSymbols(); } @@ -390,22 +390,23 @@ static Error updateAndRemoveSymbols(const CommonConfig &Config, if (Config.StripDebug && Sym.Type == STT_FILE) return true; - if ((Config.DiscardMode == DiscardType::All || - (Config.DiscardMode == DiscardType::Locals && - StringRef(Sym.Name).starts_with(".L"))) && - Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && - Sym.Type != STT_FILE && Sym.Type != STT_SECTION) - return true; - if ((Config.StripUnneeded || Config.UnneededSymbolsToRemove.matches(Sym.Name)) && (!Obj.isRelocatable() || isUnneededSymbol(Sym))) return true; - // We want to remove undefined symbols if all references have been stripped. - if (!Config.OnlySection.empty() && !Sym.Referenced && - Sym.getShndx() == SHN_UNDEF) - return true; + if (!Sym.Referenced) { + if ((Config.DiscardMode == DiscardType::All || + (Config.DiscardMode == DiscardType::Locals && + StringRef(Sym.Name).starts_with(".L"))) && + Sym.Binding == STB_LOCAL && Sym.getShndx() != SHN_UNDEF && + Sym.Type != STT_FILE && Sym.Type != STT_SECTION) + return true; + // We want to remove undefined symbols if all references have been + // stripped. + if (!Config.OnlySection.empty() && Sym.getShndx() == SHN_UNDEF) + return true; + } return false; }; diff --git a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp index 309938accdf4..daf6a0e65d54 100644 --- a/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp +++ b/contrib/llvm-project/llvm/lib/Target/PowerPC/PPCMergeStringPool.cpp @@ -170,8 +170,9 @@ void PPCMergeStringPool::collectCandidateConstants(Module &M) { LLVM_DEBUG(dbgs() << "hasInitializer() " << Global.hasInitializer() << "\n"); - // We can only pool constants. - if (!Global.isConstant() || !Global.hasInitializer()) + // We can only pool non-thread-local constants. + if (!Global.isConstant() || !Global.hasInitializer() || + Global.isThreadLocal()) continue; // If a global constant has a section we do not try to pool it because diff --git a/contrib/lua/Makefile b/contrib/lua/Makefile index 8efa2eb3fdd6..6e21588476df 100644 --- a/contrib/lua/Makefile +++ b/contrib/lua/Makefile @@ -46,7 +46,7 @@ TO_MAN= lua.1 luac.1 # Lua version and release. V= 5.4 -R= $V.6 +R= $V.8 # Targets start here. all: $(PLAT) diff --git a/contrib/lua/README b/contrib/lua/README index 1ae97165babe..b251d296f687 100644 --- a/contrib/lua/README +++ b/contrib/lua/README @@ -1,5 +1,5 @@ -This is Lua 5.4.6, released on 02 May 2023. +This is Lua 5.4.8, released on 21 May 2025. For installation instructions, license details, and further information about Lua, see doc/readme.html. diff --git a/contrib/lua/doc/contents.html b/contrib/lua/doc/contents.html index 1231e6d2481d..18b677dbac8f 100644 --- a/contrib/lua/doc/contents.html +++ b/contrib/lua/doc/contents.html @@ -10,7 +10,7 @@ <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Lua 5.4 Reference Manual </H1> @@ -18,7 +18,7 @@ Lua 5.4 Reference Manual The reference manual is the official definition of the Lua language. <BR> For a complete introduction to Lua programming, see the book -<A HREF="http://www.lua.org/pil/">Programming in Lua</A>. +<A HREF="https://www.lua.org/pil/">Programming in Lua</A>. <DIV CLASS="menubar"> <A HREF="manual.html">start</A> @@ -27,14 +27,14 @@ For a complete introduction to Lua programming, see the book · <A HREF="#index">index</A> · -<A HREF="http://www.lua.org/manual/">other versions</A> +<A HREF="https://www.lua.org/manual/">other versions</A> </DIV> <P> <SMALL> -Copyright © 2020–2023 Lua.org, PUC-Rio. +Copyright © 2020–2025 Lua.org, PUC-Rio. Freely available under the terms of the -<A HREF="http://www.lua.org/license.html">Lua license</A>. +<A HREF="https://www.lua.org/license.html">Lua license</A>. </SMALL> <H2><A NAME="contents">Contents</A></H2> @@ -668,10 +668,10 @@ Freely available under the terms of the <P CLASS="footer"> Last update: -Sat Apr 1 17:57:05 UTC 2023 +Wed May 21 21:11:33 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.5 +Last change: revised for Lua 5.4.8 --> </BODY> diff --git a/contrib/lua/doc/lua.1 b/contrib/lua/doc/lua.1 index 3f472fd81f62..3c9e000234e3 100644 --- a/contrib/lua/doc/lua.1 +++ b/contrib/lua/doc/lua.1 @@ -1,5 +1,5 @@ -.\" $Id: lua.man,v 1.14 2022/09/23 09:06:36 lhf Exp $ -.TH LUA 1 "$Date: 2022/09/23 09:06:36 $" +.\" $Id: lua.man,v 1.14 2024/05/08 18:48:27 lhf Exp $ +.TH LUA 1 "$Date: 2024/05/08 18:48:27 $" .SH NAME lua \- Lua interpreter .SH SYNOPSIS @@ -123,7 +123,7 @@ and the version-neutral variants are ignored. Code to be executed before command line options and scripts. .TP .B LUA_PATH, LUA_PATH_5_4 -Initial value of package.cpath, +Initial value of package.path, the path used by require to search for Lua loaders. .TP .B LUA_CPATH, LUA_CPATH_5_4 diff --git a/contrib/lua/doc/lua.css b/contrib/lua/doc/lua.css index cbd0799d1525..9013b445c654 100644 --- a/contrib/lua/doc/lua.css +++ b/contrib/lua/doc/lua.css @@ -143,6 +143,7 @@ table.book td.cover { table.book img { border: solid #000080 1px ; + border-radius: 2px ; } table.book span { diff --git a/contrib/lua/doc/manual.html b/contrib/lua/doc/manual.html index 0af688b343c7..8239bc2a964f 100644 --- a/contrib/lua/doc/manual.html +++ b/contrib/lua/doc/manual.html @@ -10,7 +10,7 @@ <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Lua 5.4 Reference Manual </H1> @@ -19,9 +19,9 @@ by Roberto Ierusalimschy, Luiz Henrique de Figueiredo, Waldemar Celes <P> <SMALL> -Copyright © 2020–2023 Lua.org, PUC-Rio. +Copyright © 2020–2025 Lua.org, PUC-Rio. Freely available under the terms of the -<a href="http://www.lua.org/license.html">Lua license</a>. +<a href="https://www.lua.org/license.html">Lua license</a>. </SMALL> <DIV CLASS="menubar"> @@ -29,7 +29,7 @@ Freely available under the terms of the · <A HREF="contents.html#index">index</A> · -<A HREF="http://www.lua.org/manual/">other versions</A> +<A HREF="https://www.lua.org/manual/">other versions</A> </DIV> <!-- ====================================================================== --> @@ -391,7 +391,7 @@ Whenever there is an error, an <em>error object</em> is propagated with information about the error. Lua itself only generates errors whose error object is a string, -but programs may generate errors with +but programs can generate errors with any value as the error object. It is up to the Lua program or its host to handle such error objects. For historical reasons, @@ -401,7 +401,7 @@ even though it does not have to be a string. <p> When you use <a href="#pdf-xpcall"><code>xpcall</code></a> (or <a href="#lua_pcall"><code>lua_pcall</code></a>, in C) -you may give a <em>message handler</em> +you can give a <em>message handler</em> to be called in case of errors. This function is called with the original error object and returns a new error object. @@ -453,7 +453,7 @@ which is then called a <em>metamethod</em>. In the previous example, the key is the string "<code>__add</code>" and the metamethod is the function that performs the addition. Unless stated otherwise, -a metamethod may in fact be any callable value, +a metamethod can in fact be any callable value, which is either a function or a value with a <code>__call</code> metamethod. @@ -1725,7 +1725,7 @@ labels in Lua are considered statements too: <p> A label is visible in the entire block where it is defined, except inside nested functions. -A goto may jump to any visible label as long as it does not +A goto can jump to any visible label as long as it does not enter into the scope of a local variable. A label should not be declared where a label with the same name is visible, @@ -5571,7 +5571,7 @@ otherwise, returns <code>NULL</code>. <hr><h3><a name="lua_toclose"><code>lua_toclose</code></a></h3><p> -<span class="apii">[-0, +0, <em>m</em>]</span> +<span class="apii">[-0, +0, <em>v</em>]</span> <pre>void lua_toclose (lua_State *L, int index);</pre> <p> @@ -5592,6 +5592,11 @@ unless previously deactivated by <a href="#lua_closeslot"><code>lua_closeslot</c <p> +This function raises an error if the value at the given slot +neither has a <code>__close</code> metamethod nor is a false value. + + +<p> This function should not be called for an index that is equal to or below an active to-be-closed slot. @@ -5664,6 +5669,12 @@ after its last character (as in C), but can contain other zeros in its body. +<p> +This function can raise memory errors only +when converting a number to a string +(as then it may create a new string). + + @@ -11276,13 +11287,13 @@ The returned table can contain all the fields returned by <a href="#lua_getinfo" with the string <code>what</code> describing which fields to fill in. The default for <code>what</code> is to get all information available, except the table of valid lines. -If present, -the option '<code>f</code>' +The option '<code>f</code>' adds a field named <code>func</code> with the function itself. -If present, -the option '<code>L</code>' -adds a field named <code>activelines</code> with the table of -valid lines. +The option '<code>L</code>' adds a field named <code>activelines</code> +with the table of valid lines, +provided the function is a Lua function. +If the function has no debug information, +the table is empty. <p> @@ -11619,6 +11630,10 @@ Lua does not consult any environment variables. In particular, the values of <a href="#pdf-package.path"><code>package.path</code></a> and <a href="#pdf-package.cpath"><code>package.cpath</code></a> are set with the default paths defined in <code>luaconf.h</code>. +To signal to the libraries that this option is on, +the stand-alone interpreter sets the field +<code>"LUA_NOENV"</code> in the registry to a true value. +Other libraries may consult this field for the same purpose. <p> @@ -12033,13 +12048,12 @@ and LiteralString, see <a href="#3.1">§3.1</a>.) - <P CLASS="footer"> Last update: -Tue May 2 20:09:38 UTC 2023 +Wed May 21 21:09:59 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.6 +Last change: revised for Lua 5.4.8 --> </body></html> diff --git a/contrib/lua/doc/readme.html b/contrib/lua/doc/readme.html index 918ec8ed9378..a4eb59dd38c6 100644 --- a/contrib/lua/doc/readme.html +++ b/contrib/lua/doc/readme.html @@ -29,7 +29,7 @@ tt, kbd, code { <BODY> <H1> -<A HREF="http://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> +<A HREF="https://www.lua.org/"><IMG SRC="logo.gif" ALT="Lua"></A> Welcome to Lua 5.4 </H1> @@ -49,29 +49,31 @@ Welcome to Lua 5.4 <P> Lua is a powerful, efficient, lightweight, embeddable scripting language developed by a -<A HREF="http://www.lua.org/authors.html">team</A> +<A HREF="https://www.lua.org/authors.html">team</A> at -<A HREF="http://www.puc-rio.br/">PUC-Rio</A>, +<A HREF="https://www.puc-rio.br/">PUC-Rio</A>, the Pontifical Catholic University of Rio de Janeiro in Brazil. Lua is <A HREF="#license">free software</A> used in -<A HREF="http://www.lua.org/uses.html">many products and projects</A> +<A HREF="https://www.lua.org/uses.html">many products and projects</A> around the world. <P> Lua's -<A HREF="http://www.lua.org/">official web site</A> +<A HREF="https://www.lua.org/">official website</A> provides complete information about Lua, including an -<A HREF="http://www.lua.org/about.html">executive summary</A> +<A HREF="https://www.lua.org/about.html">executive summary</A>, +tips on +<A HREF="https://www.lua.org/start.html">getting started</A>, and updated -<A HREF="http://www.lua.org/docs.html">documentation</A>, +<A HREF="https://www.lua.org/docs.html">documentation</A>, especially the -<A HREF="http://www.lua.org/manual/5.4/">reference manual</A>, +<A HREF="https://www.lua.org/manual/5.4/">reference manual</A>, which may differ slightly from the <A HREF="contents.html">local copy</A> distributed in this package. @@ -79,7 +81,7 @@ distributed in this package. <H2><A NAME="install">Installing Lua</A></H2> <P> Lua is distributed in -<A HREF="http://www.lua.org/ftp/">source</A> +<A HREF="https://www.lua.org/ftp/">source</A> form. You need to build it before using it. Building Lua should be straightforward @@ -88,7 +90,7 @@ Lua is implemented in pure ANSI C and compiles unmodified in all known platforms that have an ANSI C compiler. Lua also compiles unmodified as C++. The instructions given below for building Lua are for Unix-like platforms, -such as Linux and Mac OS X. +such as Linux and macOS. See also <A HREF="#other">instructions for other systems</A> and @@ -97,7 +99,7 @@ and <P> If you don't have the time or the inclination to compile Lua yourself, get a binary from -<A HREF="http://lua-users.org/wiki/LuaBinaries">LuaBinaries</A>. +<A HREF="https://luabinaries.sourceforge.net">LuaBinaries</A>. <H3>Building Lua</H3> <P> @@ -107,7 +109,7 @@ Here are the details. <OL> <LI> Open a terminal window and move to -the top-level directory, which is named <TT>lua-5.4.6</TT>. +the top-level directory, which is named <TT>lua-5.4.8</TT>. The <TT>Makefile</TT> there controls both the build process and the installation process. <P> <LI> @@ -211,8 +213,8 @@ then try "<KBD>make linux-readline MYLIBS=-ltermcap</KBD>". record the changes you've made. <P> - On the other hand, if you need to customize some Lua features, you'll need - to edit <TT>src/luaconf.h</TT> before building and installing Lua. + On the other hand, if you need to customize some Lua features, + edit <TT>src/luaconf.h</TT> before building and installing Lua. The edited file will be the one installed, and it will be used by any Lua clients that you build, to ensure consistency. Further customization is available to experts by editing the Lua sources. @@ -241,7 +243,7 @@ compiler: </DL> <P> - To use Lua as a library in your own programs, you'll need to know how to + To use Lua as a library in your own programs, you need to know how to create and use libraries with your compiler. Moreover, to dynamically load C libraries for Lua, you'll need to know how to create dynamic libraries and you'll need to make sure that the Lua API functions are accessible to @@ -284,11 +286,11 @@ lists the <H2><A NAME="license">License</A></H2> <P> -<A HREF="http://www.opensource.org/docs/definition.php"> -<IMG SRC="osi-certified-72x60.png" ALIGN="right" ALT="[osi certified]" STYLE="padding-left: 30px ;"> +<A HREF="https://opensource.org/osd"> +<IMG SRC="OSIApproved_100X125.png" ALIGN="right" ALT="[Open Source Initiative Approved License]" STYLE="padding-left: 1em" WIDTH=50> </A> Lua is free software distributed under the terms of the -<A HREF="http://www.opensource.org/licenses/mit-license.html">MIT license</A> +<A HREF="https://opensource.org/license/mit">MIT license</A> reproduced below; it may be used for any purpose, including commercial purposes, at absolutely no cost without having to ask us. @@ -296,11 +298,11 @@ at absolutely no cost without having to ask us. The only requirement is that if you do use Lua, then you should give us credit by including the appropriate copyright notice somewhere in your product or its documentation. -For details, see -<A HREF="http://www.lua.org/license.html">this</A>. +For details, see the +<A HREF="https://www.lua.org/license.html">license page</A>. <BLOCKQUOTE STYLE="padding-bottom: 0em"> -Copyright © 1994–2023 Lua.org, PUC-Rio. +Copyright © 1994–2025 Lua.org, PUC-Rio. <P> Permission is hereby granted, free of charge, to any person obtaining a copy @@ -327,10 +329,10 @@ THE SOFTWARE. <P CLASS="footer"> Last update: -Tue May 2 20:08:55 UTC 2023 +Wed May 21 21:12:01 UTC 2025 </P> <!-- -Last change: revised for Lua 5.4.6 +Last change: revised for Lua 5.4.8 --> </BODY> diff --git a/contrib/lua/src/lapi.c b/contrib/lua/src/lapi.c index 34e64af1428c..04e09cff7e0d 100644 --- a/contrib/lua/src/lapi.c +++ b/contrib/lua/src/lapi.c @@ -417,9 +417,9 @@ LUA_API const char *lua_tolstring (lua_State *L, int idx, size_t *len) { o = index2value(L, idx); /* previous call may reallocate the stack */ } if (len != NULL) - *len = vslen(o); + *len = tsslen(tsvalue(o)); lua_unlock(L); - return svalue(o); + return getstr(tsvalue(o)); } @@ -1343,7 +1343,7 @@ void lua_warning (lua_State *L, const char *msg, int tocont) { LUA_API void *lua_newuserdatauv (lua_State *L, size_t size, int nuvalue) { Udata *u; lua_lock(L); - api_check(L, 0 <= nuvalue && nuvalue < USHRT_MAX, "invalid value"); + api_check(L, 0 <= nuvalue && nuvalue < SHRT_MAX, "invalid value"); u = luaS_newudata(L, size, nuvalue); setuvalue(L, s2v(L->top.p), u); api_incr_top(L); diff --git a/contrib/lua/src/lauxlib.c b/contrib/lua/src/lauxlib.c index 4ca6c6548899..923105ed3176 100644 --- a/contrib/lua/src/lauxlib.c +++ b/contrib/lua/src/lauxlib.c @@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */ if (findfield(L, top + 1, 2)) { const char *name = lua_tostring(L, -1); if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ @@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { return 1; } else { + const char *msg; luaL_pushfail(L); + msg = (en != 0) ? strerror(en) : "(no extra info)"; if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); + lua_pushfstring(L, "%s: %s", fname, msg); else - lua_pushstring(L, strerror(en)); + lua_pushstring(L, msg); lua_pushinteger(L, en); return 3; } @@ -732,9 +735,12 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); + int err = errno; const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + if (err != 0) + lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err)); + else + lua_pushfstring(L, "cannot %s %s", what, filename); lua_remove(L, fnameindex); return LUA_ERRFILE; } @@ -787,6 +793,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } else { lua_pushfstring(L, "@%s", filename); + errno = 0; lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } @@ -796,6 +803,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, if (c == LUA_SIGNATURE[0]) { /* binary file? */ lf.n = 0; /* remove possible newline */ if (filename) { /* "real" file? */ + errno = 0; lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); skipcomment(lf.f, &c); /* re-read initial portion */ @@ -803,6 +811,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + errno = 0; status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -933,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ - if (l->func == NULL) /* place holder? */ + if (l->func == NULL) /* placeholder? */ lua_pushboolean(L, 0); else { int i; @@ -1025,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { } +/* +** Standard panic funcion just prints an error message. The test +** with 'lua_type' avoids possible memory errors in 'lua_tostring'. +*/ static int panic (lua_State *L) { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "error object is not a string"; + const char *msg = (lua_type(L, -1) == LUA_TSTRING) + ? lua_tostring(L, -1) + : "error object is not a string"; lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", msg); return 0; /* return to Lua to abort */ diff --git a/contrib/lua/src/lcode.c b/contrib/lua/src/lcode.c index 8d6ce8c08bd2..85466a82ee1d 100644 --- a/contrib/lua/src/lcode.c +++ b/contrib/lua/src/lcode.c @@ -35,6 +35,7 @@ #define MAXREGS 255 +/* (note that expressions VJMP also have jumps.) */ #define hasjumps(e) ((e)->t != (e)->f) @@ -415,7 +416,7 @@ int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { /* ** Format and emit an 'iAsBx' instruction. */ -int luaK_codeAsBx (FuncState *fs, OpCode o, int a, int bc) { +static int codeAsBx (FuncState *fs, OpCode o, int a, int bc) { unsigned int b = bc + OFFSET_sBx; lua_assert(getOpMode(o) == iAsBx); lua_assert(a <= MAXARG_A && b <= MAXARG_Bx); @@ -678,7 +679,7 @@ static int fitsBx (lua_Integer i) { void luaK_int (FuncState *fs, int reg, lua_Integer i) { if (fitsBx(i)) - luaK_codeAsBx(fs, OP_LOADI, reg, cast_int(i)); + codeAsBx(fs, OP_LOADI, reg, cast_int(i)); else luaK_codek(fs, reg, luaK_intK(fs, i)); } @@ -687,7 +688,7 @@ void luaK_int (FuncState *fs, int reg, lua_Integer i) { static void luaK_float (FuncState *fs, int reg, lua_Number f) { lua_Integer fi; if (luaV_flttointeger(f, &fi, F2Ieq) && fitsBx(fi)) - luaK_codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); + codeAsBx(fs, OP_LOADF, reg, cast_int(fi)); else luaK_codek(fs, reg, luaK_numberK(fs, f)); } @@ -783,7 +784,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VLOCAL: { /* already in a register */ - e->u.info = e->u.var.ridx; + int temp = e->u.var.ridx; + e->u.info = temp; /* (can't do a direct assignment; values overlap) */ e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } @@ -991,7 +993,7 @@ void luaK_exp2anyregup (FuncState *fs, expdesc *e) { ** or it is a constant. */ void luaK_exp2val (FuncState *fs, expdesc *e) { - if (hasjumps(e)) + if (e->k == VJMP || hasjumps(e)) luaK_exp2anyreg(fs, e); else luaK_dischargevars(fs, e); @@ -1032,7 +1034,7 @@ static int luaK_exp2K (FuncState *fs, expdesc *e) { ** in the range of R/K indices). ** Returns 1 iff expression is K. */ -int luaK_exp2RK (FuncState *fs, expdesc *e) { +static int exp2RK (FuncState *fs, expdesc *e) { if (luaK_exp2K(fs, e)) return 1; else { /* not a constant in the right range: put it in a register */ @@ -1044,7 +1046,7 @@ int luaK_exp2RK (FuncState *fs, expdesc *e) { static void codeABRK (FuncState *fs, OpCode o, int a, int b, expdesc *ec) { - int k = luaK_exp2RK(fs, ec); + int k = exp2RK(fs, ec); luaK_codeABCk(fs, o, a, b, ec->u.info, k); } @@ -1222,7 +1224,7 @@ static void codenot (FuncState *fs, expdesc *e) { /* -** Check whether expression 'e' is a small literal string +** Check whether expression 'e' is a short literal string */ static int isKstr (FuncState *fs, expdesc *e) { return (e->k == VK && !hasjumps(e) && e->u.info <= MAXARG_B && @@ -1232,7 +1234,7 @@ static int isKstr (FuncState *fs, expdesc *e) { /* ** Check whether expression 'e' is a literal integer. */ -int luaK_isKint (expdesc *e) { +static int isKint (expdesc *e) { return (e->k == VKINT && !hasjumps(e)); } @@ -1242,7 +1244,7 @@ int luaK_isKint (expdesc *e) { ** proper range to fit in register C */ static int isCint (expdesc *e) { - return luaK_isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); + return isKint(e) && (l_castS2U(e->u.ival) <= l_castS2U(MAXARG_C)); } @@ -1251,7 +1253,7 @@ static int isCint (expdesc *e) { ** proper range to fit in register sC */ static int isSCint (expdesc *e) { - return luaK_isKint(e) && fitsC(e->u.ival); + return isKint(e) && fitsC(e->u.ival); } @@ -1290,15 +1292,17 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { - t->u.ind.t = t->u.info; /* upvalue index */ - t->u.ind.idx = k->u.info; /* literal string */ + int temp = t->u.info; /* upvalue index */ + lua_assert(isKstr(fs, k)); + t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ + t->u.ind.idx = k->u.info; /* literal short string */ t->k = VINDEXUP; } else { /* register index of the table */ t->u.ind.t = (t->k == VLOCAL) ? t->u.var.ridx: t->u.info; if (isKstr(fs, k)) { - t->u.ind.idx = k->u.info; /* literal string */ + t->u.ind.idx = k->u.info; /* literal short string */ t->k = VINDEXSTR; } else if (isCint(k)) { @@ -1466,7 +1470,7 @@ static void codebinK (FuncState *fs, BinOpr opr, */ static int finishbinexpneg (FuncState *fs, expdesc *e1, expdesc *e2, OpCode op, int line, TMS event) { - if (!luaK_isKint(e2)) + if (!isKint(e2)) return 0; /* not an integer constant */ else { lua_Integer i2 = e2->u.ival; @@ -1599,7 +1603,7 @@ static void codeeq (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { op = OP_EQI; r2 = im; /* immediate operand */ } - else if (luaK_exp2RK(fs, e2)) { /* 2nd expression is constant? */ + else if (exp2RK(fs, e2)) { /* 2nd expression is constant? */ op = OP_EQK; r2 = e2->u.info; /* constant index */ } @@ -1665,7 +1669,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { } case OPR_EQ: case OPR_NE: { if (!tonumeral(v, NULL)) - luaK_exp2RK(fs, v); + exp2RK(fs, v); /* else keep numeral, which may be an immediate operand */ break; } diff --git a/contrib/lua/src/lcode.h b/contrib/lua/src/lcode.h index 326582445263..0b971fc4359b 100644 --- a/contrib/lua/src/lcode.h +++ b/contrib/lua/src/lcode.h @@ -61,10 +61,8 @@ typedef enum UnOpr { OPR_MINUS, OPR_BNOT, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr; LUAI_FUNC int luaK_code (FuncState *fs, Instruction i); LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx); -LUAI_FUNC int luaK_codeAsBx (FuncState *fs, OpCode o, int A, int Bx); LUAI_FUNC int luaK_codeABCk (FuncState *fs, OpCode o, int A, int B, int C, int k); -LUAI_FUNC int luaK_isKint (expdesc *e); LUAI_FUNC int luaK_exp2const (FuncState *fs, const expdesc *e, TValue *v); LUAI_FUNC void luaK_fixline (FuncState *fs, int line); LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n); @@ -76,7 +74,6 @@ LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e); -LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e); LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key); LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k); LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e); diff --git a/contrib/lua/src/ldebug.c b/contrib/lua/src/ldebug.c index 28b1caabf77e..7264fce8a55c 100644 --- a/contrib/lua/src/ldebug.c +++ b/contrib/lua/src/ldebug.c @@ -31,12 +31,15 @@ -#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) +#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL) static const char *funcnamefromcall (lua_State *L, CallInfo *ci, const char **name); +static const char strlocal[] = "local"; +static const char strupval[] = "upvalue"; + static int currentpc (CallInfo *ci) { lua_assert(isLua(ci)); @@ -254,7 +257,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { + if (!LuaClosure(cl)) { ar->source = "=[C]"; ar->srclen = LL("=[C]"); ar->linedefined = -1; @@ -288,29 +291,31 @@ static int nextline (const Proto *p, int currentline, int pc) { static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { setnilvalue(s2v(L->top.p)); api_incr_top(L); } else { - int i; - TValue v; const Proto *p = f->l.p; int currentline = p->linedefined; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue2s(L, L->top.p, t); /* push it on stack */ api_incr_top(L); - setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - if (!p->is_vararg) /* regular function? */ - i = 0; /* consider all instructions */ - else { /* vararg function */ - lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); - currentline = nextline(p, currentline, 0); - i = 1; /* skip first instruction (OP_VARARGPREP) */ - } - for (; i < p->sizelineinfo; i++) { /* for each instruction */ - currentline = nextline(p, currentline, i); /* get its line */ - luaH_setint(L, t, currentline, &v); /* table[line] = true */ + if (p->lineinfo != NULL) { /* proto with debug information? */ + int i; + TValue v; + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ + luaH_setint(L, t, currentline, &v); /* table[line] = true */ + } } } } @@ -339,7 +344,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } @@ -417,40 +422,6 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) { ** ======================================================= */ -static const char *getobjname (const Proto *p, int lastpc, int reg, - const char **name); - - -/* -** Find a "name" for the constant 'c'. -*/ -static void kname (const Proto *p, int c, const char **name) { - TValue *kvalue = &p->k[c]; - *name = (ttisstring(kvalue)) ? svalue(kvalue) : "?"; -} - - -/* -** Find a "name" for the register 'c'. -*/ -static void rname (const Proto *p, int pc, int c, const char **name) { - const char *what = getobjname(p, pc, c, name); /* search for 'c' */ - if (!(what && *what == 'c')) /* did not find a constant name? */ - *name = "?"; -} - - -/* -** Find a "name" for a 'C' value in an RK instruction. -*/ -static void rkname (const Proto *p, int pc, Instruction i, const char **name) { - int c = GETARG_C(i); /* key index */ - if (GETARG_k(i)) /* is 'c' a constant? */ - kname(p, c, name); - else /* 'c' is a register */ - rname(p, pc, c, name); -} - static int filterpc (int pc, int jmptarget) { if (pc < jmptarget) /* is code conditional (inside a jump)? */ @@ -509,28 +480,29 @@ static int findsetreg (const Proto *p, int lastpc, int reg) { /* -** Check whether table being indexed by instruction 'i' is the -** environment '_ENV' +** Find a "name" for the constant 'c'. */ -static const char *gxf (const Proto *p, int pc, Instruction i, int isup) { - int t = GETARG_B(i); /* table index */ - const char *name; /* name of indexed variable */ - if (isup) /* is an upvalue? */ - name = upvalname(p, t); - else - getobjname(p, pc, t, &name); - return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +static const char *kname (const Proto *p, int index, const char **name) { + TValue *kvalue = &p->k[index]; + if (ttisstring(kvalue)) { + *name = getstr(tsvalue(kvalue)); + return "constant"; + } + else { + *name = "?"; + return NULL; + } } -static const char *getobjname (const Proto *p, int lastpc, int reg, - const char **name) { - int pc; - *name = luaF_getlocalname(p, reg + 1, lastpc); +static const char *basicgetobjname (const Proto *p, int *ppc, int reg, + const char **name) { + int pc = *ppc; + *name = luaF_getlocalname(p, reg + 1, pc); if (*name) /* is a local? */ - return "local"; + return strlocal; /* else try symbolic execution */ - pc = findsetreg(p, lastpc, reg); + *ppc = pc = findsetreg(p, pc, reg); if (pc != -1) { /* could find instruction? */ Instruction i = p->code[pc]; OpCode op = GET_OPCODE(i); @@ -538,18 +510,86 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, case OP_MOVE: { int b = GETARG_B(i); /* move from 'b' to 'a' */ if (b < GETARG_A(i)) - return getobjname(p, pc, b, name); /* get name for 'b' */ + return basicgetobjname(p, ppc, b, name); /* get name for 'b' */ break; } + case OP_GETUPVAL: { + *name = upvalname(p, GETARG_B(i)); + return strupval; + } + case OP_LOADK: return kname(p, GETARG_Bx(i), name); + case OP_LOADKX: return kname(p, GETARG_Ax(p->code[pc + 1]), name); + default: break; + } + } + return NULL; /* could not find reasonable name */ +} + + +/* +** Find a "name" for the register 'c'. +*/ +static void rname (const Proto *p, int pc, int c, const char **name) { + const char *what = basicgetobjname(p, &pc, c, name); /* search for 'c' */ + if (!(what && *what == 'c')) /* did not find a constant name? */ + *name = "?"; +} + + +/* +** Find a "name" for a 'C' value in an RK instruction. +*/ +static void rkname (const Proto *p, int pc, Instruction i, const char **name) { + int c = GETARG_C(i); /* key index */ + if (GETARG_k(i)) /* is 'c' a constant? */ + kname(p, c, name); + else /* 'c' is a register */ + rname(p, pc, c, name); +} + + +/* +** Check whether table being indexed by instruction 'i' is the +** environment '_ENV'. If the table is an upvalue, get its name; +** otherwise, find some "name" for the table and check whether +** that name is the name of a local variable (and not, for instance, +** a string). Then check that, if there is a name, it is '_ENV'. +*/ +static const char *isEnv (const Proto *p, int pc, Instruction i, int isup) { + int t = GETARG_B(i); /* table index */ + const char *name; /* name of indexed variable */ + if (isup) /* is 't' an upvalue? */ + name = upvalname(p, t); + else { /* 't' is a register */ + const char *what = basicgetobjname(p, &pc, t, &name); + if (what != strlocal && what != strupval) + name = NULL; /* cannot be the variable _ENV */ + } + return (name && strcmp(name, LUA_ENV) == 0) ? "global" : "field"; +} + + +/* +** Extend 'basicgetobjname' to handle table accesses +*/ +static const char *getobjname (const Proto *p, int lastpc, int reg, + const char **name) { + const char *kind = basicgetobjname(p, &lastpc, reg, name); + if (kind != NULL) + return kind; + else if (lastpc != -1) { /* could find instruction? */ + Instruction i = p->code[lastpc]; + OpCode op = GET_OPCODE(i); + switch (op) { case OP_GETTABUP: { int k = GETARG_C(i); /* key index */ kname(p, k, name); - return gxf(p, pc, i, 1); + return isEnv(p, lastpc, i, 1); } case OP_GETTABLE: { int k = GETARG_C(i); /* key index */ - rname(p, pc, k, name); - return gxf(p, pc, i, 0); + rname(p, lastpc, k, name); + return isEnv(p, lastpc, i, 0); } case OP_GETI: { *name = "integer index"; @@ -558,24 +598,10 @@ static const char *getobjname (const Proto *p, int lastpc, int reg, case OP_GETFIELD: { int k = GETARG_C(i); /* key index */ kname(p, k, name); - return gxf(p, pc, i, 0); - } - case OP_GETUPVAL: { - *name = upvalname(p, GETARG_B(i)); - return "upvalue"; - } - case OP_LOADK: - case OP_LOADKX: { - int b = (op == OP_LOADK) ? GETARG_Bx(i) - : GETARG_Ax(p->code[pc + 1]); - if (ttisstring(&p->k[b])) { - *name = svalue(&p->k[b]); - return "constant"; - } - break; + return isEnv(p, lastpc, i, 0); } case OP_SELF: { - rkname(p, pc, i, name); + rkname(p, lastpc, i, name); return "method"; } default: break; /* go through to return NULL */ @@ -627,7 +653,7 @@ static const char *funcnamefromcode (lua_State *L, const Proto *p, default: return NULL; /* cannot find a reasonable name */ } - *name = getstr(G(L)->tmname[tm]) + 2; + *name = getshrstr(G(L)->tmname[tm]) + 2; return "metamethod"; } @@ -684,7 +710,7 @@ static const char *getupvalname (CallInfo *ci, const TValue *o, for (i = 0; i < c->nupvalues; i++) { if (c->upvals[i]->v.p == o) { *name = upvalname(c->p, i); - return "upvalue"; + return strupval; } } return NULL; @@ -866,6 +892,28 @@ static int changedline (const Proto *p, int oldpc, int newpc) { /* +** Traces Lua calls. If code is running the first instruction of a function, +** and function is not vararg, and it is not coming from an yield, +** calls 'luaD_hookcall'. (Vararg functions will call 'luaD_hookcall' +** after adjusting its variable arguments; otherwise, they could call +** a line/count hook before the call hook. Functions coming from +** an yield already called 'luaD_hookcall' before yielding.) +*/ +int luaG_tracecall (lua_State *L) { + CallInfo *ci = L->ci; + Proto *p = ci_func(ci)->p; + ci->u.l.trap = 1; /* ensure hooks will be checked */ + if (ci->u.l.savedpc == p->code) { /* first instruction (not resuming)? */ + if (p->is_vararg) + return 0; /* hooks will start at VARARGPREP instruction */ + else if (!(ci->callstatus & CIST_HOOKYIELD)) /* not yieded? */ + luaD_hookcall(L, ci); /* check 'call' hook */ + } + return 1; /* keep 'trap' on */ +} + + +/* ** Traces the execution of a Lua function. Called before the execution ** of each opcode, when debug is on. 'L->oldpc' stores the last ** instruction traced, to detect line changes. When entering a new @@ -888,12 +936,12 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { } pc++; /* reference is always next instruction */ ci->u.l.savedpc = pc; /* save 'pc' */ - counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0); if (counthook) resethookcount(L); /* reset count */ else if (!(mask & LUA_MASKLINE)) return 1; /* no line hook and count != 0; nothing to be done now */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return 1; /* do not call hook again (VM yielded, so it did not move) */ } @@ -915,7 +963,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ luaD_throw(L, LUA_YIELD); } diff --git a/contrib/lua/src/ldebug.h b/contrib/lua/src/ldebug.h index 2c3074c61b6f..2bfce3cb5e77 100644 --- a/contrib/lua/src/ldebug.h +++ b/contrib/lua/src/ldebug.h @@ -58,6 +58,7 @@ LUAI_FUNC const char *luaG_addinfo (lua_State *L, const char *msg, TString *src, int line); LUAI_FUNC l_noret luaG_errormsg (lua_State *L); LUAI_FUNC int luaG_traceexec (lua_State *L, const Instruction *pc); +LUAI_FUNC int luaG_tracecall (lua_State *L); #endif diff --git a/contrib/lua/src/ldo.c b/contrib/lua/src/ldo.c index 2a0017ca62a3..c92573d6e699 100644 --- a/contrib/lua/src/ldo.c +++ b/contrib/lua/src/ldo.c @@ -94,10 +94,6 @@ void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop) { setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */ break; } - case LUA_ERRERR: { - setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling")); - break; - } case LUA_OK: { /* special case only for closing upvalues */ setnilvalue(s2v(oldtop)); /* no error message */ break; @@ -120,6 +116,7 @@ l_noret luaD_throw (lua_State *L, int errcode) { else { /* thread has no error handler */ global_State *g = G(L); errcode = luaE_resetthread(L, errcode); /* close all upvalues */ + L->status = errcode; if (g->mainthread->errorJmp) { /* main thread has a handler? */ setobjs2s(L, g->mainthread->top.p++, L->top.p - 1); /* copy error obj. */ luaD_throw(g->mainthread, errcode); /* re-throw in main thread */ @@ -198,6 +195,16 @@ static void correctstack (lua_State *L) { /* some space for error handling */ #define ERRORSTACKSIZE (LUAI_MAXSTACK + 200) + +/* raise an error while running the message handler */ +l_noret luaD_errerr (lua_State *L) { + TString *msg = luaS_newliteral(L, "error in error handling"); + setsvalue2s(L, L->top.p, msg); + L->top.p++; /* assume EXTRA_STACK */ + luaD_throw(L, LUA_ERRERR); +} + + /* ** Reallocate the stack to a new size, correcting all pointers into it. ** In ISO C, any pointer use after the pointer has been deallocated is @@ -247,7 +254,7 @@ int luaD_growstack (lua_State *L, int n, int raiseerror) { a stack error; cannot grow further than that. */ lua_assert(stacksize(L) == ERRORSTACKSIZE); if (raiseerror) - luaD_throw(L, LUA_ERRERR); /* error inside message handler */ + luaD_errerr(L); /* error inside message handler */ return 0; /* if not 'raiseerror', just signal it */ } else if (n < LUAI_MAXSTACK) { /* avoids arithmetic overflows */ @@ -409,7 +416,7 @@ static void rethook (lua_State *L, CallInfo *ci, int nres) { ** stack, below original 'func', so that 'luaD_precall' can call it. Raise ** an error if there is no '__call' metafield. */ -StkId luaD_tryfuncTM (lua_State *L, StkId func) { +static StkId tryfuncTM (lua_State *L, StkId func) { const TValue *tm; StkId p; checkstackGCp(L, 1, func); /* space for metamethod */ @@ -568,7 +575,7 @@ int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, return -1; } default: { /* not a function */ - func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + func = tryfuncTM(L, func); /* try to get '__call' metamethod */ /* return luaD_pretailcall(L, ci, func, narg1 + 1, delta); */ narg1++; goto retry; /* try again */ @@ -609,7 +616,7 @@ CallInfo *luaD_precall (lua_State *L, StkId func, int nresults) { return ci; } default: { /* not a function */ - func = luaD_tryfuncTM(L, func); /* try to get '__call' metamethod */ + func = tryfuncTM(L, func); /* try to get '__call' metamethod */ /* return luaD_precall(L, func, nresults); */ goto retry; /* try again with metamethod */ } @@ -792,6 +799,10 @@ static void resume (lua_State *L, void *ud) { lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ if (isLua(ci)) { /* yielded inside a hook? */ + /* undo increment made by 'luaG_traceexec': instruction was not + executed yet */ + lua_assert(ci->callstatus & CIST_HOOKYIELD); + ci->u.l.savedpc--; L->top.p = firstArg; /* discard arguments */ luaV_execute(L, ci); /* just continue running Lua code */ } diff --git a/contrib/lua/src/ldo.h b/contrib/lua/src/ldo.h index 1aa446ad09e9..4de9540ec807 100644 --- a/contrib/lua/src/ldo.h +++ b/contrib/lua/src/ldo.h @@ -60,6 +60,7 @@ /* type of protected functions, to be ran by 'runprotected' */ typedef void (*Pfunc) (lua_State *L, void *ud); +LUAI_FUNC l_noret luaD_errerr (lua_State *L); LUAI_FUNC void luaD_seterrorobj (lua_State *L, int errcode, StkId oldtop); LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name, const char *mode); @@ -71,7 +72,6 @@ LUAI_FUNC int luaD_pretailcall (lua_State *L, CallInfo *ci, StkId func, LUAI_FUNC CallInfo *luaD_precall (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults); LUAI_FUNC void luaD_callnoyield (lua_State *L, StkId func, int nResults); -LUAI_FUNC StkId luaD_tryfuncTM (lua_State *L, StkId func); LUAI_FUNC int luaD_closeprotected (lua_State *L, ptrdiff_t level, int status); LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u, ptrdiff_t oldtop, ptrdiff_t ef); diff --git a/contrib/lua/src/lgc.c b/contrib/lua/src/lgc.c index a3094ff57126..5817f9eec35a 100644 --- a/contrib/lua/src/lgc.c +++ b/contrib/lua/src/lgc.c @@ -542,10 +542,12 @@ static void traversestrongtable (global_State *g, Table *h) { static lu_mem traversetable (global_State *g, Table *h) { const char *weakkey, *weakvalue; const TValue *mode = gfasttm(g, h->metatable, TM_MODE); + TString *smode; markobjectN(g, h->metatable); - if (mode && ttisstring(mode) && /* is there a weak mode? */ - (cast_void(weakkey = strchr(svalue(mode), 'k')), - cast_void(weakvalue = strchr(svalue(mode), 'v')), + if (mode && ttisshrstring(mode) && /* is there a weak mode? */ + (cast_void(smode = tsvalue(mode)), + cast_void(weakkey = strchr(getshrstr(smode), 'k')), + cast_void(weakvalue = strchr(getshrstr(smode), 'v')), (weakkey || weakvalue))) { /* is really weak? */ if (!weakkey) /* strong keys? */ traverseweakvalue(g, h); @@ -638,7 +640,9 @@ static int traversethread (global_State *g, lua_State *th) { for (uv = th->openupval; uv != NULL; uv = uv->u.open.next) markobject(g, uv); /* open upvalues cannot be collected */ if (g->gcstate == GCSatomic) { /* final traversal? */ - for (; o < th->stack_last.p + EXTRA_STACK; o++) + if (!g->gcemergency) + luaD_shrinkstack(th); /* do not change stack in emergency cycle */ + for (o = th->top.p; o < th->stack_last.p + EXTRA_STACK; o++) setnilvalue(s2v(o)); /* clear dead stack slice */ /* 'remarkupvals' may have removed thread from 'twups' list */ if (!isintwups(th) && th->openupval != NULL) { @@ -646,8 +650,6 @@ static int traversethread (global_State *g, lua_State *th) { g->twups = th; } } - else if (!g->gcemergency) - luaD_shrinkstack(th); /* do not change stack in emergency cycle */ return 1 + stacksize(th); } @@ -1409,7 +1411,7 @@ static void stepgenfull (lua_State *L, global_State *g) { setminordebt(g); } else { /* another bad collection; stay in incremental mode */ - g->GCestimate = gettotalbytes(g); /* first estimate */; + g->GCestimate = gettotalbytes(g); /* first estimate */ entersweep(L); luaC_runtilstate(L, bitmask(GCSpause)); /* finish collection */ setpause(g); @@ -1604,7 +1606,7 @@ static lu_mem singlestep (lua_State *L) { case GCSenteratomic: { work = atomic(L); /* work is what was traversed by 'atomic' */ entersweep(L); - g->GCestimate = gettotalbytes(g); /* first estimate */; + g->GCestimate = gettotalbytes(g); /* first estimate */ break; } case GCSswpallgc: { /* sweep "regular" objects */ @@ -1710,6 +1712,8 @@ static void fullinc (lua_State *L, global_State *g) { entersweep(L); /* sweep everything to turn them back to white */ /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); + luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ + g->gcstate = GCSenteratomic; /* go straight to atomic phase */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ /* estimate must be correct after a full GC cycle */ lua_assert(g->GCestimate == gettotalbytes(g)); diff --git a/contrib/lua/src/liolib.c b/contrib/lua/src/liolib.c index b08397da45da..c5075f3e78a9 100644 --- a/contrib/lua/src/liolib.c +++ b/contrib/lua/src/liolib.c @@ -245,8 +245,8 @@ static int f_gc (lua_State *L) { */ static int io_fclose (lua_State *L) { LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); + errno = 0; + return luaL_fileresult(L, (fclose(p->f) == 0), NULL); } @@ -272,6 +272,7 @@ static int io_open (lua_State *L) { LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + errno = 0; p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -292,6 +293,7 @@ static int io_popen (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); + errno = 0; p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; @@ -300,6 +302,7 @@ static int io_popen (lua_State *L) { static int io_tmpfile (lua_State *L) { LStream *p = newfile(L); + errno = 0; p->f = tmpfile(); return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } @@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int n, success; clearerr(f); + errno = 0; if (nargs == 0) { /* no arguments? */ success = read_line(L, f, 1); n = first + 1; /* to return 1 result */ @@ -660,6 +664,7 @@ static int io_readline (lua_State *L) { static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - arg; int status = 1; + errno = 0; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ @@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { } if (l_likely(status)) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); + else + return luaL_fileresult(L, status, NULL); } @@ -703,6 +709,7 @@ static int f_seek (lua_State *L) { l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); + errno = 0; op = l_fseek(f, offset, mode[op]); if (l_unlikely(op)) return luaL_fileresult(L, 0, NULL); /* error */ @@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) { FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); + int res; + errno = 0; + res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); + FILE *f = getiofile(L, IO_OUTPUT); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); + FILE *f = tofile(L); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } @@ -773,7 +786,7 @@ static const luaL_Reg meth[] = { ** metamethods for file handles */ static const luaL_Reg metameth[] = { - {"__index", NULL}, /* place holder */ + {"__index", NULL}, /* placeholder */ {"__gc", f_gc}, {"__close", f_gc}, {"__tostring", f_tostring}, diff --git a/contrib/lua/src/lmathlib.c b/contrib/lua/src/lmathlib.c index d0b1e1e5d6f5..438106348084 100644 --- a/contrib/lua/src/lmathlib.c +++ b/contrib/lua/src/lmathlib.c @@ -249,6 +249,15 @@ static int math_type (lua_State *L) { ** =================================================================== */ +/* +** This code uses lots of shifts. ANSI C does not allow shifts greater +** than or equal to the width of the type being shifted, so some shifts +** are written in convoluted ways to match that restriction. For +** preprocessor tests, it assumes a width of 32 bits, so the maximum +** shift there is 31 bits. +*/ + + /* number of binary digits in the mantissa of a float */ #define FIGS l_floatatt(MANT_DIG) @@ -271,16 +280,19 @@ static int math_type (lua_State *L) { /* 'long' has at least 64 bits */ #define Rand64 unsigned long +#define SRand64 long #elif !defined(LUA_USE_C89) && defined(LLONG_MAX) /* there is a 'long long' type (which must have at least 64 bits) */ #define Rand64 unsigned long long +#define SRand64 long long #elif ((LUA_MAXUNSIGNED >> 31) >> 31) >= 3 /* 'lua_Unsigned' has at least 64 bits */ #define Rand64 lua_Unsigned +#define SRand64 lua_Integer #endif @@ -319,23 +331,30 @@ static Rand64 nextrand (Rand64 *state) { } -/* must take care to not shift stuff by more than 63 slots */ - - /* ** Convert bits from a random integer into a float in the ** interval [0,1), getting the higher FIG bits from the ** random unsigned integer and converting that to a float. +** Some old Microsoft compilers cannot cast an unsigned long +** to a floating-point number, so we use a signed long as an +** intermediary. When lua_Number is float or double, the shift ensures +** that 'sx' is non negative; in that case, a good compiler will remove +** the correction. */ /* must throw out the extra (64 - FIGS) bits */ #define shift64_FIG (64 - FIGS) -/* to scale to [0, 1), multiply by scaleFIG = 2^(-FIGS) */ +/* 2^(-FIGS) == 2^-1 / 2^(FIGS-1) */ #define scaleFIG (l_mathop(0.5) / ((Rand64)1 << (FIGS - 1))) static lua_Number I2d (Rand64 x) { - return (lua_Number)(trim64(x) >> shift64_FIG) * scaleFIG; + SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG); + lua_Number res = (lua_Number)(sx) * scaleFIG; + if (sx < 0) + res += l_mathop(1.0); /* correct the two's complement if negative */ + lua_assert(0 <= res && res < 1); + return res; } /* convert a 'Rand64' to a 'lua_Unsigned' */ @@ -471,8 +490,6 @@ static lua_Number I2d (Rand64 x) { #else /* 32 < FIGS <= 64 */ -/* must take care to not shift stuff by more than 31 slots */ - /* 2^(-FIGS) = 1.0 / 2^30 / 2^3 / 2^(FIGS-33) */ #define scaleFIG \ (l_mathop(1.0) / (UONE << 30) / l_mathop(8.0) / (UONE << (FIGS - 33))) diff --git a/contrib/lua/src/loadlib.c b/contrib/lua/src/loadlib.c index d792dffaa03b..6d289fcebb8c 100644 --- a/contrib/lua/src/loadlib.c +++ b/contrib/lua/src/loadlib.c @@ -25,15 +25,6 @@ /* -** LUA_IGMARK is a mark to ignore all before it when building the -** luaopen_ function name. -*/ -#if !defined (LUA_IGMARK) -#define LUA_IGMARK "-" -#endif - - -/* ** LUA_CSUBSEP is the character that replaces dots in submodule names ** when searching for a C loader. ** LUA_LSUBSEP is the character that replaces dots in submodule names diff --git a/contrib/lua/src/lobject.c b/contrib/lua/src/lobject.c index f73ffc6d92bd..9cfa5227eb46 100644 --- a/contrib/lua/src/lobject.c +++ b/contrib/lua/src/lobject.c @@ -542,7 +542,7 @@ const char *luaO_pushvfstring (lua_State *L, const char *fmt, va_list argp) { addstr2buff(&buff, fmt, strlen(fmt)); /* rest of 'fmt' */ clearbuff(&buff); /* empty buffer into the stack */ lua_assert(buff.pushed == 1); - return svalue(s2v(L->top.p - 1)); + return getstr(tsvalue(s2v(L->top.p - 1))); } diff --git a/contrib/lua/src/lobject.h b/contrib/lua/src/lobject.h index 556608e4aa21..980e42f8c27a 100644 --- a/contrib/lua/src/lobject.h +++ b/contrib/lua/src/lobject.h @@ -386,7 +386,7 @@ typedef struct GCObject { typedef struct TString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ - lu_byte shrlen; /* length for short strings */ + lu_byte shrlen; /* length for short strings, 0xFF for long strings */ unsigned int hash; union { size_t lnglen; /* length for long strings */ @@ -398,19 +398,17 @@ typedef struct TString { /* -** Get the actual string (array of bytes) from a 'TString'. +** Get the actual string (array of bytes) from a 'TString'. (Generic +** version and specialized versions for long and short strings.) */ -#define getstr(ts) ((ts)->contents) +#define getstr(ts) ((ts)->contents) +#define getlngstr(ts) check_exp((ts)->shrlen == 0xFF, (ts)->contents) +#define getshrstr(ts) check_exp((ts)->shrlen != 0xFF, (ts)->contents) -/* get the actual string (array of bytes) from a Lua value */ -#define svalue(o) getstr(tsvalue(o)) - /* get string length from 'TString *s' */ -#define tsslen(s) ((s)->tt == LUA_VSHRSTR ? (s)->shrlen : (s)->u.lnglen) - -/* get string length from 'TValue *o' */ -#define vslen(o) tsslen(tsvalue(o)) +#define tsslen(s) \ + ((s)->shrlen != 0xFF ? (s)->shrlen : (s)->u.lnglen) /* }================================================================== */ diff --git a/contrib/lua/src/lopcodes.h b/contrib/lua/src/lopcodes.h index 4c55145399ff..46911cac14e0 100644 --- a/contrib/lua/src/lopcodes.h +++ b/contrib/lua/src/lopcodes.h @@ -210,15 +210,15 @@ OP_LOADNIL,/* A B R[A], R[A+1], ..., R[A+B] := nil */ OP_GETUPVAL,/* A B R[A] := UpValue[B] */ OP_SETUPVAL,/* A B UpValue[B] := R[A] */ -OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:string] */ +OP_GETTABUP,/* A B C R[A] := UpValue[B][K[C]:shortstring] */ OP_GETTABLE,/* A B C R[A] := R[B][R[C]] */ OP_GETI,/* A B C R[A] := R[B][C] */ -OP_GETFIELD,/* A B C R[A] := R[B][K[C]:string] */ +OP_GETFIELD,/* A B C R[A] := R[B][K[C]:shortstring] */ -OP_SETTABUP,/* A B C UpValue[A][K[B]:string] := RK(C) */ +OP_SETTABUP,/* A B C UpValue[A][K[B]:shortstring] := RK(C) */ OP_SETTABLE,/* A B C R[A][R[B]] := RK(C) */ OP_SETI,/* A B C R[A][B] := RK(C) */ -OP_SETFIELD,/* A B C R[A][K[B]:string] := RK(C) */ +OP_SETFIELD,/* A B C R[A][K[B]:shortstring] := RK(C) */ OP_NEWTABLE,/* A B C k R[A] := {} */ diff --git a/contrib/lua/src/loslib.c b/contrib/lua/src/loslib.c index ad5a92768852..ba80d72c4575 100644 --- a/contrib/lua/src/loslib.c +++ b/contrib/lua/src/loslib.c @@ -155,6 +155,7 @@ static int os_execute (lua_State *L) { static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); + errno = 0; return luaL_fileresult(L, remove(filename) == 0, filename); } @@ -162,6 +163,7 @@ static int os_remove (lua_State *L) { static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); + errno = 0; return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } diff --git a/contrib/lua/src/lparser.c b/contrib/lua/src/lparser.c index b745f236f068..1ac82990e0c3 100644 --- a/contrib/lua/src/lparser.c +++ b/contrib/lua/src/lparser.c @@ -198,7 +198,7 @@ static int new_localvar (LexState *ls, TString *name) { checklimit(fs, dyd->actvar.n + 1 - fs->firstlocal, MAXVARS, "local variables"); luaM_growvector(L, dyd->actvar.arr, dyd->actvar.n + 1, - dyd->actvar.size, Vardesc, USHRT_MAX, "local variables"); + dyd->actvar.size, Vardesc, SHRT_MAX, "local variables"); var = &dyd->actvar.arr[dyd->actvar.n++]; var->vd.kind = VDKREG; /* default */ var->vd.name = name; @@ -849,12 +849,11 @@ static void recfield (LexState *ls, ConsControl *cc) { FuncState *fs = ls->fs; int reg = ls->fs->freereg; expdesc tab, key, val; - if (ls->t.token == TK_NAME) { - checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); + if (ls->t.token == TK_NAME) codename(ls, &key); - } else /* ls->t.token == '[' */ yindex(ls, &key); + checklimit(fs, cc->nh, MAX_INT, "items in a constructor"); cc->nh++; checknext(ls, '='); tab = *cc->t; @@ -1022,10 +1021,11 @@ static int explist (LexState *ls, expdesc *v) { } -static void funcargs (LexState *ls, expdesc *f, int line) { +static void funcargs (LexState *ls, expdesc *f) { FuncState *fs = ls->fs; expdesc args; int base, nparams; + int line = ls->linenumber; switch (ls->t.token) { case '(': { /* funcargs -> '(' [ explist ] ')' */ luaX_next(ls); @@ -1063,8 +1063,8 @@ static void funcargs (LexState *ls, expdesc *f, int line) { } init_exp(f, VCALL, luaK_codeABC(fs, OP_CALL, base, nparams+1, 2)); luaK_fixline(fs, line); - fs->freereg = base+1; /* call remove function and arguments and leaves - (unless changed) one result */ + fs->freereg = base+1; /* call removes function and arguments and leaves + one result (unless changed later) */ } @@ -1103,7 +1103,6 @@ static void suffixedexp (LexState *ls, expdesc *v) { /* suffixedexp -> primaryexp { '.' NAME | '[' exp ']' | ':' NAME funcargs | funcargs } */ FuncState *fs = ls->fs; - int line = ls->linenumber; primaryexp(ls, v); for (;;) { switch (ls->t.token) { @@ -1123,12 +1122,12 @@ static void suffixedexp (LexState *ls, expdesc *v) { luaX_next(ls); codename(ls, &key); luaK_self(fs, v, &key); - funcargs(ls, v, line); + funcargs(ls, v); break; } case '(': case TK_STRING: case '{': { /* funcargs */ luaK_exp2nextreg(fs, v); - funcargs(ls, v, line); + funcargs(ls, v); break; } default: return; diff --git a/contrib/lua/src/lstate.c b/contrib/lua/src/lstate.c index 1e925e5ad4cb..f3f2ccfdd5fb 100644 --- a/contrib/lua/src/lstate.c +++ b/contrib/lua/src/lstate.c @@ -119,7 +119,7 @@ CallInfo *luaE_extendCI (lua_State *L) { /* ** free all CallInfo structures not in use by a thread */ -void luaE_freeCI (lua_State *L) { +static void freeCI (lua_State *L) { CallInfo *ci = L->ci; CallInfo *next = ci->next; ci->next = NULL; @@ -166,7 +166,7 @@ void luaE_checkcstack (lua_State *L) { if (getCcalls(L) == LUAI_MAXCCALLS) luaG_runerror(L, "C stack overflow"); else if (getCcalls(L) >= (LUAI_MAXCCALLS / 10 * 11)) - luaD_throw(L, LUA_ERRERR); /* error while handling stack error */ + luaD_errerr(L); /* error while handling stack error */ } @@ -204,7 +204,7 @@ static void freestack (lua_State *L) { if (L->stack.p == NULL) return; /* stack not completely built yet */ L->ci = &L->base_ci; /* free the entire 'ci' list */ - luaE_freeCI(L); + freeCI(L); lua_assert(L->nci == 0); luaM_freearray(L, L->stack.p, stacksize(L) + EXTRA_STACK); /* free stack */ } @@ -272,7 +272,9 @@ static void close_state (lua_State *L) { luaC_freeallobjects(L); /* just collect its objects */ else { /* closing a fully built state */ L->ci = &L->base_ci; /* unwind CallInfo list */ + L->errfunc = 0; /* stack unwind can "throw away" the error function */ luaD_closeprotected(L, 1, LUA_OK); /* close all upvalues */ + L->top.p = L->stack.p + 1; /* empty the stack to run finalizers */ luaC_freeallobjects(L); /* collect all objects */ luai_userstateclose(L); } @@ -328,6 +330,7 @@ int luaE_resetthread (lua_State *L, int status) { if (status == LUA_YIELD) status = LUA_OK; L->status = LUA_OK; /* so it can run __close metamethods */ + L->errfunc = 0; /* stack unwind can "throw away" the error function */ status = luaD_closeprotected(L, 1, status); if (status != LUA_OK) /* errors? */ luaD_seterrorobj(L, status, L->stack.p + 1); @@ -433,7 +436,7 @@ void luaE_warning (lua_State *L, const char *msg, int tocont) { void luaE_warnerror (lua_State *L, const char *where) { TValue *errobj = s2v(L->top.p - 1); /* error object */ const char *msg = (ttisstring(errobj)) - ? svalue(errobj) + ? getstr(tsvalue(errobj)) : "error object is not a string"; /* produce warning "error in %s (%s)" (where, msg) */ luaE_warning(L, "error in ", 1); diff --git a/contrib/lua/src/lstate.h b/contrib/lua/src/lstate.h index 8bf6600e3441..007704c826be 100644 --- a/contrib/lua/src/lstate.h +++ b/contrib/lua/src/lstate.h @@ -181,7 +181,7 @@ struct CallInfo { union { struct { /* only for Lua functions */ const Instruction *savedpc; - volatile l_signalT trap; + volatile l_signalT trap; /* function is tracing lines/counts */ int nextraargs; /* # of extra arguments in vararg functions */ } l; struct { /* only for C functions */ @@ -396,7 +396,6 @@ union GCUnion { LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt); LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1); LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L); -LUAI_FUNC void luaE_freeCI (lua_State *L); LUAI_FUNC void luaE_shrinkCI (lua_State *L); LUAI_FUNC void luaE_checkcstack (lua_State *L); LUAI_FUNC void luaE_incCstack (lua_State *L); diff --git a/contrib/lua/src/lstring.c b/contrib/lua/src/lstring.c index 13dcaf4259bc..97757355c0b6 100644 --- a/contrib/lua/src/lstring.c +++ b/contrib/lua/src/lstring.c @@ -36,7 +36,7 @@ int luaS_eqlngstr (TString *a, TString *b) { lua_assert(a->tt == LUA_VLNGSTR && b->tt == LUA_VLNGSTR); return (a == b) || /* same instance or... */ ((len == b->u.lnglen) && /* equal length and ... */ - (memcmp(getstr(a), getstr(b), len) == 0)); /* equal contents */ + (memcmp(getlngstr(a), getlngstr(b), len) == 0)); /* equal contents */ } @@ -52,7 +52,7 @@ unsigned int luaS_hashlongstr (TString *ts) { lua_assert(ts->tt == LUA_VLNGSTR); if (ts->extra == 0) { /* no hash? */ size_t len = ts->u.lnglen; - ts->hash = luaS_hash(getstr(ts), len, ts->hash); + ts->hash = luaS_hash(getlngstr(ts), len, ts->hash); ts->extra = 1; /* now it has its hash */ } return ts->hash; @@ -157,6 +157,7 @@ static TString *createstrobj (lua_State *L, size_t l, int tag, unsigned int h) { TString *luaS_createlngstrobj (lua_State *L, size_t l) { TString *ts = createstrobj(L, l, LUA_VLNGSTR, G(L)->seed); ts->u.lnglen = l; + ts->shrlen = 0xFF; /* signals that it is a long string */ return ts; } @@ -193,7 +194,7 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { TString **list = &tb->hash[lmod(h, tb->size)]; lua_assert(str != NULL); /* otherwise 'memcmp'/'memcpy' are undefined */ for (ts = *list; ts != NULL; ts = ts->u.hnext) { - if (l == ts->shrlen && (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { + if (l == ts->shrlen && (memcmp(str, getshrstr(ts), l * sizeof(char)) == 0)) { /* found! */ if (isdead(g, ts)) /* dead (but not collected yet)? */ changewhite(ts); /* resurrect it */ @@ -206,8 +207,8 @@ static TString *internshrstr (lua_State *L, const char *str, size_t l) { list = &tb->hash[lmod(h, tb->size)]; /* rehash with new size */ } ts = createstrobj(L, l, LUA_VSHRSTR, h); - memcpy(getstr(ts), str, l * sizeof(char)); ts->shrlen = cast_byte(l); + memcpy(getshrstr(ts), str, l * sizeof(char)); ts->u.hnext = *list; *list = ts; tb->nuse++; @@ -223,10 +224,10 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { return internshrstr(L, str, l); else { TString *ts; - if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString)))) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); - memcpy(getstr(ts), str, l * sizeof(char)); + memcpy(getlngstr(ts), str, l * sizeof(char)); return ts; } } diff --git a/contrib/lua/src/ltable.c b/contrib/lua/src/ltable.c index 3c690c5f1751..3353c047939a 100644 --- a/contrib/lua/src/ltable.c +++ b/contrib/lua/src/ltable.c @@ -252,7 +252,7 @@ LUAI_FUNC unsigned int luaH_realasize (const Table *t) { return t->alimit; /* this is the size */ else { unsigned int size = t->alimit; - /* compute the smallest power of 2 not smaller than 'n' */ + /* compute the smallest power of 2 not smaller than 'size' */ size |= (size >> 1); size |= (size >> 2); size |= (size >> 4); @@ -662,7 +662,8 @@ static Node *getfreepos (Table *t) { ** put new key in its main position; otherwise (colliding node is in its main ** position), new key goes to an empty position. */ -void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { +static void luaH_newkey (lua_State *L, Table *t, const TValue *key, + TValue *value) { Node *mp; TValue aux; if (l_unlikely(ttisnil(key))) @@ -721,22 +722,36 @@ void luaH_newkey (lua_State *L, Table *t, const TValue *key, TValue *value) { /* ** Search function for integers. If integer is inside 'alimit', get it -** directly from the array part. Otherwise, if 'alimit' is not equal to -** the real size of the array, key still can be in the array part. In -** this case, try to avoid a call to 'luaH_realasize' when key is just -** one more than the limit (so that it can be incremented without -** changing the real size of the array). +** directly from the array part. Otherwise, if 'alimit' is not +** the real size of the array, the key still can be in the array part. +** In this case, do the "Xmilia trick" to check whether 'key-1' is +** smaller than the real size. +** The trick works as follow: let 'p' be an integer such that +** '2^(p+1) >= alimit > 2^p', or '2^(p+1) > alimit-1 >= 2^p'. +** That is, 2^(p+1) is the real size of the array, and 'p' is the highest +** bit on in 'alimit-1'. What we have to check becomes 'key-1 < 2^(p+1)'. +** We compute '(key-1) & ~(alimit-1)', which we call 'res'; it will +** have the 'p' bit cleared. If the key is outside the array, that is, +** 'key-1 >= 2^(p+1)', then 'res' will have some bit on higher than 'p', +** therefore it will be larger or equal to 'alimit', and the check +** will fail. If 'key-1 < 2^(p+1)', then 'res' has no bit on higher than +** 'p', and as the bit 'p' itself was cleared, 'res' will be smaller +** than 2^p, therefore smaller than 'alimit', and the check succeeds. +** As special cases, when 'alimit' is 0 the condition is trivially false, +** and when 'alimit' is 1 the condition simplifies to 'key-1 < alimit'. +** If key is 0 or negative, 'res' will have its higher bit on, so that +** if cannot be smaller than alimit. */ const TValue *luaH_getint (Table *t, lua_Integer key) { - if (l_castS2U(key) - 1u < t->alimit) /* 'key' in [1, t->alimit]? */ + lua_Unsigned alimit = t->alimit; + if (l_castS2U(key) - 1u < alimit) /* 'key' in [1, t->alimit]? */ return &t->array[key - 1]; - else if (!limitequalsasize(t) && /* key still may be in the array part? */ - (l_castS2U(key) == t->alimit + 1 || - l_castS2U(key) - 1u < luaH_realasize(t))) { + else if (!isrealasize(t) && /* key still may be in the array part? */ + (((l_castS2U(key) - 1u) & ~(alimit - 1u)) < alimit)) { t->alimit = cast_uint(key); /* probably '#t' is here now */ return &t->array[key - 1]; } - else { + else { /* key is not in the array part; check the hash */ Node *n = hashint(t, key); for (;;) { /* check whether 'key' is somewhere in the chain */ if (keyisinteger(n) && keyival(n) == key) diff --git a/contrib/lua/src/ltable.h b/contrib/lua/src/ltable.h index 75dd9e26e015..8e6890342348 100644 --- a/contrib/lua/src/ltable.h +++ b/contrib/lua/src/ltable.h @@ -41,8 +41,6 @@ LUAI_FUNC void luaH_setint (lua_State *L, Table *t, lua_Integer key, LUAI_FUNC const TValue *luaH_getshortstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key); LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key); -LUAI_FUNC void luaH_newkey (lua_State *L, Table *t, const TValue *key, - TValue *value); LUAI_FUNC void luaH_set (lua_State *L, Table *t, const TValue *key, TValue *value); LUAI_FUNC void luaH_finishset (lua_State *L, Table *t, const TValue *key, diff --git a/contrib/lua/src/ltm.h b/contrib/lua/src/ltm.h index c309e2ae10e3..73b833c605da 100644 --- a/contrib/lua/src/ltm.h +++ b/contrib/lua/src/ltm.h @@ -9,7 +9,6 @@ #include "lobject.h" -#include "lstate.h" /* @@ -96,8 +95,8 @@ LUAI_FUNC int luaT_callorderiTM (lua_State *L, const TValue *p1, int v2, int inv, int isfloat, TMS event); LUAI_FUNC void luaT_adjustvarargs (lua_State *L, int nfixparams, - CallInfo *ci, const Proto *p); -LUAI_FUNC void luaT_getvarargs (lua_State *L, CallInfo *ci, + struct CallInfo *ci, const Proto *p); +LUAI_FUNC void luaT_getvarargs (lua_State *L, struct CallInfo *ci, StkId where, int wanted); diff --git a/contrib/lua/src/lua.c b/contrib/lua/src/lua.c index 0ff884545304..4a90e55dd94b 100644 --- a/contrib/lua/src/lua.c +++ b/contrib/lua/src/lua.c @@ -115,12 +115,13 @@ static void l_message (const char *pname, const char *msg) { /* ** Check whether 'status' is not OK and, if so, prints the error -** message on the top of the stack. It assumes that the error object -** is a string, as it was either generated by Lua or by 'msghandler'. +** message on the top of the stack. */ static int report (lua_State *L, int status) { if (status != LUA_OK) { const char *msg = lua_tostring(L, -1); + if (msg == NULL) + msg = "(error message not a string)"; l_message(progname, msg); lua_pop(L, 1); /* remove message */ } @@ -210,12 +211,17 @@ static int dostring (lua_State *L, const char *s, const char *name) { /* ** Receives 'globname[=modname]' and runs 'globname = require(modname)'. +** If there is no explicit modname and globname contains a '-', cut +** the suffix after '-' (the "version") to make the global name. */ static int dolibrary (lua_State *L, char *globname) { int status; + char *suffix = NULL; char *modname = strchr(globname, '='); - if (modname == NULL) /* no explicit name? */ + if (modname == NULL) { /* no explicit name? */ modname = globname; /* module name is equal to global name */ + suffix = strchr(modname, *LUA_IGMARK); /* look for a suffix mark */ + } else { *modname = '\0'; /* global name ends here */ modname++; /* module name starts after the '=' */ @@ -223,8 +229,11 @@ static int dolibrary (lua_State *L, char *globname) { lua_getglobal(L, "require"); lua_pushstring(L, modname); status = docall(L, 1, 1); /* call 'require(modname)' */ - if (status == LUA_OK) + if (status == LUA_OK) { + if (suffix != NULL) /* is there a suffix mark? */ + *suffix = '\0'; /* remove suffix from global name */ lua_setglobal(L, globname); /* globname = require(modname) */ + } return report(L, status); } @@ -481,10 +490,8 @@ static int incomplete (lua_State *L, int status) { if (status == LUA_ERRSYNTAX) { size_t lmsg; const char *msg = lua_tolstring(L, -1, &lmsg); - if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) { - lua_pop(L, 1); + if (lmsg >= marklen && strcmp(msg + lmsg - marklen, EOFMARK) == 0) return 1; - } } return 0; /* else... */ } @@ -499,9 +506,9 @@ static int pushline (lua_State *L, int firstline) { size_t l; const char *prmt = get_prompt(L, firstline); int readstatus = lua_readline(L, b, prmt); - if (readstatus == 0) - return 0; /* no input (prompt will be popped by caller) */ lua_pop(L, 1); /* remove prompt */ + if (readstatus == 0) + return 0; /* no input */ l = strlen(b); if (l > 0 && b[l-1] == '\n') /* line ends with newline? */ b[--l] = '\0'; /* remove it */ @@ -543,8 +550,9 @@ static int multiline (lua_State *L) { int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ if (!incomplete(L, status) || !pushline(L, 0)) { lua_saveline(L, line); /* keep history */ - return status; /* cannot or should not try to add continuation line */ + return status; /* should not or cannot try to add continuation line */ } + lua_remove(L, -2); /* remove error message (from incomplete line) */ lua_pushliteral(L, "\n"); /* add newline... */ lua_insert(L, -2); /* ...between the two lines */ lua_concat(L, 3); /* join them */ diff --git a/contrib/lua/src/lua.h b/contrib/lua/src/lua.h index fd16cf8050b8..f3ea590d9cd6 100644 --- a/contrib/lua/src/lua.h +++ b/contrib/lua/src/lua.h @@ -18,14 +18,14 @@ #define LUA_VERSION_MAJOR "5" #define LUA_VERSION_MINOR "4" -#define LUA_VERSION_RELEASE "6" +#define LUA_VERSION_RELEASE "8" #define LUA_VERSION_NUM 504 -#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 6) +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 8) #define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR #define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2025 Lua.org, PUC-Rio" #define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" @@ -497,7 +497,7 @@ struct lua_Debug { /****************************************************************************** -* Copyright (C) 1994-2023 Lua.org, PUC-Rio. +* Copyright (C) 1994-2025 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/contrib/lua/src/luaconf.h b/contrib/lua/src/luaconf.h index e517fb4d2e75..c7ca969e321f 100644 --- a/contrib/lua/src/luaconf.h +++ b/contrib/lua/src/luaconf.h @@ -257,6 +257,15 @@ #endif + +/* +** LUA_IGMARK is a mark to ignore all after it when building the +** module name (e.g., used to build the luaopen_ function name). +** Typically, the suffix after the mark is the module version, +** as in "mod-v1.2.so". +*/ +#define LUA_IGMARK "-" + /* }================================================================== */ diff --git a/contrib/lua/src/lundump.c b/contrib/lua/src/lundump.c index 02aed64fb622..e8d92a8534ff 100644 --- a/contrib/lua/src/lundump.c +++ b/contrib/lua/src/lundump.c @@ -81,7 +81,7 @@ static size_t loadUnsigned (LoadState *S, size_t limit) { static size_t loadSize (LoadState *S) { - return loadUnsigned(S, ~(size_t)0); + return loadUnsigned(S, MAX_SIZET); } @@ -122,7 +122,7 @@ static TString *loadStringN (LoadState *S, Proto *p) { ts = luaS_createlngstrobj(L, size); /* create string */ setsvalue2s(L, L->top.p, ts); /* anchor it ('loadVector' can GC) */ luaD_inctop(L); - loadVector(S, getstr(ts), size); /* load directly in final place */ + loadVector(S, getlngstr(ts), size); /* load directly in final place */ L->top.p--; /* pop string */ } luaC_objbarrier(L, p, ts); diff --git a/contrib/lua/src/lundump.h b/contrib/lua/src/lundump.h index f3748a998075..a97676ca1852 100644 --- a/contrib/lua/src/lundump.h +++ b/contrib/lua/src/lundump.h @@ -21,8 +21,7 @@ /* ** Encode major-minor version in one byte, one nibble for each */ -#define MYINT(s) (s[0]-'0') /* assume one-digit numerals */ -#define LUAC_VERSION (MYINT(LUA_VERSION_MAJOR)*16+MYINT(LUA_VERSION_MINOR)) +#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100) #define LUAC_FORMAT 0 /* this is the official format */ diff --git a/contrib/lua/src/lvm.c b/contrib/lua/src/lvm.c index 9d1bdfb0bd6e..45b47e7c8793 100644 --- a/contrib/lua/src/lvm.c +++ b/contrib/lua/src/lvm.c @@ -95,8 +95,10 @@ static int l_strton (const TValue *obj, TValue *result) { lua_assert(obj != result); if (!cvt2num(obj)) /* is object not a string? */ return 0; - else - return (luaO_str2num(svalue(obj), result) == vslen(obj) + 1); + else { + TString *st = tsvalue(obj); + return (luaO_str2num(getstr(st), result) == tsslen(st) + 1); + } } @@ -341,7 +343,10 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, lua_assert(isempty(slot)); /* slot must be empty */ tm = fasttm(L, h->metatable, TM_NEWINDEX); /* get metamethod */ if (tm == NULL) { /* no metamethod? */ + sethvalue2s(L, L->top.p, h); /* anchor 't' */ + L->top.p++; /* assume EXTRA_STACK */ luaH_finishset(L, h, key, slot, val); /* set new value */ + L->top.p--; invalidateTMcache(h); luaC_barrierback(L, obj2gco(h), val); return; @@ -370,30 +375,32 @@ void luaV_finishset (lua_State *L, const TValue *t, TValue *key, /* -** Compare two strings 'ls' x 'rs', returning an integer less-equal- -** -greater than zero if 'ls' is less-equal-greater than 'rs'. +** Compare two strings 'ts1' x 'ts2', returning an integer less-equal- +** -greater than zero if 'ts1' is less-equal-greater than 'ts2'. ** The code is a little tricky because it allows '\0' in the strings -** and it uses 'strcoll' (to respect locales) for each segments -** of the strings. +** and it uses 'strcoll' (to respect locales) for each segment +** of the strings. Note that segments can compare equal but still +** have different lengths. */ -static int l_strcmp (const TString *ls, const TString *rs) { - const char *l = getstr(ls); - size_t ll = tsslen(ls); - const char *r = getstr(rs); - size_t lr = tsslen(rs); +static int l_strcmp (const TString *ts1, const TString *ts2) { + const char *s1 = getstr(ts1); + size_t rl1 = tsslen(ts1); /* real length */ + const char *s2 = getstr(ts2); + size_t rl2 = tsslen(ts2); for (;;) { /* for each segment */ - int temp = strcoll(l, r); + int temp = strcoll(s1, s2); if (temp != 0) /* not equal? */ return temp; /* done */ else { /* strings are equal up to a '\0' */ - size_t len = strlen(l); /* index of first '\0' in both strings */ - if (len == lr) /* 'rs' is finished? */ - return (len == ll) ? 0 : 1; /* check 'ls' */ - else if (len == ll) /* 'ls' is finished? */ - return -1; /* 'ls' is less than 'rs' ('rs' is not finished) */ - /* both strings longer than 'len'; go on comparing after the '\0' */ - len++; - l += len; ll -= len; r += len; lr -= len; + size_t zl1 = strlen(s1); /* index of first '\0' in 's1' */ + size_t zl2 = strlen(s2); /* index of first '\0' in 's2' */ + if (zl2 == rl2) /* 's2' is finished? */ + return (zl1 == rl1) ? 0 : 1; /* check 's1' */ + else if (zl1 == rl1) /* 's1' is finished? */ + return -1; /* 's1' is less than 's2' ('s2' is not finished) */ + /* both strings longer than 'zl'; go on comparing after the '\0' */ + zl1++; zl2++; + s1 += zl1; rl1 -= zl1; s2 += zl2; rl2 -= zl2; } } } @@ -628,8 +635,9 @@ int luaV_equalobj (lua_State *L, const TValue *t1, const TValue *t2) { static void copy2buff (StkId top, int n, char *buff) { size_t tl = 0; /* size already copied */ do { - size_t l = vslen(s2v(top - n)); /* length of string being copied */ - memcpy(buff + tl, svalue(s2v(top - n)), l * sizeof(char)); + TString *st = tsvalue(s2v(top - n)); + size_t l = tsslen(st); /* length of string being copied */ + memcpy(buff + tl, getstr(st), l * sizeof(char)); tl += l; } while (--n > 0); } @@ -655,12 +663,12 @@ void luaV_concat (lua_State *L, int total) { } else { /* at least two non-empty string values; get as many as possible */ - size_t tl = vslen(s2v(top - 1)); + size_t tl = tsslen(tsvalue(s2v(top - 1))); TString *ts; /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { - size_t l = vslen(s2v(top - n - 1)); - if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { + size_t l = tsslen(tsvalue(s2v(top - n - 1))); + if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) { L->top.p = top - total; /* pop strings to avoid wasting stack */ luaG_runerror(L, "string length overflow"); } @@ -673,7 +681,7 @@ void luaV_concat (lua_State *L, int total) { } else { /* long string; copy strings directly to final result */ ts = luaS_createlngstrobj(L, tl); - copy2buff(top, n, getstr(ts)); + copy2buff(top, n, getlngstr(ts)); } setsvalue2s(L, top - n, ts); /* create result */ } @@ -1159,18 +1167,11 @@ void luaV_execute (lua_State *L, CallInfo *ci) { startfunc: trap = L->hookmask; returning: /* trap already set */ - cl = clLvalue(s2v(ci->func.p)); + cl = ci_func(ci); k = cl->p->k; pc = ci->u.l.savedpc; - if (l_unlikely(trap)) { - if (pc == cl->p->code) { /* first instruction (not resuming)? */ - if (cl->p->is_vararg) - trap = 0; /* hooks will start after VARARGPREP instruction */ - else /* check 'call' hook */ - luaD_hookcall(L, ci); - } - ci->u.l.trap = 1; /* assume trap is on, for now */ - } + if (l_unlikely(trap)) + trap = luaG_tracecall(L); base = ci->func.p + 1; /* main loop of interpreter */ for (;;) { @@ -1257,7 +1258,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *upval = cl->upvals[GETARG_B(i)]->v.p; TValue *rc = KC(i); - TString *key = tsvalue(rc); /* key must be a string */ + TString *key = tsvalue(rc); /* key must be a short string */ if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { setobj2s(L, ra, slot); } @@ -1300,7 +1301,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *rb = vRB(i); TValue *rc = KC(i); - TString *key = tsvalue(rc); /* key must be a string */ + TString *key = tsvalue(rc); /* key must be a short string */ if (luaV_fastget(L, rb, key, slot, luaH_getshortstr)) { setobj2s(L, ra, slot); } @@ -1313,7 +1314,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { TValue *upval = cl->upvals[GETARG_A(i)]->v.p; TValue *rb = KB(i); TValue *rc = RKC(i); - TString *key = tsvalue(rb); /* key must be a string */ + TString *key = tsvalue(rb); /* key must be a short string */ if (luaV_fastget(L, upval, key, slot, luaH_getshortstr)) { luaV_finishfastset(L, upval, slot, rc); } @@ -1356,7 +1357,7 @@ void luaV_execute (lua_State *L, CallInfo *ci) { const TValue *slot; TValue *rb = KB(i); TValue *rc = RKC(i); - TString *key = tsvalue(rb); /* key must be a string */ + TString *key = tsvalue(rb); /* key must be a short string */ if (luaV_fastget(L, s2v(ra), key, slot, luaH_getshortstr)) { luaV_finishfastset(L, s2v(ra), slot, rc); } diff --git a/contrib/mandoc/roff_term.c b/contrib/mandoc/roff_term.c index 8f95aa920790..85d2caeb2749 100644 --- a/contrib/mandoc/roff_term.c +++ b/contrib/mandoc/roff_term.c @@ -165,6 +165,7 @@ roff_term_pre_po(ROFF_TERM_ARGS) static int polast; /* Previously requested. */ static int po; /* Currently requested. */ static int pouse; /* Currently used. */ + int pomin; /* Minimum to be used. */ int pomax; /* Maximum to be used. */ int ponew; /* Newly requested. */ @@ -186,9 +187,9 @@ roff_term_pre_po(ROFF_TERM_ARGS) po = ponew; /* Truncate to the range [-offset, 60], remember, and apply it. */ + pomin = -p->tcol->offset; pomax = term_len(p, 60); - pouse = po >= pomax ? pomax : - po < -(int)p->tcol->offset ? -p->tcol->offset : po; + pouse = po > pomax ? pomax : po < pomin ? pomin : po; p->tcol->offset += pouse; } diff --git a/contrib/one-true-awk/FIXES b/contrib/one-true-awk/FIXES index b3bf38f0aa1c..b876b9ec5ec9 100644 --- a/contrib/one-true-awk/FIXES +++ b/contrib/one-true-awk/FIXES @@ -25,6 +25,14 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the second edition of the AWK book was published in September 2023. +Aug 04, 2025 + Fix incorrect divisor in rand() - it was returning + even random numbers only. Thanks to Ozan Yigit. + + Fix a syntax issue with /= that caused constants to + turn into variables [eg. 42 /= 7]. Thanks to Arnold + Robbins. + Jan 14, 2025 Fix incorrect error line number issues. unput has no business managing lineno. Thanks to Ozan Yigit. diff --git a/contrib/one-true-awk/main.c b/contrib/one-true-awk/main.c index 361c23e70861..b8053af34b05 100644 --- a/contrib/one-true-awk/main.c +++ b/contrib/one-true-awk/main.c @@ -22,7 +22,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ -const char *version = "version 20250116"; +const char *version = "version 20250804"; #define DEBUG #include <stdio.h> diff --git a/contrib/one-true-awk/run.c b/contrib/one-true-awk/run.c index eaddfdecbdd3..9bc07a517372 100644 --- a/contrib/one-true-awk/run.c +++ b/contrib/one-true-awk/run.c @@ -1567,6 +1567,8 @@ Cell *assign(Node **a, int n) /* a[0] = a[1], a[0] += a[1], etc. */ xf *= yf; break; case DIVEQ: + if ((x->tval & CON) != 0) + FATAL("non-constant required for left side of /="); if (yf == 0) FATAL("division by zero in /="); xf /= yf; @@ -2188,7 +2190,7 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis /* random() returns numbers in [0..2^31-1] * in order to get a number in [0, 1), divide it by 2^31 */ - u = (Awkfloat) random() / (0x7fffffffL + 0x1UL); + u = (Awkfloat) random() / RAND_MAX; break; case FSRAND: if (isrec(x)) /* no argument provided */ diff --git a/contrib/tcpdump/print-pfsync.c b/contrib/tcpdump/print-pfsync.c index 6bf9abaf3903..e4f11930816c 100644 --- a/contrib/tcpdump/print-pfsync.c +++ b/contrib/tcpdump/print-pfsync.c @@ -53,8 +53,8 @@ static void pfsync_print(netdissect_options *, struct pfsync_header *, const u_char *, u_int); static void print_src_dst(netdissect_options *, - const struct pfsync_state_peer *, - const struct pfsync_state_peer *, uint8_t); + const struct pf_state_peer_export *, + const struct pf_state_peer_export *, uint8_t); static void print_state(netdissect_options *, union pfsync_state_union *, int); void @@ -330,7 +330,7 @@ print_host(netdissect_options *ndo, struct pf_addr *addr, uint16_t port, } static void -print_seq(netdissect_options *ndo, const struct pfsync_state_peer *p) +print_seq(netdissect_options *ndo, const struct pf_state_peer_export *p) { if (p->seqdiff) ND_PRINT("[%u + %u](+%u)", ntohl(p->seqlo), @@ -341,8 +341,8 @@ print_seq(netdissect_options *ndo, const struct pfsync_state_peer *p) } static void -print_src_dst(netdissect_options *ndo, const struct pfsync_state_peer *src, - const struct pfsync_state_peer *dst, uint8_t proto) +print_src_dst(netdissect_options *ndo, const struct pf_state_peer_export *src, + const struct pf_state_peer_export *dst, uint8_t proto) { if (proto == IPPROTO_TCP) { @@ -390,7 +390,7 @@ print_src_dst(netdissect_options *ndo, const struct pfsync_state_peer *src, static void print_state(netdissect_options *ndo, union pfsync_state_union *s, int version) { - struct pfsync_state_peer *src, *dst; + struct pf_state_peer_export *src, *dst; struct pfsync_state_key *sk, *nk; int min, sec; diff --git a/contrib/tzcode/Makefile b/contrib/tzcode/Makefile index 0087b4596515..2130582c2deb 100644 --- a/contrib/tzcode/Makefile +++ b/contrib/tzcode/Makefile @@ -137,7 +137,7 @@ TIME_T_ALTERNATIVES_TAIL = int_least32_t.ck uint_least32_t.ck \ uint_least64_t.ck # What kind of TZif data files to generate. (TZif is the binary time -# zone data format that zic generates; see Internet RFC 8536.) +# zone data format that zic generates; see Internet RFC 9636.) # If you want only POSIX time, with time values interpreted as # seconds since the epoch (not counting leap seconds), use # REDO= posix_only @@ -255,6 +255,7 @@ LDLIBS= # -DHAVE_UNISTD_H=0 if <unistd.h> does not work* # -DHAVE_UTMPX_H=0 if <utmpx.h> does not work* # -Dlocale_t=XXX if your system uses XXX instead of locale_t +# -DMKTIME_MIGHT_OVERFLOW if mktime might fail due to time_t overflow # -DPORT_TO_C89 if tzcode should also run on mostly-C89 platforms+ # Typically it is better to use a later standard. For example, # with GCC 4.9.4 (2016), prefer '-std=gnu11' to '-DPORT_TO_C89'. @@ -262,7 +263,7 @@ LDLIBS= # feature (integers at least 64 bits wide) and maybe more. # -DRESERVE_STD_EXT_IDS if your platform reserves standard identifiers # with external linkage, e.g., applications cannot define 'localtime'. -# -Dssize_t=long on hosts like MS-Windows that lack ssize_t +# -Dssize_t=int on hosts like MS-Windows that lack ssize_t # -DSUPPORT_C89=0 if the tzcode library should not support C89 callers # Although -DSUPPORT_C89=0 might work around latent bugs in callers, # it does not conform to POSIX. @@ -285,7 +286,7 @@ LDLIBS= # This mishandles some past timestamps, as US DST rules have changed. # It also mishandles settings like TZ='EET-2EEST' for eastern Europe, # as Europe and US DST rules differ. -# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 255) +# -DTZNAME_MAXIMUM=N to limit time zone abbreviations to N bytes (default 254) # -DUNINIT_TRAP if reading uninitialized storage can cause problems # other than simply getting garbage data # -DUSE_LTZ=0 to build zdump with the system time zone library @@ -319,7 +320,8 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ $(GCC_INSTRUMENT) \ -Wall -Wextra \ -Walloc-size-larger-than=100000 -Warray-bounds=2 \ - -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wdate-time \ + -Wbad-function-cast -Wbidi-chars=any,ucn -Wcast-align=strict -Wcast-qual \ + -Wdate-time \ -Wdeclaration-after-statement -Wdouble-promotion \ -Wduplicated-branches -Wduplicated-cond -Wflex-array-member-not-at-end \ -Wformat=2 -Wformat-overflow=2 -Wformat-signedness -Wformat-truncation \ @@ -336,7 +338,7 @@ GCC_DEBUG_FLAGS = -DGCC_LINT -g3 -O3 \ -Wsuggest-attribute=noreturn -Wsuggest-attribute=pure \ -Wtrampolines -Wundef -Wunused-macros -Wuse-after-free=3 \ -Wvariadic-macros -Wvla -Wwrite-strings \ - -Wno-format-nonliteral -Wno-sign-compare + -Wno-format-nonliteral -Wno-sign-compare -Wno-type-limits # # If your system has a "GMT offset" field in its "struct tm"s # (or if you decide to add such a field in your system's "time.h" file), @@ -614,8 +616,8 @@ TZS_YEAR= 2050 TZS_CUTOFF_FLAG= -c $(TZS_YEAR) TZS= to$(TZS_YEAR).tzs TZS_NEW= to$(TZS_YEAR)new.tzs -TZS_DEPS= $(YDATA) asctime.c localtime.c \ - private.h tzfile.h zdump.c zic.c +TZS_DEPS= $(YDATA) localtime.c private.h \ + strftime.c tzfile.h zdump.c zic.c TZDATA_DIST = $(COMMON) $(DATA) $(MISC) # EIGHT_YARDS is just a yard short of the whole ENCHILADA. EIGHT_YARDS = $(TZDATA_DIST) $(DOCS) $(SOURCES) tzdata.zi @@ -855,10 +857,10 @@ tzselect: tzselect.ksh version chmod +x $@.out mv $@.out $@ -check: check_mild back.ck +check: check_mild back.ck now.ck check_mild: check_web check_zishrink \ character-set.ck white-space.ck links.ck mainguard.ck \ - name-lengths.ck now.ck slashed-abbrs.ck sorted.ck \ + name-lengths.ck slashed-abbrs.ck sorted.ck \ tables.ck ziguard.ck tzs.ck # True if UTF8_LOCALE does not work; @@ -1103,7 +1105,7 @@ set-timestamps.out: $(EIGHT_YARDS) touch -md @1 test.out; then \ rm -f test.out && \ for file in $$files; do \ - if git diff --quiet $$file; then \ + if git diff --quiet HEAD $$file; then \ time=$$(TZ=UTC0 git log -1 \ --format='tformat:%cd' \ --date='format:%Y-%m-%dT%H:%M:%SZ' \ @@ -1354,13 +1356,13 @@ long-long.ck unsigned.ck: $(VERSION_DEPS) zonenames: tzdata.zi @$(AWK) '/^Z/ { print $$2 } /^L/ { print $$3 }' tzdata.zi -asctime.o: private.h tzfile.h +asctime.o: private.h date.o: private.h difftime.o: private.h -localtime.o: private.h tzfile.h tzdir.h -strftime.o: private.h tzfile.h -zdump.o: version.h -zic.o: private.h tzfile.h tzdir.h version.h +localtime.o: private.h tzdir.h tzfile.h +strftime.o: localtime.c private.h tzdir.h tzfile.h +zdump.o: private.h version.h +zic.o: private.h tzdir.h tzfile.h version.h .PHONY: ALL INSTALL all .PHONY: check check_mild check_time_t_alternatives diff --git a/contrib/tzcode/NEWS b/contrib/tzcode/NEWS index 83b8b8c8d39c..8c0771641ef0 100644 --- a/contrib/tzcode/NEWS +++ b/contrib/tzcode/NEWS @@ -1,5 +1,108 @@ News for the tz database +Release 2025b - 2025-03-22 13:40:46 -0700 + + Briefly: + New zone for Aysén Region in Chile which moves from -04/-03 to -03. + + Changes to future timestamps + + Chile's Aysén Region moves from -04/-03 to -03 year-round, joining + Magallanes Region. The region will not change its clocks on + 2025-04-05 at 24:00, diverging from America/Santiago and creating a + new zone America/Coyhaique. (Thanks to Yonathan Dossow.) Model + this as a change to standard offset effective 2025-03-20. + + Changes to past timestamps + + Iran switched from +04 to +0330 on 1978-11-10 at 24:00, not at + year end. (Thanks to Roozbeh Pournader.) + + Changes to code + + 'zic -l TIMEZONE -d . -l /some/other/file/system' no longer + attempts to create an incorrect symlink, and no longer has a + read buffer underflow. (Problem reported by Evgeniy Gorbanev.) + + +Release 2025a - 2025-01-15 10:47:24 -0800 + + Briefly: + Paraguay adopted permanent -03 starting spring 2024. + Improve pre-1991 data for the Philippines. + Etc/Unknown is now reserved. + + Changes to future timestamps + + Paraguay stopped changing its clocks after the spring-forward + transition on 2024-10-06, so it is now permanently at -03. + (Thanks to Heitor David Pinto and Even Scharning.) + This affects timestamps starting 2025-03-22, as well as the + obsolescent tm_isdst flags starting 2024-10-15. + + Changes to past timestamps + + Correct timestamps for the Philippines before 1900, and from 1937 + through 1990. (Thanks to P Chan for the heads-up and citations.) + This includes adjusting local mean time before 1899; fixing + transitions in September 1899, January 1937, and June 1954; adding + transitions in December 1941, November 1945, March and September + 1977, and May and July 1990; and removing incorrect transitions in + March and September 1978. + + Changes to data + + Add zone1970.tab lines for the Concordia and Eyre Bird Observatory + research stations. (Thanks to Derick Rethans and Jule Dabars.) + + Changes to code + + strftime %s now generates the correct numeric string even when the + represented number does not fit into time_t. This is better than + generating the numeric equivalent of (time_t) -1, as strftime did + in TZDB releases 96a (when %s was introduced) through 2020a and in + releases 2022b through 2024b. It is also better than failing and + returning 0, as strftime did in releases 2020b through 2022a. + + strftime now outputs an invalid conversion specifier as-is, + instead of eliding the leading '%', which confused debugging. + + An invalid TZ now generates the time zone abbreviation "-00", not + "UTC", to help the user see that an error has occurred. (Thanks + to Arthur David Olson for suggesting a "wrong result".) + + mktime and timeoff no longer incorrectly fail merely because a + struct tm component near INT_MIN or INT_MAX overflows when a + lower-order component carries into it. + + TZNAME_MAXIMUM, the maximum number of bytes in a proleptic TZ + string's time zone abbreviation, now defaults to 254 not 255. + This helps reduce the size of internal state from 25480 to 21384 + on common platforms. This change should not be a problem, as + nobody uses such long "abbreviations" and the longstanding tzcode + maximum was 16 until release 2023a. For those who prefer no + arbitrary limits, you can now specify TZNAME_MAXIMUM values up to + PTRDIFF_MAX, a limit forced by C anyway; formerly tzcode silently + misbehaved unless TZNAME_MAXIMUM was less than INT_MAX. + + tzset and related functions no longer leak a file descriptor if + another thread forks or execs at about the same time and if the + platform has O_CLOFORK and O_CLOEXEC respectively. Also, the + functions no longer let a TZif file become a controlling terminal. + + 'zdump -' now reads TZif data from /dev/stdin. + (From a question by Arthur David Olson.) + + Changes to documentation + + The name Etc/Unknown is now reserved: it will not be used by TZDB. + This is for compatibility with CLDR, which uses the string + "Etc/Unknown" for an unknown or invalid timezone. (Thanks to + Justin Grant, Mark Davis, and Guy Harris.) + + Cite Internet RFC 9636, which obsoletes RFC 8536 for TZif format. + + Release 2024b - 2024-09-04 12:27:47 -0700 Briefly: @@ -116,7 +219,7 @@ Release 2024b - 2024-09-04 12:27:47 -0700 Changes to commentary Commentary about historical transitions in Portugal and her former - colonies has been expanded with links to many relevant legislation. + colonies has been expanded with links to relevant legislation. (Thanks to Tim Parenti.) @@ -204,10 +307,10 @@ Release 2023d - 2023-12-21 20:02:24 -0800 changing its time zone from -01/+00 to -02/-01 at the same moment as the spring-forward transition. Its clocks will therefore not spring forward as previously scheduled. The time zone change - reverts to its common practice before 1981. + reverts to its common practice before 1981. (Thanks to Jule Dabars.) Fix predictions for DST transitions in Palestine in 2072-2075, - correcting a typo introduced in 2023a. + correcting a typo introduced in 2023a. (Thanks to Jule Dabars.) Changes to past and future timestamps diff --git a/contrib/tzcode/asctime.c b/contrib/tzcode/asctime.c index ebb90a1cc84d..1977a2272896 100644 --- a/contrib/tzcode/asctime.c +++ b/contrib/tzcode/asctime.c @@ -7,6 +7,7 @@ /* ** Avoid the temptation to punt entirely to strftime; +** strftime can behave badly when tm components are out of range, and ** the output of strftime is supposed to be locale specific ** whereas the output of asctime is supposed to be constant. */ @@ -18,27 +19,6 @@ #include "un-namespace.h" #include <stdio.h> -/* -** All years associated with 32-bit time_t values are exactly four digits long; -** some years associated with 64-bit time_t values are not. -** Vintage programs are coded for years that are always four digits long -** and may assume that the newline always lands in the same place. -** For years that are less than four digits, we pad the output with -** leading zeroes to get the newline in the traditional place. -** The -4 ensures that we get four characters of output even if -** we call a strftime variant that produces fewer characters for some years. -** This conforms to recent ISO C and POSIX standards, which say behavior -** is undefined when the year is less than 1000 or greater than 9999. -*/ -static char const ASCTIME_FMT[] = "%s %s%3d %.2d:%.2d:%.2d %-4s\n"; -/* -** For years that are more than four digits we put extra spaces before the year -** so that code trying to overwrite the newline won't end up overwriting -** a digit within a year and truncating the year (operating on the assumption -** that no output is better than wrong output). -*/ -static char const ASCTIME_FMT_B[] = "%s %s%3d %.2d:%.2d:%.2d %s\n"; - enum { STD_ASCTIME_BUF_SIZE = 26 }; /* ** Big enough for something such as @@ -52,14 +32,24 @@ enum { STD_ASCTIME_BUF_SIZE = 26 }; */ static char buf_asctime[2*3 + 5*INT_STRLEN_MAXIMUM(int) + 7 + 2 + 1 + 1]; -/* A similar buffer for ctime. - C89 requires that they be the same buffer. - This requirement was removed in C99, so support it only if requested, - as support is more likely to lead to bugs in badly written programs. */ -#if SUPPORT_C89 -# define buf_ctime buf_asctime -#else -static char buf_ctime[sizeof buf_asctime]; +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF +# include <stdarg.h> +ATTRIBUTE_FORMAT((printf, 3, 4)) static int +my_snprintf(char *s, size_t size, char const *format, ...) +{ + int n; + va_list args; + char stackbuf[sizeof buf_asctime]; + va_start(args, format); + n = vsprintf(stackbuf, format, args); + va_end (args); + if (0 <= n && n < size) + memcpy (s, stackbuf, n + 1); + return n; +} +# undef snprintf +# define snprintf my_snprintf #endif /* Publish asctime_r and ctime_r only when supporting older POSIX. */ @@ -84,14 +74,19 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - const char * wn; - const char * mn; - char year[INT_STRLEN_MAXIMUM(int) + 2]; - char result[sizeof buf_asctime]; + register const char * wn; + register const char * mn; + int year, mday, hour, min, sec; + long long_TM_YEAR_BASE = TM_YEAR_BASE; + size_t bufsize = (buf == buf_asctime + ? sizeof buf_asctime : STD_ASCTIME_BUF_SIZE); if (timeptr == NULL) { + strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + /* Set errno now, since strcpy might change it in + POSIX.1-2017 and earlier. */ errno = EINVAL; - return strcpy(buf, "??? ??? ?? ??:??:?? ????\n"); + return buf; } if (timeptr->tm_wday < 0 || timeptr->tm_wday >= DAYSPERWEEK) wn = "???"; @@ -99,25 +94,41 @@ asctime_r(struct tm const *restrict timeptr, char *restrict buf) if (timeptr->tm_mon < 0 || timeptr->tm_mon >= MONSPERYEAR) mn = "???"; else mn = mon_name[timeptr->tm_mon]; - /* - ** Use strftime's %Y to generate the year, to avoid overflow problems - ** when computing timeptr->tm_year + TM_YEAR_BASE. - ** Assume that strftime is unaffected by other out-of-range members - ** (e.g., timeptr->tm_mday) when processing "%Y". - */ - strftime(year, sizeof year, "%Y", timeptr); - /* - ** We avoid using snprintf since it's not available on all systems. - */ - sprintf(result, - ((strlen(year) <= 4) ? ASCTIME_FMT : ASCTIME_FMT_B), - wn, mn, - timeptr->tm_mday, timeptr->tm_hour, - timeptr->tm_min, timeptr->tm_sec, - year); - if (strlen(result) < STD_ASCTIME_BUF_SIZE - || buf == buf_ctime || buf == buf_asctime) - return strcpy(buf, result); + + year = timeptr->tm_year; + mday = timeptr->tm_mday; + hour = timeptr->tm_hour; + min = timeptr->tm_min; + sec = timeptr->tm_sec; + + /* Vintage programs are coded for years that are always four bytes long + and may assume that the newline always lands in the same place. + For years that are less than four bytes, pad the output with + leading zeroes to get the newline in the traditional place. + For years longer than four bytes, put extra spaces before the year + so that vintage code trying to overwrite the newline + won't overwrite a digit within a year and truncate the year, + using the principle that no output is better than wrong output. + This conforms to ISO C and POSIX standards, which say behavior + is undefined when the year is less than 1000 or greater than 9999. + + Also, avoid overflow when formatting tm_year + TM_YEAR_BASE. */ + + if ((year <= LONG_MAX - TM_YEAR_BASE + ? snprintf (buf, bufsize, + ((-999 - TM_YEAR_BASE <= year + && year <= 9999 - TM_YEAR_BASE) + ? "%s %s%3d %.2d:%.2d:%.2d %04ld\n" + : "%s %s%3d %.2d:%.2d:%.2d %ld\n"), + wn, mn, mday, hour, min, sec, + year + long_TM_YEAR_BASE) + : snprintf (buf, bufsize, + "%s %s%3d %.2d:%.2d:%.2d %d%d\n", + wn, mn, mday, hour, min, sec, + year / 10 + TM_YEAR_BASE / 10, + year % 10)) + < bufsize) + return buf; else { errno = EOVERFLOW; return NULL; @@ -142,5 +153,8 @@ ctime_r(const time_t *timep, char *buf) char * ctime(const time_t *timep) { - return ctime_r(timep, buf_ctime); + /* Do not call localtime_r, as C23 requires ctime to initialize the + static storage that localtime updates. */ + struct tm *tmp = localtime(timep); + return tmp ? asctime(tmp) : NULL; } diff --git a/contrib/tzcode/date.1 b/contrib/tzcode/date.1 index 01907bc76e2c..3a02e7c2e08a 100644 --- a/contrib/tzcode/date.1 +++ b/contrib/tzcode/date.1 @@ -6,15 +6,13 @@ date \- show and set date and time .SH SYNOPSIS .if n .nh .if n .na -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B date [ -.B \*-u +.B \-u ] [ -.B \*-c +.B \-c ] [ -.B \*-r +.B \-r .I seconds ] [ .BI + format @@ -35,7 +33,7 @@ command without arguments writes the date and time to the standard output in the form .ce 1 -Wed Mar 8 14:54:40 EST 1989 +Sat Mar 8 14:54:40 EST 2025 .br with .B EST @@ -49,99 +47,24 @@ If a command-line argument starts with a plus sign (\c .q "\fB+\fP" ), the rest of the argument is used as a .I format -that controls what appears in the output. -In the format, when a percent sign (\c -.q "\fB%\fP" -appears, -it and the character after it are not output, -but rather identify part of the date or time -to be output in a particular way -(or identify a special character to output): -.nf -.sp -.if t .in +.5i -.if n .in +2 -.ta \w'%M\0\0'u +\w'Wed Mar 8 14:54:40 EST 1989\0\0'u - Sample output Explanation -%a Wed Abbreviated weekday name* -%A Wednesday Full weekday name* -%b Mar Abbreviated month name* -%B March Full month name* -%c Wed Mar 08 14:54:40 1989 Date and time* -%C 19 Century -%d 08 Day of month (always two digits) -%D 03/08/89 Month/day/year (eight characters) -%e 8 Day of month (leading zero blanked) -%h Mar Abbreviated month name* -%H 14 24-hour-clock hour (two digits) -%I 02 12-hour-clock hour (two digits) -%j 067 Julian day number (three digits) -%k 2 12-hour-clock hour (leading zero blanked) -%l 14 24-hour-clock hour (leading zero blanked) -%m 03 Month number (two digits) -%M 54 Minute (two digits) -%n \\n newline character -%p PM AM/PM designation -%r 02:54:40 PM Hour:minute:second AM/PM designation -%R 14:54 Hour:minute -%S 40 Second (two digits) -%t \\t tab character -%T 14:54:40 Hour:minute:second -%U 10 Sunday-based week number (two digits) -%w 3 Day number (one digit, Sunday is 0) -%W 10 Monday-based week number (two digits) -%x 03/08/89 Date* -%X 14:54:40 Time* -%y 89 Last two digits of year -%Y 1989 Year in full -%z -0500 Numeric time zone -%Z EST Time zone abbreviation -%+ Wed Mar 8 14:54:40 EST 1989 Default output format* -.if t .in -.5i -.if n .in -2 -* The exact output depends on the locale. -.sp -.fi -If a character other than one of those shown above appears after -a percent sign in the format, -that following character is output. -All other characters in the format are copied unchanged to the output; -a newline character is always added at the end of the output. -.PP -In Sunday-based week numbering, -the first Sunday of the year begins week 1; -days preceding it are part of -.q "week 0" . -In Monday-based week numbering, -the first Monday of the year begins week 1. -.PP -To set the date, use a command line argument with one of the following forms: -.nf -.if t .in +.5i -.if n .in +2 -.ta \w'198903081454\0'u -1454 24-hour-clock hours (first two digits) and minutes -081454 Month day (first two digits), hours, and minutes -03081454 Month (two digits, January is 01), month day, hours, minutes -8903081454 Year, month, month day, hours, minutes -0308145489 Month, month day, hours, minutes, year - (on System V-compatible systems) -030814541989 Month, month day, hours, minutes, four-digit year -198903081454 Four-digit year, month, month day, hours, minutes -.if t .in -.5i -.if n .in -2 -.fi -If the century, year, month, or month day is not given, -the current value is used. -Any of the above forms may be followed by a period and two digits that give -the seconds part of the new time; if no seconds are given, zero is assumed. +that is processed by +.BR strftime (3) +to determine what to output; +a newline character is appended. +For example, the shell command: +.ce 1 +date +"%Y\-%m\-%d %H:%M:%S %z" +.br +outputs a line like +.q "2025\-03\-08 14:54:40 \-0500" +instead. .PP These options are available: .TP -.BR \*-u " or " \*-c +.BR \-u " or " \-c Use Universal Time when setting and showing the date and time. .TP -.BI "\*-r " seconds +.BI "\-r " seconds Output the date that corresponds to .I seconds past the epoch of 1970-01-01 00:00:00 UTC, where @@ -149,16 +72,13 @@ past the epoch of 1970-01-01 00:00:00 UTC, where should be an integer, either decimal, octal (leading 0), or hexadecimal (leading 0x), preceded by an optional sign. .SH FILES -.ta \w'/usr/share/zoneinfo/posixrules\0\0'u +.ta \w'/usr/share/zoneinfo/Etc/UTC\0\0'u /etc/localtime local timezone file .br /usr/lib/locale/\f2L\fP/LC_TIME description of time locale \f2L\fP .br /usr/share/zoneinfo timezone directory .br -/usr/share/zoneinfo/posixrules default DST rules (obsolete) -.br -/usr/share/zoneinfo/GMT for UTC leap seconds -.PP -If /usr/share/zoneinfo/GMT is absent, -UTC leap seconds are loaded from /usr/share/zoneinfo/GMT0 if present. +/usr/share/zoneinfo/Etc/UTC for UTC leap seconds +.SH SEE ALSO +.BR strftime (3). diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c index a6ec3d8e4e21..a80d422f2955 100644 --- a/contrib/tzcode/localtime.c +++ b/contrib/tzcode/localtime.c @@ -13,42 +13,116 @@ /*LINTLIBRARY*/ #define LOCALTIME_IMPLEMENTATION +#ifdef __FreeBSD__ #include "namespace.h" +#include <pthread.h> +#endif /* __FreeBSD__ */ #ifdef DETECT_TZ_CHANGES -#ifndef DETECT_TZ_CHANGES_INTERVAL -#define DETECT_TZ_CHANGES_INTERVAL 61 -#endif +# ifndef DETECT_TZ_CHANGES_INTERVAL +# define DETECT_TZ_CHANGES_INTERVAL 61 +# endif int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL; -#include <sys/stat.h> -#endif -#include <fcntl.h> -#if THREAD_SAFE -#include <pthread.h> -#endif +# include <sys/stat.h> +#endif /* DETECT_TZ_CHANGES */ #include "private.h" -#include "un-namespace.h" #include "tzdir.h" #include "tzfile.h" - +#include <fcntl.h> +#ifdef __FreeBSD__ #include "libc_private.h" +#include "un-namespace.h" +#endif /* __FreeBSD__ */ + +#if HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif +#if !defined S_ISREG && defined S_IFREG +/* Ancient UNIX or recent MS-Windows. */ +# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG) +#endif #if defined THREAD_SAFE && THREAD_SAFE +# include <pthread.h> +#ifdef __FreeBSD__ +# define pthread_mutex_lock(l) (__isthreaded ? _pthread_mutex_lock(l) : 0) +# define pthread_mutex_unlock(l) (__isthreaded ? _pthread_mutex_unlock(l) : 0) +#endif /* __FreeBSD__ */ static pthread_mutex_t locallock = PTHREAD_MUTEX_INITIALIZER; -static int lock(void) { - if (__isthreaded) - return _pthread_mutex_lock(&locallock); - return 0; -} -static void unlock(void) { - if (__isthreaded) - _pthread_mutex_unlock(&locallock); -} +static int lock(void) { return pthread_mutex_lock(&locallock); } +static void unlock(void) { pthread_mutex_unlock(&locallock); } #else static int lock(void) { return 0; } static void unlock(void) { } #endif +/* Unless intptr_t is missing, pacify gcc -Wcast-qual on char const * exprs. + Use this carefully, as the casts disable type checking. + This is a macro so that it can be used in static initializers. */ +#ifdef INTPTR_MAX +# define UNCONST(a) ((char *) (intptr_t) (a)) +#else +# define UNCONST(a) ((char *) (a)) +#endif + +/* A signed type wider than int, so that we can add 1900 + tm_mon/12 to tm_year + without overflow. The static_assert checks that it is indeed wider + than int; if this fails on your platform please let us know. */ +#if INT_MAX < LONG_MAX +typedef long iinntt; +# define IINNTT_MIN LONG_MIN +# define IINNTT_MAX LONG_MAX +#elif INT_MAX < LLONG_MAX +typedef long long iinntt; +# define IINNTT_MIN LLONG_MIN +# define IINNTT_MAX LLONG_MAX +#else +typedef intmax_t iinntt; +# define IINNTT_MIN INTMAX_MIN +# define IINNTT_MAX INTMAX_MAX +#endif +static_assert(IINNTT_MIN < INT_MIN && INT_MAX < IINNTT_MAX); + +/* On platforms where offtime or mktime might overflow, + strftime.c defines USE_TIMEX_T to be true and includes us. + This tells us to #define time_t to an internal type timex_t that is + wide enough so that strftime %s never suffers from integer overflow, + and to #define offtime (if TM_GMTOFF is defined) or mktime (otherwise) + to a static function that returns the redefined time_t. + It also tells us to define only data and code needed + to support the offtime or mktime variant. */ +#ifndef USE_TIMEX_T +# define USE_TIMEX_T false +#endif +#if USE_TIMEX_T +# undef TIME_T_MIN +# undef TIME_T_MAX +# undef time_t +# define time_t timex_t +# if MKTIME_FITS_IN(LONG_MIN, LONG_MAX) +typedef long timex_t; +# define TIME_T_MIN LONG_MIN +# define TIME_T_MAX LONG_MAX +# elif MKTIME_FITS_IN(LLONG_MIN, LLONG_MAX) +typedef long long timex_t; +# define TIME_T_MIN LLONG_MIN +# define TIME_T_MAX LLONG_MAX +# else +typedef intmax_t timex_t; +# define TIME_T_MIN INTMAX_MIN +# define TIME_T_MAX INTMAX_MAX +# endif + +# ifdef TM_GMTOFF +# undef timeoff +# define timeoff timex_timeoff +# undef EXTERN_TIMEOFF +# else +# undef mktime +# define mktime timex_mktime +# endif +#endif + #ifndef TZ_ABBR_CHAR_SET # define TZ_ABBR_CHAR_SET \ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" @@ -58,12 +132,23 @@ static void unlock(void) { } # define TZ_ABBR_ERR_CHAR '_' #endif /* !defined TZ_ABBR_ERR_CHAR */ -/* -** Support non-POSIX platforms that distinguish between text and binary files. -*/ +/* Port to platforms that lack some O_* flags. Unless otherwise + specified, the flags are standardized by POSIX. */ #ifndef O_BINARY -# define O_BINARY 0 +# define O_BINARY 0 /* MS-Windows */ +#endif +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif +#ifndef O_CLOFORK +# define O_CLOFORK 0 +#endif +#ifndef O_IGNORE_CTTY +# define O_IGNORE_CTTY 0 /* GNU/Hurd */ +#endif +#ifndef O_NOCTTY +# define O_NOCTTY 0 #endif #ifndef WILDABBR @@ -92,7 +177,10 @@ static void unlock(void) { } static const char wildabbr[] = WILDABBR; static char const etc_utc[] = "Etc/UTC"; + +#if !USE_TIMEX_T || defined TM_ZONE || !defined TM_GMTOFF static char const *utc = etc_utc + sizeof "Etc/" - 1; +#endif /* ** The DST rules to use if TZ has no rules and we can't load TZDEFRULES. @@ -104,10 +192,31 @@ static char const *utc = etc_utc + sizeof "Etc/" - 1; # define TZDEFRULESTRING ",M3.2.0,M11.1.0" #endif +/* Limit to time zone abbreviation length in proleptic TZ strings. + This is distinct from TZ_MAX_CHARS, which limits TZif file contents. + It defaults to 254, not 255, so that desigidx_type can be an unsigned char. + unsigned char suffices for TZif files, so the only reason to increase + TZNAME_MAXIMUM is to support TZ strings specifying abbreviations + longer than 254 bytes. There is little reason to do that, though, + as strings that long are hardly "abbreviations". */ +#ifndef TZNAME_MAXIMUM +# define TZNAME_MAXIMUM 254 +#endif + +#if TZNAME_MAXIMUM < UCHAR_MAX +typedef unsigned char desigidx_type; +#elif TZNAME_MAXIMUM < INT_MAX +typedef int desigidx_type; +#elif TZNAME_MAXIMUM < PTRDIFF_MAX +typedef ptrdiff_t desigidx_type; +#else +# error "TZNAME_MAXIMUM too large" +#endif + struct ttinfo { /* time type information */ - int_fast32_t tt_utoff; /* UT offset in seconds */ + int_least32_t tt_utoff; /* UT offset in seconds */ + desigidx_type tt_desigidx; /* abbreviation list index */ bool tt_isdst; /* used to set tm_isdst */ - int tt_desigidx; /* abbreviation list index */ bool tt_ttisstd; /* transition is std time */ bool tt_ttisut; /* transition is UT */ }; @@ -126,12 +235,6 @@ static char const UNSPEC[] = "-00"; for ttunspecified to work without crashing. */ enum { CHARS_EXTRA = max(sizeof UNSPEC, 2) - 1 }; -/* Limit to time zone abbreviation length in proleptic TZ strings. - This is distinct from TZ_MAX_CHARS, which limits TZif file contents. */ -#ifndef TZNAME_MAXIMUM -# define TZNAME_MAXIMUM 255 -#endif - /* A representation of the contents of a TZif file. Ideally this would have no size limits; the following sizes should suffice for practical use. This struct should not be too large, as instances @@ -166,12 +269,14 @@ struct rule { int_fast32_t r_time; /* transition time of rule */ }; +#ifdef __FreeBSD__ +static void tzset_unlocked_name(char const *); +#endif /* __FreeBSD__ */ static struct tm *gmtsub(struct state const *, time_t const *, int_fast32_t, struct tm *); static bool increment_overflow(int *, int); static bool increment_overflow_time(time_t *, int_fast32_t); static int_fast32_t leapcorr(struct state const *, time_t); -static bool normalize_overflow32(int_fast32_t *, int *, int); static struct tm *timesub(time_t const *, int_fast32_t, struct state const *, struct tm *); static bool tzparse(char const *, struct state *, struct state const *); @@ -192,9 +297,11 @@ static struct state *const gmtptr = &gmtmem; # define TZ_STRLEN_MAX 255 #endif /* !defined TZ_STRLEN_MAX */ +#if !USE_TIMEX_T || !defined TM_GMTOFF static char lcl_TZname[TZ_STRLEN_MAX + 1]; static int lcl_is_set; - +#endif +#ifdef __FreeBSD__ static pthread_once_t gmt_once = PTHREAD_ONCE_INIT; static pthread_once_t gmtime_once = PTHREAD_ONCE_INIT; static pthread_key_t gmtime_key; @@ -205,6 +312,7 @@ static int offtime_key_error; static pthread_once_t localtime_once = PTHREAD_ONCE_INIT; static pthread_key_t localtime_key; static int localtime_key_error; +#endif /* __FreeBSD__ */ /* ** Section 4.12.3 of X3.159-1989 requires that @@ -218,27 +326,29 @@ static int localtime_key_error; ** trigger latent bugs in programs. */ -#if SUPPORT_C89 +#if !USE_TIMEX_T + +# if SUPPORT_C89 static struct tm tm; #endif -#if 2 <= HAVE_TZNAME + TZ_TIME_T -char * tzname[2] = { - (char *) wildabbr, - (char *) wildabbr -}; -#endif -#if 2 <= USG_COMPAT + TZ_TIME_T +# if 2 <= HAVE_TZNAME + TZ_TIME_T +char *tzname[2] = { UNCONST(wildabbr), UNCONST(wildabbr) }; +# endif +# if 2 <= USG_COMPAT + TZ_TIME_T long timezone; int daylight; -#endif -#if 2 <= ALTZONE + TZ_TIME_T +# endif +# if 2 <= ALTZONE + TZ_TIME_T long altzone; +# endif + #endif /* Initialize *S to a value based on UTOFF, ISDST, and DESIGIDX. */ static void -init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, int desigidx) +init_ttinfo(struct ttinfo *s, int_fast32_t utoff, bool isdst, + desigidx_type desigidx) { s->tt_utoff = utoff; s->tt_isdst = isdst; @@ -302,20 +412,22 @@ detzcode64(const char *const codep) return result; } +#if !USE_TIMEX_T || !defined TM_GMTOFF + static void update_tzname_etc(struct state const *sp, struct ttinfo const *ttisp) { -#if HAVE_TZNAME - tzname[ttisp->tt_isdst] = (char *) &sp->chars[ttisp->tt_desigidx]; -#endif -#if USG_COMPAT +# if HAVE_TZNAME + tzname[ttisp->tt_isdst] = UNCONST(&sp->chars[ttisp->tt_desigidx]); +# endif +# if USG_COMPAT if (!ttisp->tt_isdst) timezone = - ttisp->tt_utoff; -#endif -#if ALTZONE +# endif +# if ALTZONE if (ttisp->tt_isdst) altzone = - ttisp->tt_utoff; -#endif +# endif } /* If STDDST_MASK indicates that SP's TYPE provides useful info, @@ -346,18 +458,18 @@ settzname(void) When STDDST_MASK becomes zero we can stop looking. */ int stddst_mask = 0; -#if HAVE_TZNAME - tzname[0] = tzname[1] = (char *) (sp ? wildabbr : utc); +# if HAVE_TZNAME + tzname[0] = tzname[1] = UNCONST(sp ? wildabbr : utc); stddst_mask = 3; -#endif -#if USG_COMPAT +# endif +# if USG_COMPAT timezone = 0; stddst_mask = 3; -#endif -#if ALTZONE +# endif +# if ALTZONE altzone = 0; stddst_mask |= 2; -#endif +# endif /* ** And to get the latest time zone abbreviations into tzname. . . */ @@ -367,9 +479,9 @@ settzname(void) for (i = sp->typecnt - 1; stddst_mask && 0 <= i; i--) stddst_mask = may_update_tzname_etc(stddst_mask, sp, i); } -#if USG_COMPAT +# if USG_COMPAT daylight = stddst_mask >> 1 ^ 1; -#endif +# endif } /* Replace bogus characters in time zone abbreviations. @@ -396,21 +508,24 @@ scrub_abbrs(struct state *sp) return 0; } +#endif + #ifdef DETECT_TZ_CHANGES /* - * Determine if there's a change in the timezone since the last time we checked. + * Check whether either the time zone name or the file it refers to has + * changed since the last time we checked. * Returns: -1 on error - * 0 if the timezone has not changed - * 1 if the timezone has changed + * 0 if the time zone has not changed + * 1 if the time zone has changed */ static int -change_in_tz(const char *name) +tzfile_changed(const char *name, int fd) { static char old_name[PATH_MAX]; static struct stat old_sb; struct stat sb; - if (stat(name, &sb) != 0) + if (_fstat(fd, &sb) != 0) return -1; if (strcmp(name, old_name) != 0) { @@ -429,9 +544,7 @@ change_in_tz(const char *name) return 0; } -#else /* !DETECT_TZ_CHANGES */ -#define change_in_tz(X) 1 -#endif /* !DETECT_TZ_CHANGES */ +#endif /* DETECT_TZ_CHANGES */ /* Input buffer for data read from a compiled tz file. */ union input_buffer { @@ -444,8 +557,10 @@ union input_buffer { + 4 * TZ_MAX_TIMES]; }; +#ifndef __FreeBSD__ /* TZDIR with a trailing '/' rather than a trailing '\0'. */ static char const tzdirslash[sizeof TZDIR] = TZDIR "/"; +#endif /* !__FreeBSD__ */ /* Local storage needed for 'tzloadbody'. */ union local_storage { @@ -458,6 +573,7 @@ union local_storage { struct state st; } u; +#ifndef __FreeBSD__ /* The name of the file to be opened. Ideally this would have no size limits, to support arbitrarily long Zone names. Limiting Zone names to 1024 bytes should suffice for practical use. @@ -465,19 +581,31 @@ union local_storage { file_analysis as that struct is allocated anyway, as the other union member. */ char fullname[max(sizeof(struct file_analysis), sizeof tzdirslash + 1024)]; +#endif /* !__FreeBSD__ */ }; -/* Load tz data from the file named NAME into *SP. Read extended - format if DOEXTEND. Use *LSP for temporary storage. Return 0 on +/* These tzload flags can be ORed together, and fit into 'char'. */ +enum { TZLOAD_FROMENV = 1 }; /* The TZ string came from the environment. */ +enum { TZLOAD_TZSTRING = 2 }; /* Read any newline-surrounded TZ string. */ + +/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS. + Use *LSP for temporary storage. Return 0 on success, an errno value on failure. */ static int -tzloadbody(char const *name, struct state *sp, bool doextend, +tzloadbody(char const *name, struct state *sp, char tzloadflags, union local_storage *lsp) { register int i; register int fid; register int stored; register ssize_t nread; +#ifdef __FreeBSD__ + struct stat sb; + const char *relname; + int dd, serrno; +#else /* !__FreeBSD__ */ + register bool doaccess; +#endif /* !__FreeBSD__ */ register union input_buffer *up = &lsp->u.u; register int tzheadsize = sizeof(struct tzhead); @@ -491,7 +619,16 @@ tzloadbody(char const *name, struct state *sp, bool doextend, if (name[0] == ':') ++name; - if (name[0] != '/') { +#ifndef __FreeBSD__ +#ifdef SUPPRESS_TZDIR + /* Do not prepend TZDIR. This is intended for specialized + applications only, due to its security implications. */ + doaccess = true; +#else + doaccess = name[0] == '/'; +#endif + if (!doaccess) { + char const *dot; if (sizeof lsp->fullname - sizeof tzdirslash <= strlen(name)) return ENAMETOOLONG; @@ -501,27 +638,89 @@ tzloadbody(char const *name, struct state *sp, bool doextend, memcpy(lsp->fullname, tzdirslash, sizeof tzdirslash); strcpy(lsp->fullname + sizeof tzdirslash, name); + /* Set doaccess if NAME contains a ".." file name + component, as such a name could read a file outside + the TZDIR virtual subtree. */ + for (dot = name; (dot = strchr(dot, '.')); dot++) + if ((dot == name || dot[-1] == '/') && dot[1] == '.' + && (dot[2] == '/' || !dot[2])) { + doaccess = true; + break; + } + name = lsp->fullname; } - if (doextend) { - /* - * Detect if the timezone file has changed. Check - * 'doextend' to ignore TZDEFRULES; the change_in_tz() - * function can only keep state for a single file. - */ - switch (change_in_tz(name)) { - case -1: - return errno; - case 0: - return 0; - case 1: - break; - } + if (doaccess && (tzloadflags & TZLOAD_FROMENV)) { + /* Check for security violations and for devices whose mere + opening could have unwanted side effects. Although these + checks are racy, they're better than nothing and there is + no portable way to fix the races. */ + if (access(name, R_OK) < 0) + return errno; +#ifdef S_ISREG + { + struct stat st; + if (stat(name, &st) < 0) + return errno; + if (!S_ISREG(st.st_mode)) + return EINVAL; + } +#endif + } + fid = _open(name, (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK + | O_IGNORE_CTTY | O_NOCTTY)); +#else /* __FreeBSD__ */ + relname = name; + if (strncmp(relname, TZDIR "/", strlen(TZDIR) + 1) == 0) + relname += strlen(TZDIR) + 1; + dd = _open(TZDIR, O_DIRECTORY | O_RDONLY); + if (issetugid() && (tzloadflags & TZLOAD_FROMENV)) { + if (dd < 0) + return errno; + if (fstatat(dd, name, &sb, AT_RESOLVE_BENEATH) < 0) { + fid = -1; + } else if (!S_ISREG(sb.st_mode)) { + fid = -1; + errno = EINVAL; + } else { + fid = _openat(dd, relname, O_RDONLY | O_BINARY, AT_RESOLVE_BENEATH); + } + } else { + if (dd < 0) { + relname = name; + dd = AT_FDCWD; + } + fid = _openat(dd, relname, O_RDONLY | O_BINARY, 0); } - fid = _open(name, O_RDONLY | O_BINARY); + if (dd != AT_FDCWD && dd >= 0) { + serrno = errno; + _close(dd); + errno = serrno; + } +#endif /* __FreeBSD__ */ if (fid < 0) return errno; +#ifdef DETECT_TZ_CHANGES + if (tzloadflags) { + /* + * Detect if the timezone file has changed. Check tzloadflags + * to ignore TZDEFRULES; the tzfile_changed() function can only + * keep state for a single file. + */ + switch (tzfile_changed(name, fid)) { + case -1: + serrno = errno; + _close(fid); + return serrno; + case 0: + _close(fid); + return 0; + case 1: + break; + } + } +#endif /* DETECT_TZ_CHANGES */ nread = _read(fid, up->buf, sizeof up->buf); if (nread < tzheadsize) { int err = nread < 0 ? errno : EINVAL; @@ -645,7 +844,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, correction must differ from the previous one's by 1 second or less, except that the first correction can be any value; these requirements are more generous than - RFC 8536, to allow future RFC extensions. */ + RFC 9636, to allow future RFC extensions. */ if (! (i == 0 || (prevcorr < corr ? corr == prevcorr + 1 @@ -696,7 +895,7 @@ tzloadbody(char const *name, struct state *sp, bool doextend, if (!version) break; } - if (doextend && nread > 2 && + if ((tzloadflags & TZLOAD_TZSTRING) && nread > 2 && up->buf[0] == '\n' && up->buf[nread - 1] == '\n' && sp->typecnt + 2 <= TZ_MAX_TYPES) { struct state *ts = &lsp->u.st; @@ -771,23 +970,23 @@ tzloadbody(char const *name, struct state *sp, bool doextend, return 0; } -/* Load tz data from the file named NAME into *SP. Read extended - format if DOEXTEND. Return 0 on success, an errno value on failure. */ +/* Load tz data from the file named NAME into *SP. Respect TZLOADFLAGS. + Return 0 on success, an errno value on failure. */ static int -tzload(char const *name, struct state *sp, bool doextend) +tzload(char const *name, struct state *sp, char tzloadflags) { #ifdef ALL_STATE union local_storage *lsp = malloc(sizeof *lsp); if (!lsp) { return HAVE_MALLOC_ERRNO ? errno : ENOMEM; } else { - int err = tzloadbody(name, sp, doextend, lsp); + int err = tzloadbody(name, sp, tzloadflags, lsp); free(lsp); return err; } #else union local_storage ls; - return tzloadbody(name, sp, doextend, &ls); + return tzloadbody(name, sp, tzloadflags, &ls); #endif } @@ -1128,7 +1327,7 @@ tzparse(const char *name, struct state *sp, struct state const *basep) sp->leapcnt = basep->leapcnt; memcpy(sp->lsis, basep->lsis, sp->leapcnt * sizeof *sp->lsis); } else { - load_ok = tzload(TZDEFRULES, sp, false) == 0; + load_ok = tzload(TZDEFRULES, sp, 0) == 0; if (!load_ok) sp->leapcnt = 0; /* So, we're off a little. */ } @@ -1365,13 +1564,16 @@ tzparse(const char *name, struct state *sp, struct state const *basep) static void gmtload(struct state *const sp) { - if (tzload(etc_utc, sp, true) != 0) + if (tzload(etc_utc, sp, TZLOAD_TZSTRING) != 0) tzparse("UTC0", sp, NULL); } #ifdef DETECT_TZ_CHANGES +/* + * Check if the time zone data we have is still fresh. + */ static int -recheck_tzdata() +tzdata_is_fresh(void) { static time_t last_checked; struct timespec now; @@ -1387,14 +1589,15 @@ recheck_tzdata() return 0; } -#else /* !DETECT_TZ_CHANGES */ -#define recheck_tzdata() 0 -#endif /* !DETECT_TZ_CHANGES */ +#endif /* DETECT_TZ_CHANGES */ + +#if !USE_TIMEX_T || !defined TM_GMTOFF /* Initialize *SP to a value appropriate for the TZ setting NAME. + Respect TZLOADFLAGS. Return 0 on success, an errno value on failure. */ static int -zoneinit(struct state *sp, char const *name) +zoneinit(struct state *sp, char const *name, char tzloadflags) { if (name && ! name[0]) { /* @@ -1409,7 +1612,7 @@ zoneinit(struct state *sp, char const *name) strcpy(sp->chars, utc); return 0; } else { - int err = tzload(name, sp, true); + int err = tzload(name, sp, tzloadflags); if (err != 0 && name && name[0] != ':' && tzparse(name, sp, NULL)) err = 0; if (err == 0) @@ -1419,22 +1622,35 @@ zoneinit(struct state *sp, char const *name) } static void +tzset_unlocked(void) +{ +#ifdef __FreeBSD__ + tzset_unlocked_name(getenv("TZ")); +} +static void tzset_unlocked_name(char const *name) { +#else + char const *name = getenv("TZ"); +#endif struct state *sp = lclptr; int lcl = name ? strlen(name) < sizeof lcl_TZname : -1; if (lcl < 0 ? lcl_is_set < 0 : 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0) - if (recheck_tzdata() == 0) - return; -#ifdef ALL_STATE +#ifdef DETECT_TZ_CHANGES + if (tzdata_is_fresh() == 0) +#endif /* DETECT_TZ_CHANGES */ + return; +# ifdef ALL_STATE if (! sp) lclptr = sp = malloc(sizeof *lclptr); -#endif /* defined ALL_STATE */ +# endif if (sp) { - if (zoneinit(sp, name) != 0) - zoneinit(sp, ""); + if (zoneinit(sp, name, TZLOAD_FROMENV | TZLOAD_TZSTRING) != 0) { + zoneinit(sp, "", 0); + strcpy(sp->chars, UNSPEC); + } if (0 < lcl) strcpy(lcl_TZname, name); } @@ -1442,12 +1658,9 @@ tzset_unlocked_name(char const *name) lcl_is_set = lcl; } -static void -tzset_unlocked(void) -{ - tzset_unlocked_name(getenv("TZ")); -} +#endif +#if !USE_TIMEX_T void tzset(void) { @@ -1456,7 +1669,9 @@ tzset(void) tzset_unlocked(); unlock(); } +#endif +#ifdef __FreeBSD__ void freebsd13_tzsetwall(void) { @@ -1468,7 +1683,7 @@ freebsd13_tzsetwall(void) __sym_compat(tzsetwall, freebsd13_tzsetwall, FBSD_1.0); __warn_references(tzsetwall, "warning: tzsetwall() is deprecated, use tzset() instead."); - +#endif /* __FreeBSD__ */ static void gmtcheck(void) { @@ -1485,15 +1700,18 @@ gmtcheck(void) } unlock(); } +#ifdef __FreeBSD__ +#define gmtcheck() _once(&gmt_once, gmtcheck) +#endif -#if NETBSD_INSPIRED +#if NETBSD_INSPIRED && !USE_TIMEX_T timezone_t tzalloc(char const *name) { timezone_t sp = malloc(sizeof *sp); if (sp) { - int err = zoneinit(sp, name); + int err = zoneinit(sp, name, TZLOAD_TZSTRING); if (err != 0) { free(sp); errno = err; @@ -1522,6 +1740,8 @@ tzfree(timezone_t sp) #endif +#if !USE_TIMEX_T || !defined TM_GMTOFF + /* ** The easy way to behave "as if no library function calls" localtime ** is to not call it, so we drop its guts into "localsub", which can be @@ -1576,14 +1796,14 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, return NULL; /* "cannot happen" */ result = localsub(sp, &newt, setname, tmp); if (result) { -#if defined ckd_add && defined ckd_sub +# if defined ckd_add && defined ckd_sub if (t < sp->ats[0] ? ckd_sub(&result->tm_year, result->tm_year, years) : ckd_add(&result->tm_year, result->tm_year, years)) return NULL; -#else +# else register int_fast64_t newy; newy = result->tm_year; @@ -1593,7 +1813,7 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, if (! (INT_MIN <= newy && newy <= INT_MAX)) return NULL; result->tm_year = newy; -#endif +# endif } return result; } @@ -1622,25 +1842,26 @@ localsub(struct state const *sp, time_t const *timep, int_fast32_t setname, result = timesub(&t, ttisp->tt_utoff, sp, tmp); if (result) { result->tm_isdst = ttisp->tt_isdst; -#ifdef TM_ZONE - result->TM_ZONE = (char *) &sp->chars[ttisp->tt_desigidx]; -#endif /* defined TM_ZONE */ +# ifdef TM_ZONE + result->TM_ZONE = UNCONST(&sp->chars[ttisp->tt_desigidx]); +# endif if (setname) update_tzname_etc(sp, ttisp); } return result; } +#endif -#if NETBSD_INSPIRED +#if !USE_TIMEX_T +# if NETBSD_INSPIRED struct tm * localtime_rz(struct state *restrict sp, time_t const *restrict timep, struct tm *restrict tmp) { return localsub(sp, timep, 0, tmp); } - -#endif +# endif static struct tm * localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) @@ -1652,45 +1873,47 @@ localtime_tzset(time_t const *timep, struct tm *tmp, bool setname) } #ifndef DETECT_TZ_CHANGES if (setname || !lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); tmp = localsub(lclptr, timep, setname, tmp); unlock(); return tmp; } +#ifdef __FreeBSD__ static void localtime_key_init(void) { - - localtime_key_error = _pthread_key_create(&localtime_key, free); + localtime_key_error = _pthread_key_create(&localtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * localtime(const time_t *timep) { -#if !SUPPORT_C89 - static struct tm tm; -#endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&localtime_once, localtime_key_init); - if (localtime_key_error != 0) { - errno = localtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(localtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return localtime_tzset(timep, p_tm, true); +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&localtime_once, localtime_key_init); + if (localtime_key_error != 0) { + errno = localtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(localtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(localtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } +#endif /* __FreeBSD__ */ + return localtime_tzset(timep, p_tm, true); } struct tm * @@ -1698,6 +1921,7 @@ localtime_r(const time_t *restrict timep, struct tm *restrict tmp) { return localtime_tzset(timep, tmp, false); } +#endif /* ** gmtsub is to gmtime as localsub is to localtime. @@ -1716,12 +1940,14 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, ** "+xx" or "-xx" if offset is non-zero, ** but this is no time for a treasure hunt. */ - tmp->TM_ZONE = ((char *) - (offset ? wildabbr : gmtptr ? gmtptr->chars : utc)); + tmp->TM_ZONE = UNCONST(offset ? wildabbr + : gmtptr ? gmtptr->chars : utc); #endif /* defined TM_ZONE */ return result; } +#if !USE_TIMEX_T + /* * Re-entrant version of gmtime. */ @@ -1729,45 +1955,47 @@ gmtsub(ATTRIBUTE_MAYBE_UNUSED struct state const *sp, time_t const *timep, struct tm * gmtime_r(time_t const *restrict timep, struct tm *restrict tmp) { - _once(&gmt_once, gmtcheck); - return gmtsub(gmtptr, timep, 0, tmp); + gmtcheck(); + return gmtsub(gmtptr, timep, 0, tmp); } +#ifdef __FreeBSD__ static void gmtime_key_init(void) { - - gmtime_key_error = _pthread_key_create(&gmtime_key, free); + gmtime_key_error = _pthread_key_create(&gmtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * gmtime(const time_t *timep) { -#if !SUPPORT_C89 - static struct tm tm; -#endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&gmtime_once, gmtime_key_init); - if (gmtime_key_error != 0) { - errno = gmtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(gmtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return gmtime_r(timep, p_tm); +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&gmtime_once, gmtime_key_init); + if (gmtime_key_error != 0) { + errno = gmtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(gmtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(gmtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } +#endif /* __FreeBSD__ */ + return gmtime_r(timep, p_tm); } -#if STD_INSPIRED +# if STD_INSPIRED /* This function is obsolescent and may disappear in future releases. Callers can instead use localtime_rz with a fixed-offset zone. */ @@ -1775,44 +2003,47 @@ gmtime(const time_t *timep) struct tm * offtime_r(time_t const *restrict timep, long offset, struct tm *restrict tmp) { - _once(&gmt_once, gmtcheck); - return gmtsub(gmtptr, timep, offset, tmp); + gmtcheck(); + return gmtsub(gmtptr, timep, offset, tmp); } +#ifdef __FreeBSD__ static void offtime_key_init(void) { - - offtime_key_error = _pthread_key_create(&offtime_key, free); + offtime_key_error = _pthread_key_create(&offtime_key, free); } - +#endif /* __FreeBSD__ */ struct tm * offtime(const time_t *timep, long offset) { -#if !SUPPORT_C89 - static struct tm tm; +# if !SUPPORT_C89 + static struct tm tm; +# endif +#ifdef __FreeBSD__ + struct tm *p_tm = &tm; + + if (__isthreaded != 0) { + _pthread_once(&offtime_once, offtime_key_init); + if (offtime_key_error != 0) { + errno = offtime_key_error; + return (NULL); + } + if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) { + if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { + return (NULL); + } + if (_pthread_setspecific(offtime_key, p_tm) != 0) { + free(p_tm); + return (NULL); + } + } + } #endif - struct tm *p_tm = &tm; - - if (__isthreaded != 0) { - _pthread_once(&offtime_once, offtime_key_init); - if (offtime_key_error != 0) { - errno = offtime_key_error; - return (NULL); - } - if ((p_tm = _pthread_getspecific(offtime_key)) == NULL) { - if ((p_tm = malloc(sizeof(*p_tm))) == NULL) { - return (NULL); - } - if (_pthread_setspecific(offtime_key, p_tm) != 0) { - free(p_tm); - return (NULL); - } - } - } - return offtime_r(timep, offset, p_tm); + return offtime_r(timep, offset, p_tm); } +# endif #endif /* @@ -1871,7 +2102,7 @@ timesub(const time_t *timep, int_fast32_t offset, dayoff = offset / SECSPERDAY - corr / SECSPERDAY + rem / SECSPERDAY - 3; rem %= SECSPERDAY; /* y = (EPOCH_YEAR - + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), + + floor((tdays + dayoff) / DAYSPERREPEAT) * YEARSPERREPEAT), sans overflow. But calculate against 1570 (EPOCH_YEAR - YEARSPERREPEAT) instead of against 1970 so that things work for localtime values before 1970 when time_t is unsigned. */ @@ -1988,17 +2219,17 @@ increment_overflow(int *ip, int j) } static bool -increment_overflow32(int_fast32_t *const lp, int const m) +increment_overflow_time_iinntt(time_t *tp, iinntt j) { #ifdef ckd_add - return ckd_add(lp, *lp, m); + return ckd_add(tp, *tp, j); #else - register int_fast32_t const l = *lp; - - if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) - return true; - *lp += m; - return false; + if (j < 0 + ? (TYPE_SIGNED(time_t) ? *tp < TIME_T_MIN - j : *tp <= -1 - j) + : TIME_T_MAX - j < *tp) + return true; + *tp += j; + return false; #endif } @@ -2022,30 +2253,6 @@ increment_overflow_time(time_t *tp, int_fast32_t j) #endif } -static bool -normalize_overflow(int *const tensptr, int *const unitsptr, const int base) -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow(tensptr, tensdelta); -} - -static bool -normalize_overflow32(int_fast32_t *tensptr, int *unitsptr, int base) -{ - register int tensdelta; - - tensdelta = (*unitsptr >= 0) ? - (*unitsptr / base) : - (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow32(tensptr, tensdelta); -} - static int tmcomp(register const struct tm *const atmp, register const struct tm *const btmp) @@ -2090,11 +2297,9 @@ time2sub(struct tm *const tmp, { register int dir; register int i, j; - register int saved_seconds; - register int_fast32_t li; register time_t lo; register time_t hi; - int_fast32_t y; + iinntt y, mday, hour, min, saved_seconds; time_t newt; time_t t; struct tm yourtm, mytm; @@ -2102,36 +2307,57 @@ time2sub(struct tm *const tmp, *okayp = false; mktmcpy(&yourtm, tmp); + min = yourtm.tm_min; if (do_norm_secs) { - if (normalize_overflow(&yourtm.tm_min, &yourtm.tm_sec, - SECSPERMIN)) - return WRONG; + min += yourtm.tm_sec / SECSPERMIN; + yourtm.tm_sec %= SECSPERMIN; + if (yourtm.tm_sec < 0) { + yourtm.tm_sec += SECSPERMIN; + min--; + } } - if (normalize_overflow(&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow(&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; + + hour = yourtm.tm_hour; + hour += min / MINSPERHOUR; + yourtm.tm_min = min % MINSPERHOUR; + if (yourtm.tm_min < 0) { + yourtm.tm_min += MINSPERHOUR; + hour--; + } + + mday = yourtm.tm_mday; + mday += hour / HOURSPERDAY; + yourtm.tm_hour = hour % HOURSPERDAY; + if (yourtm.tm_hour < 0) { + yourtm.tm_hour += HOURSPERDAY; + mday--; + } + y = yourtm.tm_year; - if (normalize_overflow32(&y, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; + y += yourtm.tm_mon / MONSPERYEAR; + yourtm.tm_mon %= MONSPERYEAR; + if (yourtm.tm_mon < 0) { + yourtm.tm_mon += MONSPERYEAR; + y--; + } + /* ** Turn y into an actual year number for now. ** It is converted back to an offset from TM_YEAR_BASE later. */ - if (increment_overflow32(&y, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (increment_overflow32(&y, -1)) - return WRONG; - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap(li)]; + y += TM_YEAR_BASE; + + while (mday <= 0) { + iinntt li = y - (yourtm.tm_mon <= 1); + mday += year_lengths[isleap(li)]; + y--; } - while (yourtm.tm_mday > DAYSPERLYEAR) { - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap(li)]; - if (increment_overflow32(&y, 1)) - return WRONG; + while (DAYSPERLYEAR < mday) { + iinntt li = y + (1 < yourtm.tm_mon); + mday -= year_lengths[isleap(li)]; + y++; } + yourtm.tm_mday = mday; for ( ; ; ) { i = mon_lengths[isleap(y)][yourtm.tm_mon]; if (yourtm.tm_mday <= i) @@ -2139,16 +2365,14 @@ time2sub(struct tm *const tmp, yourtm.tm_mday -= i; if (++yourtm.tm_mon >= MONSPERYEAR) { yourtm.tm_mon = 0; - if (increment_overflow32(&y, 1)) - return WRONG; + y++; } } #ifdef ckd_add if (ckd_add(&yourtm.tm_year, y, -TM_YEAR_BASE)) return WRONG; #else - if (increment_overflow32(&y, -TM_YEAR_BASE)) - return WRONG; + y -= TM_YEAR_BASE; if (! (INT_MIN <= y && y <= INT_MAX)) return WRONG; yourtm.tm_year = y; @@ -2164,9 +2388,8 @@ time2sub(struct tm *const tmp, ** not in the same minute that a leap second was deleted from, ** which is a safer assumption than using 58 would be. */ - if (increment_overflow(&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; saved_seconds = yourtm.tm_sec; + saved_seconds -= SECSPERMIN - 1; yourtm.tm_sec = SECSPERMIN - 1; } else { saved_seconds = yourtm.tm_sec; @@ -2275,10 +2498,8 @@ time2sub(struct tm *const tmp, return WRONG; } label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) + if (increment_overflow_time_iinntt(&t, saved_seconds)) return WRONG; - t = newt; if (funcp(sp, &t, offset, tmp)) *okayp = true; return t; @@ -2323,7 +2544,6 @@ time1(struct tm *const tmp, errno = EINVAL; return WRONG; } - if (tmp->tm_isdst > 1) tmp->tm_isdst = 1; t = time2(tmp, funcp, sp, offset, &okay); @@ -2376,27 +2596,22 @@ time1(struct tm *const tmp, return WRONG; } +#if !defined TM_GMTOFF || !USE_TIMEX_T + static time_t mktime_tzname(struct state *sp, struct tm *tmp, bool setname) { if (sp) return time1(tmp, localsub, sp, setname); else { - _once(&gmt_once, gmtcheck); + gmtcheck(); return time1(tmp, gmtsub, gmtptr, 0); } } -#if NETBSD_INSPIRED - -time_t -mktime_z(struct state *restrict sp, struct tm *restrict tmp) -{ - return mktime_tzname(sp, tmp, false); -} - -#endif - +# if USE_TIMEX_T +static +# endif time_t mktime(struct tm *tmp) { @@ -2412,7 +2627,17 @@ mktime(struct tm *tmp) return t; } -#if STD_INSPIRED +#endif + +#if NETBSD_INSPIRED && !USE_TIMEX_T +time_t +mktime_z(struct state *restrict sp, struct tm *restrict tmp) +{ + return mktime_tzname(sp, tmp, false); +} +#endif + +#if STD_INSPIRED && !USE_TIMEX_T /* This function is obsolescent and may disappear in future releases. Callers can instead use mktime. */ time_t @@ -2424,12 +2649,14 @@ timelocal(struct tm *tmp) } #endif -#ifndef EXTERN_TIMEOFF -# ifndef timeoff -# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */ +#if defined TM_GMTOFF || !USE_TIMEX_T + +# ifndef EXTERN_TIMEOFF +# ifndef timeoff +# define timeoff my_timeoff /* Don't collide with OpenBSD 7.4 <time.h>. */ +# endif +# define EXTERN_TIMEOFF static # endif -# define EXTERN_TIMEOFF static -#endif /* This function is obsolescent and may disappear in future releases. Callers can instead use mktime_z with a fixed-offset zone. */ @@ -2438,10 +2665,12 @@ timeoff(struct tm *tmp, long offset) { if (tmp) tmp->tm_isdst = 0; - _once(&gmt_once, gmtcheck); + gmtcheck(); return time1(tmp, gmtsub, gmtptr, offset); } +#endif +#if !USE_TIMEX_T time_t timegm(struct tm *tmp) { @@ -2454,6 +2683,7 @@ timegm(struct tm *tmp) *tmp = tmcpy; return t; } +#endif static int_fast32_t leapcorr(struct state const *sp, time_t t) @@ -2474,15 +2704,16 @@ leapcorr(struct state const *sp, time_t t) ** XXX--is the below the right way to conditionalize?? */ -#if STD_INSPIRED +#if !USE_TIMEX_T +# if STD_INSPIRED /* NETBSD_INSPIRED_EXTERN functions are exported to callers if NETBSD_INSPIRED is defined, and are private otherwise. */ -# if NETBSD_INSPIRED -# define NETBSD_INSPIRED_EXTERN -# else -# define NETBSD_INSPIRED_EXTERN static -# endif +# if NETBSD_INSPIRED +# define NETBSD_INSPIRED_EXTERN +# else +# define NETBSD_INSPIRED_EXTERN static +# endif /* ** IEEE Std 1003.1 (POSIX) says that 536457599 @@ -2508,7 +2739,7 @@ time2posix(time_t t) } #ifndef DETECT_TZ_CHANGES if (!lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); if (lclptr) t = time2posix_z(lclptr, t); @@ -2555,7 +2786,7 @@ posix2time(time_t t) } #ifndef DETECT_TZ_CHANGES if (!lcl_is_set) -#endif +#endif /* DETECT_TZ_CHANGES */ tzset_unlocked(); if (lclptr) t = posix2time_z(lclptr, t); @@ -2563,17 +2794,13 @@ posix2time(time_t t) return t; } -#endif /* STD_INSPIRED */ +# endif /* STD_INSPIRED */ -#if TZ_TIME_T +# if TZ_TIME_T -# if !USG_COMPAT -# define daylight 0 -# define timezone 0 -# endif -# if !ALTZONE -# define altzone 0 -# endif +# if !USG_COMPAT +# define timezone 0 +# endif /* Convert from the underlying system's time_t to the ersatz time_tz, which is called 'time_t' in this file. Typically, this merely @@ -2591,9 +2818,9 @@ time(time_t *p) { time_t r = sys_time(0); if (r != (time_t) -1) { - int_fast32_t offset = EPOCH_LOCAL ? (daylight ? timezone : altzone) : 0; - if (increment_overflow32(&offset, -EPOCH_OFFSET) - || increment_overflow_time(&r, offset)) { + iinntt offset = EPOCH_LOCAL ? timezone : 0; + if (offset < IINNTT_MIN + EPOCH_OFFSET + || increment_overflow_time_iinntt(&r, offset - EPOCH_OFFSET)) { errno = EOVERFLOW; r = -1; } @@ -2603,4 +2830,5 @@ time(time_t *p) return r; } +# endif #endif diff --git a/contrib/tzcode/newctime.3 b/contrib/tzcode/newctime.3 index d19fd25b7926..9d09e5a55bd9 100644 --- a/contrib/tzcode/newctime.3 +++ b/contrib/tzcode/newctime.3 @@ -5,43 +5,34 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP -.B [[deprecated]] char *ctime(time_t const *clock); -.PP -/* Only in POSIX.1-2017 and earlier. */ -.B char *ctime_r(time_t const *clock, char *buf); -.PP -.B double difftime(time_t time1, time_t time0); -.PP -.B [[deprecated]] char *asctime(struct tm const *tm); -.PP -/* Only in POSIX.1-2017 and earlier. */ -.B "char *asctime_r(struct tm const *restrict tm," -.B " char *restrict result);" -.PP .B struct tm *localtime(time_t const *clock); -.PP .B "struct tm *localtime_r(time_t const *restrict clock," .B " struct tm *restrict result);" -.PP .B "struct tm *localtime_rz(timezone_t restrict zone," .B " time_t const *restrict clock," .B " struct tm *restrict result);" .PP .B struct tm *gmtime(time_t const *clock); -.PP .B "struct tm *gmtime_r(time_t const *restrict clock," .B " struct tm *restrict result);" .PP .B time_t mktime(struct tm *tm); -.PP .B "time_t mktime_z(timezone_t restrict zone," .B " struct tm *restrict tm);" .PP -.B cc ... \*-ltz +.B double difftime(time_t time1, time_t time0); +.PP +.B [[deprecated]] char *asctime(struct tm const *tm); +.B [[deprecated]] char *ctime(time_t const *clock); +.PP +/* Only in POSIX.1-2017 and earlier. */ +.B char *ctime_r(time_t const *clock, char *buf); +.B "char *asctime_r(struct tm const *restrict tm," +.B " char *restrict result);" +.PP +.B cc ... \-ltz .fi .SH DESCRIPTION .ie '\(en'' .ds en \- @@ -54,82 +45,37 @@ asctime, ctime, difftime, gmtime, localtime, mktime \- convert date and time \\$3\*(lq\\$1\*(rq\\$2 .. The -.B ctime -function -converts a long integer, pointed to by -.IR clock , -and returns a pointer to a -string of the form -.br -.ce -.eo -Thu Nov 24 18:22:48 1986\n\0 -.br -.ec -Years requiring fewer than four characters are padded with leading zeroes. -For years longer than four characters, the string is of the form -.br -.ce -.eo -Thu Nov 24 18:22:48 81986\n\0 -.ec -.br -with five spaces before the year. -These unusual formats are designed to make it less likely that older -software that expects exactly 26 bytes of output will mistakenly output -misleading values for out-of-range years. -.PP -The -.BI * clock -timestamp represents the time in seconds since 1970-01-01 00:00:00 -Coordinated Universal Time (UTC). -The POSIX standard says that timestamps must be nonnegative -and must ignore leap seconds. -Many implementations extend POSIX by allowing negative timestamps, -and can therefore represent timestamps that predate the -introduction of UTC and are some other flavor of Universal Time (UT). -Some implementations support leap seconds, in contradiction to POSIX. -.PP -The -.B ctime -function is deprecated starting in C23. -Callers can use -.B localtime_r -and -.B strftime -instead. -.PP -The .B localtime and .B gmtime functions +convert an integer, pointed to by +.IR clock , +and return pointers to .q "tm" structures, described below. +If the integer is out of range for conversion, +these functions return a null pointer. The .B localtime function corrects for the time zone and any time zone adjustments (such as Daylight Saving Time in the United States). -.PP The .B gmtime -function -converts to Coordinated Universal Time. +function converts to Coordinated Universal Time. .PP The -.B asctime -function -converts a time value contained in a -.q "tm" -structure to a string, -as shown in the above example, -and returns a pointer to the string. -This function is deprecated starting in C23. -Callers can use -.B strftime -instead. +.BI * clock +timestamp represents the time in seconds since 1970-01-01 00:00:00 +Coordinated Universal Time (UTC). +The POSIX standard says that timestamps must be nonnegative +and must ignore leap seconds. +Many implementations extend POSIX by allowing negative timestamps, +and can therefore represent timestamps that predate the +introduction of UTC and are some other flavor of Universal Time (UT). +Some implementations support leap seconds, in contradiction to POSIX. .PP The .B mktime @@ -204,6 +150,52 @@ returns the difference between two calendar times, expressed in seconds. .PP The +.B asctime +function +converts a time value contained in a +.q "tm" +structure to a pointer to a +string of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 1986\n\0 +.br +.ec +Years requiring fewer than four characters are padded with leading zeroes. +For years longer than four characters, the string is of the form +.br +.ce +.eo +Thu Nov 24 18:22:48 81986\n\0 +.ec +.br +with five spaces before the year. +This unusual format is designed to make it less likely that older +software that expects exactly 26 bytes of output will mistakenly output +misleading values for out-of-range years. +This function is deprecated starting in C23. +Callers can use +.B strftime +instead. +.PP +The +.B ctime +function is equivalent to calliing +.B localtime +and then calling +.B asctime +on the result. +Like +.BR asctime , +this function is deprecated starting in C23. +Callers can use +.B localtime +and +.B strftime +instead. +.PP +The .BR ctime_r , .BR localtime_r , .BR gmtime_r , diff --git a/contrib/tzcode/newstrftime.3 b/contrib/tzcode/newstrftime.3 index a9997a092d0a..e9a382240ed2 100644 --- a/contrib/tzcode/newstrftime.3 +++ b/contrib/tzcode/newstrftime.3 @@ -40,8 +40,6 @@ strftime \- format date and time .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP .B "size_t strftime(char *restrict buf, size_t maxsize," @@ -93,7 +91,7 @@ If a bracketed member name is followed by .B strftime can use the named member even though POSIX.1-2024 does not list it; if the name is followed by -.q \*- , +.q \- , .B strftime ignores the member even though POSIX.1-2024 lists it which means portable code should set it. @@ -139,11 +137,14 @@ is replaced by the locale's appropriate date and time representation. .IR tm_sec , .IR tm_gmtoff , .IR tm_zone , -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %D is equivalent to .c %m/%d/%y . +Although used in the United States for current dates, +this format is ambiguous elsewhere +and for dates that might involve other centuries. .RI [ tm_year , .IR tm_mon , .IR tm_mday ] @@ -167,6 +168,8 @@ is equivalent to .TP %G is replaced by the ISO 8601 year with century as a decimal number. +This is the year that includes the greater part of the week. +(Monday as the first day of a week). See also the .c %V conversion specification. @@ -176,11 +179,7 @@ conversion specification. .TP %g is replaced by the ISO 8601 year without century as a decimal number [00,99]. -This is the year that includes the greater part of the week. -(Monday as the first day of a week). -See also the -.c %V -conversion specification. +Since it omits the century, it is ambiguous for dates. .RI [ tm_year , .IR tm_yday , .IR tm_wday ] @@ -249,9 +248,22 @@ of leap seconds. is replaced by the number of seconds since the Epoch (see .BR ctime (3)). Although %s is reliable in this implementation, -it can have glitches on other platforms (notably platforms lacking -.IR tm_gmtoff ), -so portable code should format a +it can have glitches on other platforms +(notably obsolescent platforms lacking +.I tm_gmtoff +or where +.B time_t +is no wider than int), and POSIX allows +.B strftime +to set +.B errno +to +.B EINVAL +or +.B EOVERFLOW +and return 0 if the number of seconds would be negative or out of range for +.BR time_t . +Portable code should therefore format a .B time_t value directly via something like .B sprintf @@ -267,7 +279,7 @@ with "%s". .IR tm_min , .IR tm_sec , .IR tm_gmtoff +, -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %T is replaced by the time in the format @@ -284,7 +296,7 @@ is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. .RI [ tm_wday , .IR tm_yday , -.IR tm_year \*-] +.IR tm_year \-] .TP %u is replaced by the weekday (Monday as the first day of the week) @@ -318,31 +330,33 @@ as a decimal number [0,6]. .TP %X is replaced by the locale's appropriate time representation. -.RI [ tm_year \*-, -.IR tm_yday \*-, -.IR tm_mon \*-, -.IR tm_mday \*-, -.IR tm_wday \*-, +.RI [ tm_year \-, +.IR tm_yday \-, +.IR tm_mon \-, +.IR tm_mday \-, +.IR tm_wday \-, .IR tm_hour , .IR tm_min , .IR tm_sec , .IR tm_gmtoff , .IR tm_zone , -.IR tm_isdst \*-]. +.IR tm_isdst \-]. .TP %x is replaced by the locale's appropriate date representation. +This format can be ambiguous for dates, e.g., +it can generate "01/02/03" in the C locale. .RI [ tm_year , .IR tm_yday , .IR tm_mon , .IR tm_mday , .IR tm_wday , -.IR tm_hour \*-, -.IR tm_min \*-, -.IR tm_sec \*-, -.IR tm_gmtoff \*-, -.IR tm_zone \*-, -.IR tm_isdst \*-]. +.IR tm_hour \-, +.IR tm_min \-, +.IR tm_sec \-, +.IR tm_gmtoff \-, +.IR tm_zone \-, +.IR tm_isdst \-]. .TP %Y is replaced by the year with century as a decimal number. @@ -350,28 +364,29 @@ is replaced by the year with century as a decimal number. .TP %y is replaced by the year without century as a decimal number [00,99]. +Since it omits the century, it is ambiguous for dates. .RI [ tm_year ] .TP %Z is replaced by the time zone abbreviation, or by the empty string if this is not determinable. .RI [ tm_zone , -.IR tm_isdst \*-] +.IR tm_isdst \-] .TP %z is replaced by the offset from the Prime Meridian -in the format +HHMM or \*-HHMM (ISO 8601) as appropriate, +in the format +HHMM or \-HHMM (ISO 8601) as appropriate, with positive values representing locations east of Greenwich, or by the empty string if this is not determinable. -The numeric time zone abbreviation \*-0000 is used when the time is +The numeric time zone abbreviation \-0000 is used when the time is Universal Time but local time is indeterminate; by convention this is used for locations while uninhabited, and corresponds to a zero offset when the time zone abbreviation begins with -.q "\*-" . +.q "\-" . .RI [ tm_gmtoff , .IR tm_zone +, -.IR tm_isdst \*-] +.IR tm_isdst \-] .TP %% is replaced by a single %. @@ -418,15 +433,6 @@ This function fails if: The total number of resulting bytes, including the terminating NUL character, is more than .IR maxsize . -.PP -This function may fail if: -.TP -[EOVERFLOW] -The format includes an -.c %s -conversion and the number of seconds since the Epoch cannot be represented -in a -.c time_t . .SH SEE ALSO .BR date (1), .BR getenv (3), diff --git a/contrib/tzcode/newtzset.3 b/contrib/tzcode/newtzset.3 index 661fb25be098..db6bfa7fa64c 100644 --- a/contrib/tzcode/newtzset.3 +++ b/contrib/tzcode/newtzset.3 @@ -5,8 +5,6 @@ tzset \- initialize time conversion information .SH SYNOPSIS .nf -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .B #include <time.h> .PP .BI "timezone_t tzalloc(char const *" TZ ); @@ -23,7 +21,7 @@ tzset \- initialize time conversion information .br .B extern int daylight; .PP -.B cc ... \*-ltz +.B cc ... \-ltz .fi .SH DESCRIPTION .ie '\(en'' .ds en \- @@ -110,7 +108,7 @@ except a leading colon digits, comma .RB ( , ), ASCII minus -.RB ( \*- ), +.RB ( \- ), ASCII plus .RB ( + ), and NUL bytes are allowed. @@ -150,7 +148,7 @@ daylight saving time is assumed to be one hour ahead of standard time. One or more digits may be used; the value is always interpreted as a decimal number. The hour must be between zero and 24, and the minutes (and seconds) \*(en if present \*(en between zero and 59. If preceded by a -.q "\*-" , +.q "\-" , the time zone shall be east of the Prime Meridian; otherwise it shall be west (which may be indicated by an optional preceding .q "+" . @@ -239,7 +237,7 @@ values that directly specify the timezone. stands for US Eastern Standard Time (EST), 5 hours behind UT, without daylight saving. .TP -.B <+12>\*-12<+13>,M11.1.0,M1.2.1/147 +.B <+12>\-12<+13>,M11.1.0,M1.2.1/147 stands for Fiji time, 12 hours ahead of UT, springing forward on November's first Sunday at 02:00, and falling back on January's second Monday at 147:00 (i.e., 03:00 on the @@ -249,34 +247,34 @@ and daylight saving time are and .q "+13". .TP -.B IST\*-2IDT,M3.4.4/26,M10.5.0 +.B IST\-2IDT,M3.4.4/26,M10.5.0 stands for Israel Standard Time (IST) and Israel Daylight Time (IDT), 2 hours ahead of UT, springing forward on March's fourth Thursday at 26:00 (i.e., 02:00 on the first Friday on or after March 23), and falling back on October's last Sunday at 02:00. .TP -.B <\*-04>4<\*-03>,J1/0,J365/25 +.B <\-04>4<\-03>,J1/0,J365/25 stands for permanent daylight saving time, 3 hours behind UT with abbreviation -.q "\*-03". +.q "\-03". There is a dummy fall-back transition on December 31 at 25:00 daylight saving time (i.e., 24:00 standard time, equivalent to January 1 at 00:00 standard time), and a simultaneous spring-forward transition on January 1 at 00:00 standard time, so daylight saving time is in effect all year and the initial -.B <\*-04> +.B <\-04> is a placeholder. .TP -.B <\*-03>3<\*-02>,M3.5.0/\*-2,M10.5.0/\*-1 +.B <\-03>3<\-02>,M3.5.0/\-2,M10.5.0/\-1 stands for time in western Greenland, 3 hours behind UT, where clocks follow the EU rules of springing forward on March's last Sunday at 01:00 UT (\-02:00 local time, i.e., 22:00 the previous day) and falling back on October's last Sunday at 01:00 UT (\-01:00 local time, i.e., 23:00 the previous day). The abbreviations for standard and daylight saving time are -.q "\*-03" +.q "\-03" and -.q "\*-02". +.q "\-02". .PP If .I TZ diff --git a/contrib/tzcode/private.h b/contrib/tzcode/private.h index 9c5edff252fd..532d9ddc81c8 100644 --- a/contrib/tzcode/private.h +++ b/contrib/tzcode/private.h @@ -37,6 +37,38 @@ # define SUPPORT_C89 1 #endif + +/* The following feature-test macros should be defined before + any #include of a system header. */ + +/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */ +#define _GNU_SOURCE 1 +/* Fix asctime_r on Solaris 11. */ +#define _POSIX_PTHREAD_SEMANTICS 1 +/* Enable strtoimax on pre-C99 Solaris 11. */ +#define __EXTENSIONS__ 1 +/* Cause MS-Windows headers to define POSIX names. */ +#define _CRT_DECLARE_NONSTDC_NAMES 1 +/* Prevent MS-Windows headers from defining min and max. */ +#define NOMINMAX 1 + +/* On GNUish systems where time_t might be 32 or 64 bits, use 64. + On these platforms _FILE_OFFSET_BITS must also be 64; otherwise + setting _TIME_BITS to 64 does not work. The code does not + otherwise rely on _FILE_OFFSET_BITS being 64, since it does not + use off_t or functions like 'stat' that depend on off_t. */ +#ifndef _TIME_BITS +# ifndef _FILE_OFFSET_BITS +# define _FILE_OFFSET_BITS 64 +# endif +# if _FILE_OFFSET_BITS == 64 +# define _TIME_BITS 64 +# endif +#endif + +/* End of feature-test macro definitions. */ + + #ifndef __STDC_VERSION__ # define __STDC_VERSION__ 0 #endif @@ -51,6 +83,7 @@ #endif #if __STDC_VERSION__ < 202311 +# undef static_assert # define static_assert(cond) extern int static_assert_check[(cond) ? 1 : -1] #endif @@ -87,11 +120,11 @@ #if !defined HAVE_GETTEXT && defined __has_include # if __has_include(<libintl.h>) -# define HAVE_GETTEXT true +# define HAVE_GETTEXT 1 # endif #endif #ifndef HAVE_GETTEXT -# define HAVE_GETTEXT false +# define HAVE_GETTEXT 0 #endif #ifndef HAVE_INCOMPATIBLE_CTIME_R @@ -124,20 +157,20 @@ #if !defined HAVE_SYS_STAT_H && defined __has_include # if !__has_include(<sys/stat.h>) -# define HAVE_SYS_STAT_H false +# define HAVE_SYS_STAT_H 0 # endif #endif #ifndef HAVE_SYS_STAT_H -# define HAVE_SYS_STAT_H true +# define HAVE_SYS_STAT_H 1 #endif #if !defined HAVE_UNISTD_H && defined __has_include # if !__has_include(<unistd.h>) -# define HAVE_UNISTD_H false +# define HAVE_UNISTD_H 0 # endif #endif #ifndef HAVE_UNISTD_H -# define HAVE_UNISTD_H true +# define HAVE_UNISTD_H 1 #endif #ifndef NETBSD_INSPIRED @@ -149,25 +182,6 @@ # define ctime_r _incompatible_ctime_r #endif /* HAVE_INCOMPATIBLE_CTIME_R */ -/* Enable tm_gmtoff, tm_zone, and environ on GNUish systems. */ -#define _GNU_SOURCE 1 -/* Fix asctime_r on Solaris 11. */ -#define _POSIX_PTHREAD_SEMANTICS 1 -/* Enable strtoimax on pre-C99 Solaris 11. */ -#define __EXTENSIONS__ 1 - -/* On GNUish systems where time_t might be 32 or 64 bits, use 64. - On these platforms _FILE_OFFSET_BITS must also be 64; otherwise - setting _TIME_BITS to 64 does not work. The code does not - otherwise rely on _FILE_OFFSET_BITS being 64, since it does not - use off_t or functions like 'stat' that depend on off_t. */ -#ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -#endif -#if !defined _TIME_BITS && _FILE_OFFSET_BITS == 64 -# define _TIME_BITS 64 -#endif - /* ** Nested includes */ @@ -260,6 +274,10 @@ # endif #endif +#ifndef HAVE_SNPRINTF +# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) +#endif + #ifndef HAVE_STRFTIME_L # if _POSIX_VERSION < 200809 # define HAVE_STRFTIME_L 0 @@ -305,7 +323,7 @@ ** stdint.h, even with pre-C99 compilers. */ #if !defined HAVE_STDINT_H && defined __has_include -# define HAVE_STDINT_H true /* C23 __has_include implies C99 stdint.h. */ +# define HAVE_STDINT_H 1 /* C23 __has_include implies C99 stdint.h. */ #endif #ifndef HAVE_STDINT_H # define HAVE_STDINT_H \ @@ -375,11 +393,15 @@ typedef int int_fast32_t; # endif #endif +#ifndef INT_LEAST32_MAX +typedef int_fast32_t int_least32_t; +#endif + #ifndef INTMAX_MAX # ifdef LLONG_MAX typedef long long intmax_t; # ifndef HAVE_STRTOLL -# define HAVE_STRTOLL true +# define HAVE_STRTOLL 1 # endif # if HAVE_STRTOLL # define strtoimax strtoll @@ -459,7 +481,7 @@ typedef unsigned long uintmax_t; hosts, unless compiled with -DHAVE_STDCKDINT_H=0 or with pre-C23 EDG. */ #if !defined HAVE_STDCKDINT_H && defined __has_include # if __has_include(<stdckdint.h>) -# define HAVE_STDCKDINT_H true +# define HAVE_STDCKDINT_H 1 # endif #endif #ifdef HAVE_STDCKDINT_H @@ -554,13 +576,26 @@ typedef unsigned long uintmax_t; # define ATTRIBUTE_REPRODUCIBLE /* empty */ #endif +#if HAVE___HAS_C_ATTRIBUTE +# if __has_c_attribute(unsequenced) +# define ATTRIBUTE_UNSEQUENCED [[unsequenced]] +# endif +#endif +#ifndef ATTRIBUTE_UNSEQUENCED +# define ATTRIBUTE_UNSEQUENCED /* empty */ +#endif + /* GCC attributes that are useful in tzcode. + __attribute__((const)) is stricter than [[unsequenced]], + so the latter is an adequate substitute in non-GCC C23 platforms. __attribute__((pure)) is stricter than [[reproducible]], so the latter is an adequate substitute in non-GCC C23 platforms. */ #if __GNUC__ < 3 +# define ATTRIBUTE_CONST ATTRIBUTE_UNSEQUENCED # define ATTRIBUTE_FORMAT(spec) /* empty */ # define ATTRIBUTE_PURE ATTRIBUTE_REPRODUCIBLE #else +# define ATTRIBUTE_CONST __attribute__((const)) # define ATTRIBUTE_FORMAT(spec) __attribute__((format spec)) # define ATTRIBUTE_PURE __attribute__((pure)) #endif @@ -593,6 +628,12 @@ typedef unsigned long uintmax_t; # define RESERVE_STD_EXT_IDS 0 #endif +#ifdef time_tz +# define defined_time_tz true +#else +# define defined_time_tz false +#endif + /* If standard C identifiers with external linkage (e.g., localtime) are reserved and are not already being renamed anyway, rename them as if compiling with '-Dtime_tz=time_t'. */ @@ -608,9 +649,9 @@ typedef unsigned long uintmax_t; ** typical platforms. */ #if defined time_tz || EPOCH_LOCAL || EPOCH_OFFSET != 0 -# define TZ_TIME_T 1 +# define TZ_TIME_T true #else -# define TZ_TIME_T 0 +# define TZ_TIME_T false #endif #if defined LOCALTIME_IMPLEMENTATION && TZ_TIME_T @@ -707,7 +748,7 @@ DEPRECATED_IN_C23 char *ctime(time_t const *); char *asctime_r(struct tm const *restrict, char *restrict); char *ctime_r(time_t const *, char *); #endif -double difftime(time_t, time_t); +ATTRIBUTE_CONST double difftime(time_t, time_t); size_t strftime(char *restrict, size_t, char const *restrict, struct tm const *restrict); # if HAVE_STRFTIME_L @@ -729,9 +770,9 @@ void tzset(void); || defined __GLIBC__ || defined __tm_zone /* musl */ \ || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ \ || (defined __APPLE__ && defined __MACH__)) -# define HAVE_DECL_TIMEGM true +# define HAVE_DECL_TIMEGM 1 # else -# define HAVE_DECL_TIMEGM false +# define HAVE_DECL_TIMEGM 0 # endif #endif #if !HAVE_DECL_TIMEGM && !defined timegm @@ -771,7 +812,11 @@ extern long altzone; */ #ifndef STD_INSPIRED -# define STD_INSPIRED 0 +# ifdef __NetBSD__ +# define STD_INSPIRED 1 +# else +# define STD_INSPIRED 0 +# endif #endif #if STD_INSPIRED # if TZ_TIME_T || !defined offtime @@ -880,7 +925,7 @@ ATTRIBUTE_PURE time_t time2posix_z(timezone_t, time_t); default: TIME_T_MAX_NO_PADDING) \ : (time_t) -1) enum { SIGNED_PADDING_CHECK_NEEDED - = _Generic((time_t) 0, + = _Generic((time_t) 0, signed char: false, short: false, int: false, long: false, long long: false, default: true) }; @@ -927,8 +972,8 @@ static_assert(! TYPE_SIGNED(time_t) || ! SIGNED_PADDING_CHECK_NEEDED # define UNINIT_TRAP 0 #endif -/* localtime.c sometimes needs access to timeoff if it is not already public. - tz_private_timeoff should be used only by localtime.c. */ +/* strftime.c sometimes needs access to timeoff if it is not already public. + tz_private_timeoff should be used only by localtime.c and strftime.c. */ #if (!defined EXTERN_TIMEOFF \ && defined TM_GMTOFF && (200809 < _POSIX_VERSION || ! UNINIT_TRAP)) # ifndef timeoff diff --git a/contrib/tzcode/strftime.c b/contrib/tzcode/strftime.c index 755d341fa6d9..487a5234cbc5 100644 --- a/contrib/tzcode/strftime.c +++ b/contrib/tzcode/strftime.c @@ -39,8 +39,63 @@ #include <locale.h> #include <stdio.h> +/* If true, the value returned by an idealized unlimited-range mktime + always fits into an integer type with bounds MIN and MAX. + If false, the value might not fit. + This macro is usable in #if if its arguments are. + Add or subtract 2**31 - 1 for the maximum UT offset allowed in a TZif file, + divide by the maximum number of non-leap seconds in a year, + divide again by two just to be safe, + and account for the tm_year origin (1900) and time_t origin (1970). */ +#define MKTIME_FITS_IN(min, max) \ + ((min) < 0 \ + && ((min) + 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900 < INT_MIN \ + && INT_MAX < ((max) - 0x7fffffff) / 366 / 24 / 60 / 60 / 2 + 1970 - 1900) + +/* MKTIME_MIGHT_OVERFLOW is true if mktime can fail due to time_t overflow + or if it is not known whether mktime can fail, + and is false if mktime definitely cannot fail. + This macro is usable in #if, and so does not use TIME_T_MAX or sizeof. + If the builder has not configured this macro, guess based on what + known platforms do. When in doubt, guess true. */ +#ifndef MKTIME_MIGHT_OVERFLOW +# if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ +# include <sys/param.h> +# endif +# if ((/* The following heuristics assume native time_t. */ \ + defined_time_tz) \ + || ((/* Traditional time_t is 'long', so if 'long' is not wide enough \ + assume overflow unless we're on a known-safe host. */ \ + !MKTIME_FITS_IN(LONG_MIN, LONG_MAX)) \ + && (/* GNU C Library 2.29 (2019-02-01) and later has 64-bit time_t \ + if __TIMESIZE is 64. */ \ + !defined __TIMESIZE || __TIMESIZE < 64) \ + && (/* FreeBSD 12 r320347 (__FreeBSD_version 1200036; 2017-06-26), \ + and later has 64-bit time_t on all platforms but i386 which \ + is currently scheduled for end-of-life on 2028-11-30. */ \ + !defined __FreeBSD_version || __FreeBSD_version < 1200036 \ + || defined __i386) \ + && (/* NetBSD 6.0 (2012-10-17) and later has 64-bit time_t. */ \ + !defined __NetBSD_Version__ || __NetBSD_Version__ < 600000000) \ + && (/* OpenBSD 5.5 (2014-05-01) and later has 64-bit time_t. */ \ + !defined OpenBSD || OpenBSD < 201405))) +# define MKTIME_MIGHT_OVERFLOW 1 +# else +# define MKTIME_MIGHT_OVERFLOW 0 +# endif +#endif +/* Check that MKTIME_MIGHT_OVERFLOW is consistent with time_t's range. */ +static_assert(MKTIME_MIGHT_OVERFLOW + || MKTIME_FITS_IN(TIME_T_MIN, TIME_T_MAX)); + +#if MKTIME_MIGHT_OVERFLOW +/* Do this after system includes as it redefines time_t, mktime, timeoff. */ +# define USE_TIMEX_T true +# include "localtime.c" +#endif + #ifndef DEPRECATE_TWO_DIGIT_YEARS -# define DEPRECATE_TWO_DIGIT_YEARS false +# define DEPRECATE_TWO_DIGIT_YEARS 0 #endif struct lc_time_T { @@ -135,10 +190,6 @@ strftime(char *restrict s, size_t maxsize, char const *restrict format, tzset(); p = _fmt(format, t, s, s + maxsize, &warn); - if (!p) { - errno = EOVERFLOW; - return 0; - } if (DEPRECATE_TWO_DIGIT_YEARS && warn != IN_NONE && getenv(YEAR_2000_NAME)) { fprintf(stderr, "\n"); @@ -170,7 +221,12 @@ _fmt(const char *format, const struct tm *t, char *pt, if (*format == '%') { label: switch (*++format) { - case '\0': + default: + /* Output unknown conversion specifiers as-is, + to aid debugging. This includes '%' at + format end. This conforms to C23 section + 7.29.3.5 paragraph 6, which says behavior + is undefined here. */ --format; break; case 'A': @@ -327,16 +383,17 @@ label: tm.tm_mday = t->tm_mday; tm.tm_mon = t->tm_mon; tm.tm_year = t->tm_year; + + /* Get the time_t value for TM. + Native time_t, or its redefinition + by localtime.c above, is wide enough + so that this cannot overflow. */ #ifdef TM_GMTOFF mkt = timeoff(&tm, t->TM_GMTOFF); #else tm.tm_isdst = t->tm_isdst; mkt = mktime(&tm); #endif - /* If mktime fails, %s expands to the - value of (time_t) -1 as a failure - marker; this is better in practice - than strftime failing. */ if (TYPE_SIGNED(time_t)) { intmax_t n = mkt; sprintf(buf, "%"PRIdMAX, n); @@ -590,12 +647,6 @@ label: warnp); continue; case '%': - /* - ** X311J/88-090 (4.12.3.5): if conversion char is - ** undefined, behavior is undefined. Print out the - ** character itself as printf(3) also does. - */ - default: break; } } diff --git a/contrib/tzcode/theory.html b/contrib/tzcode/theory.html index d3573ede0dfb..352a3d87078f 100644 --- a/contrib/tzcode/theory.html +++ b/contrib/tzcode/theory.html @@ -123,8 +123,9 @@ If geolocation information is available, a selection interface can locate the user on a timezone map or prioritize names that are geographically close. For an example selection interface, see the <code>tzselect</code> program in the <code><abbr>tz</abbr></code> code. -The <a href="https://cldr.unicode.org">Unicode Common Locale Data -Repository</a> contains data that may be useful for other selection +Unicode's <a href="https://cldr.unicode.org">Common Locale Data +Repository (<abbr>CLDR</abbr>)</a> +contains data that may be useful for other selection interfaces; it maps timezone names like <code>Europe/Prague</code> to locale-dependent strings like "Prague", "Praha", "Прага", and "å¸ƒæ‹‰æ ¼". </p> @@ -200,6 +201,8 @@ in decreasing order of importance: <li> A name must not be empty, or contain '<code>//</code>', or start or end with '<code>/</code>'. + Also, a name must not be '<code>Etc/Unknown</code>', as + <abbr>CLDR</abbr> uses that string for an unknown or invalid timezone. </li> <li> Do not use names that differ only in case. @@ -220,10 +223,18 @@ in decreasing order of importance: do not need locations, since local time is not defined there. </li> <li> - If all the clocks in a timezone have agreed since 1970, - do not bother to include more than one timezone - even if some of the clocks disagreed before 1970. + If all clocks in a region have agreed since 1970, + give them just one name even if some of the clocks disagreed before 1970, + or reside in different countries or in notable or faraway locations. Otherwise these tables would become annoyingly large. + For example, do not create a name <code>Indian/Crozet</code> + as a near-duplicate or alias of <code>Asia/Dubai</code> + merely because they are different countries or territories, + or their clocks disagreed before 1970, or the + <a href="https://en.wikipedia.org/wiki/Crozet_Islands">Crozet Islands</a> + are notable in their own right, + or the Crozet Islands are not adjacent to other locations + that use <code>Asia/Dubai</code>. </li> <li> If boundaries between regions are fluid, such as during a war or @@ -579,10 +590,10 @@ in decreasing order of importance: locations while uninhabited. The leading '<code>-</code>' is a flag that the <abbr>UT</abbr> offset is in some sense undefined; this notation is derived - from <a href="https://datatracker.ietf.org/doc/html/rfc3339">Internet + from <a href="https://www.rfc-editor.org/rfc/rfc3339">Internet <abbr title="Request For Comments">RFC</abbr> 3339</a>. (The abbreviation 'Z' that - <a href="https://datatracker.ietf.org/doc/html/rfc9557">Internet + <a href="https://www.rfc-editor.org/rfc/rfc9557">Internet <abbr>RFC</abbr> 9557</a> uses for this concept would violate the POSIX requirement of at least three characters in an abbreviation.) @@ -1115,8 +1126,8 @@ However POSIX.1-2024, like earlier POSIX editions, has some limitations: the name of a file from which time-related information is read. The file's format is <dfn><abbr>TZif</abbr></dfn>, a timezone information format that contains binary data; see - <a href="https://datatracker.ietf.org/doc/html/8536">Internet - <abbr>RFC</abbr> 8536</a>. + <a href="https://www.rfc-editor.org/rfc/9636">Internet + <abbr>RFC</abbr> 9636</a>. The daylight saving time rules to be used for a particular timezone are encoded in the <abbr>TZif</abbr> file; the format of the file allows <abbr>US</abbr>, @@ -1201,12 +1212,15 @@ The vestigial <abbr>API</abbr>s are: The <code>tm_isdst</code> member is almost never needed and most of its uses should be discouraged in favor of the abovementioned <abbr>API</abbr>s. + It was intended as an index into the <code>tzname</code> variable, + but as mentioned previously that usage is obsolete. Although it can still be used in arguments to <code>mktime</code> to disambiguate timestamps near a <abbr>DST</abbr> transition when the clock jumps back on platforms lacking <code>tm_gmtoff</code>, this - disambiguation does not work when standard time itself jumps back, - which can occur when a location changes to a time zone with a + disambiguation works only for proleptic <code>TZ</code> strings; + it does not work in general for geographical timezones, + such as when a location changes to a time zone with a lesser <abbr>UT</abbr> offset. </li> </ul> @@ -1223,8 +1237,8 @@ The vestigial <abbr>API</abbr>s are: Programs that in the past used the <code>timezone</code> function may now examine <code>localtime(&clock)->tm_zone</code> (if <code>TM_ZONE</code> is defined) or - <code>tzname[localtime(&clock)->tm_isdst]</code> - (if <code>HAVE_TZNAME</code> is nonzero) to learn the correct time + use <code>strftime</code> with a <code>%Z</code> conversion specification + to learn the correct time zone abbreviation to use. </li> <li> diff --git a/contrib/tzcode/tz-link.html b/contrib/tzcode/tz-link.html index be2aae5489d6..ad2cc972a4f9 100644 --- a/contrib/tzcode/tz-link.html +++ b/contrib/tzcode/tz-link.html @@ -194,9 +194,9 @@ After obtaining the code and data files, see the The code lets you compile the <code><abbr>tz</abbr></code> source files into machine-readable binary files, one for each location. The binary files are in a special format specified by -<a href="https://datatracker.ietf.org/doc/html/8536">The +<a href="https://www.rfc-editor.org/rfc/9636">The Time Zone Information Format (<abbr>TZif</abbr>)</a> -(Internet <abbr title="Request For Comments">RFC</abbr> 8536). +(Internet <abbr title="Request For Comments">RFC</abbr> 9636). The code also lets you read a <abbr>TZif</abbr> file and interpret timestamps for that location.</p> @@ -260,7 +260,7 @@ Studio Code</a>. </p> <p> For further information about updates, please see -<a href="https://datatracker.ietf.org/doc/html/rfc6557">Procedures for +<a href="https://www.rfc-editor.org/rfc/rfc6557">Procedures for Maintaining the Time Zone Database</a> (Internet <abbr>RFC</abbr> 6557). More detail can be found in <a href="theory.html">Theory and pragmatics of the @@ -379,26 +379,26 @@ calculates the current time difference between locations.</li> <li>The <a href="https://www.ietf.org">Internet Engineering Task Force</a>'s <a href="https://datatracker.ietf.org/wg/tzdist/charter/">Time Zone Data Distribution Service (tzdist) working group</a> defined <a -href="https://datatracker.ietf.org/doc/html/rfc7808">TZDIST</a> +href="https://www.rfc-editor.org/rfc/rfc7808">TZDIST</a> (Internet <abbr>RFC</abbr> 7808), a time zone data distribution service, -along with <a href="https://datatracker.ietf.org/doc/html/rfc7809">CalDAV</a> +along with <a href="https://www.rfc-editor.org/rfc/rfc7809">CalDAV</a> (Internet <abbr>RFC</abbr> 7809), a calendar access protocol for transferring time zone data by reference. <a href="https://devguide.calconnect.org/Time-Zones/TZDS/">TZDIST implementations</a> are available. The <a href="https://www.ietf.org/mailman/listinfo/tzdist-bis">tzdist-bis mailing list</a> discusses possible extensions.</li> -<li>The <a href="https://datatracker.ietf.org/doc/html/rfc5545"> +<li>The <a href="https://www.rfc-editor.org/rfc/rfc5545"> Internet Calendaring and Scheduling Core Object Specification (iCalendar)</a> (Internet <abbr>RFC</abbr> 5445) covers time zone data; see its VTIMEZONE calendar component. The iCalendar format requires specialized parsers and generators; a -variant <a href="https://datatracker.ietf.org/doc/html/rfc6321">xCal</a> +variant <a href="https://www.rfc-editor.org/rfc/rfc6321">xCal</a> (Internet <abbr>RFC</abbr> 6321) uses <a href="https://www.w3.org/XML/"><abbr title="Extensible Markup Language">XML</abbr></a> format, and a variant -<a href="https://datatracker.ietf.org/doc/html/rfc7265">jCal</a> +<a href="https://www.rfc-editor.org/rfc/rfc7265">jCal</a> (Internet <abbr>RFC</abbr> 7265) uses <a href="https://www.json.org/json-en.html"><abbr title="JavaScript Object Notation">JSON</abbr></a> format.</li> @@ -935,7 +935,13 @@ with perhaps the best-documented history of clock adjustments.</dd> <dt>United States</dt> <dd>The Department of Transportation's <a href="https://www.transportation.gov/regulations/recent-time-zone-proceedings">Recent -Time Zone Proceedings</a> lists changes to time zone boundaries.</dd> +Time Zone Proceedings</a> lists changes to +official written time zone boundaries, and its <a +href="https://geodata.bts.gov/datasets/usdot::time-zones/about">Time +Zones dataset</a> maps current boundaries. +These boundaries are only for standard time, so the current map puts +all of Arizona in one time zone even though part of Arizona +observes <abbr>DST</abbr> and part does not.</dd> <dt>Uruguay</dt> <dd>The Oceanography, Hydrography, and Meteorology Service of the Uruguayan Navy (SOHMA) publishes an annual <a @@ -979,6 +985,14 @@ a Sleep Research Society position statement</a>. doi:<a href="https://doi.org/10.1093/sleep/zsac236">10.1093/sleep/zsac236</a>. After reviewing the scientific literature, the Sleep Research Society advocates permanent standard time due to its health benefits. +<li>Neumann P, von Blanckenburg K. <a +href="https://journals.sagepub.com/doi/full/10.1177/0961463X241310562">What +time will it be? A comprehensive literature review on daylight saving time</a>. +<em>Time Soc</em>. 2025-01-21. +doi:<a href="https://doi.org/10.1177/0961463X241310562">10.1177/0961463X241310562</a>. +This reviews DST's effects on electricity, health, crime, road safety, +and the economy, focusing on research since 2010, and concludes that +year-round standard time is preferable overall. <li>Rishi MA, Cheng JY, Strang AR <em>et al</em>. <a href="https://jcsm.aasm.org/doi/10.5664/jcsm.10898">Permanent standard time is the optimal choice for health and safety: @@ -994,7 +1008,8 @@ should we abolish Daylight Saving Time?</a> <em>J Biol Rhythms.</em> 2019;34(3):227–230. doi:<a href="https://doi.org/10.1177/0748730419854197">10.1177/0748730419854197</a>. The Society for Research on Biological Rhythms -opposes DST changes and permanent DST, and advocates that governments adopt +opposes <abbr>DST</abbr> changes and permanent <abbr>DST</abbr>, +and advocates that governments adopt "permanent Standard Time for the health and safety of their citizens".</li> </ul> </section> @@ -1023,7 +1038,7 @@ title="Institute of Electrical and Electronics Engineers">IEEE</abbr> 1588) can achieve submicrosecond clock accuracy on a local area network with special-purpose hardware.</li> <li><a -href="https://datatracker.ietf.org/doc/html/rfc4833">Timezone +href="https://www.rfc-editor.org/rfc/rfc4833">Timezone Options for <abbr title="Dynamic Host Configuration Protocol">DHCP</abbr></a> (Internet <abbr>RFC</abbr> 4833) specifies a <a @@ -1105,7 +1120,7 @@ the abovementioned <abbr>NTP</abbr> implementations, <a href="https://github.com/google/unsmear">supports</a> conversion between <abbr>UTC</abbr> and smeared <abbr>POSIX</abbr> timestamps, and is used by major cloud service providers. However, according to -<a href="https://datatracker.ietf.org/doc/html/rfc8633#section-3.7.1">§3.7.1 of +<a href="https://www.rfc-editor.org/rfc/rfc8633#section-3.7.1">§3.7.1 of Network Time Protocol Best Current Practices</a> (Internet <abbr>RFC</abbr> 8633), leap smearing is not suitable for applications requiring accurate <abbr>UTC</abbr> or civil time, @@ -1165,16 +1180,16 @@ interchange – Part 1: Basic rules</em></a>.</li> <a href="https://www.w3.org/TR/xmlschema/#dateTime"><abbr>XML</abbr> Schema: Datatypes – dateTime</a> specifies a format inspired by <abbr>ISO</abbr> 8601 that is in common use in <abbr>XML</abbr> data.</li> -<li><a href="https://datatracker.ietf.org/doc/html/rfc5322#section-3.3">§3.3 of +<li><a href="https://www.rfc-editor.org/rfc/rfc5322#section-3.3">§3.3 of Internet Message Format</a> (Internet <abbr>RFC</abbr> 5322) specifies the time notation used in email and <a href="https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol"><abbr>HTTP</abbr></a> headers.</li> <li> -<a href="https://datatracker.ietf.org/doc/html/rfc3339">Date and Time +<a href="https://www.rfc-editor.org/rfc/rfc3339">Date and Time on the Internet: Timestamps</a> (Internet <abbr>RFC</abbr> 3339) specifies an <abbr>ISO</abbr> 8601 profile for use in new Internet protocols. -An extension, <a href="https://datatracker.ietf.org/doc/html/rfc9557">Date +An extension, <a href="https://www.rfc-editor.org/rfc/rfc9557">Date and Time on the Internet: Timestamps with Additional Information</a> (Internet <abbr>RFC</abbr> 9557) extends this profile to let you specify the <code><abbr>tzdb</abbr></code> timezone of a timestamp diff --git a/contrib/tzcode/tzfile.5 b/contrib/tzcode/tzfile.5 index 63bda4114388..66d169fc5302 100644 --- a/contrib/tzcode/tzfile.5 +++ b/contrib/tzcode/tzfile.5 @@ -11,7 +11,7 @@ The timezone information files used by .Xr tzset 3 are found under .Pa /usr/share/zoneinfo . -These files use the format described in Internet RFC 8536. +These files use the format described in Internet RFC 9636. Each file is a sequence of 8-bit bytes. In a file, a binary integer is represented by a sequence of one or more bytes in network order (bigendian, or high-order byte first), @@ -107,7 +107,7 @@ and serves as an index into the array of time zone abbreviation bytes that follow the .Vt ttinfo -entries in the file; if the designated string is "\*-00", the +entries in the file; if the designated string is "\-00", the .Vt ttinfo entry is a placeholder indicating that local time is unspecified. The @@ -128,7 +128,7 @@ The byte strings can overlap if one is a suffix of the other. The encoding of these strings is not specified. .It Va tzh_leapcnt pairs of four-byte values, written in network byte order; -the first value of each pair gives the nonnegative time +the first value of each pair gives the non-negative time (as returned by .Xr time 3 ) at which a leap second occurs or at which the leap second table expires; @@ -141,7 +141,7 @@ Each pair denotes one leap second, either positive or negative, except that if the last pair has the same correction as the previous one, the last pair denotes the leap second table's expiration time. Each leap second is at the end of a UTC calendar month. -The first leap second has a nonnegative occurrence time, +The first leap second has a non-negative occurrence time, and is a positive leap second if and only if its correction is positive; the correction for each leap second after the first differs from the previous leap second by either 1 for a positive leap second, @@ -168,7 +168,7 @@ The standard/wall and UT/local indicators were designed for transforming a TZif file's transition times into transitions appropriate for another time zone specified via a proleptic TZ string that lacks rules. -For example, when TZ="EET\*-2EEST" and there is no TZif file "EET\*-2EEST", +For example, when TZ="EET\-2EEST" and there is no TZif file "EET\-2EEST", the idea was to adapt the transition times from a TZif file with the well-known name "posixrules" that is present only for this purpose and is a copy of the file "Europe/Brussels", a file with a different UT offset. @@ -177,7 +177,7 @@ the default rules are installation-dependent, and no implementation is known to support this feature for timestamps past 2037, so users desiring (say) Greek time should instead specify TZ="Europe/Athens" for better historical coverage, falling back on -TZ="EET\*-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required +TZ="EET\-2EEST,M3.5.0/3,M10.5.0/4" if POSIX conformance is required and older timestamps need not be handled accurately. .Pp The @@ -203,7 +203,7 @@ after the last transition time stored in the file or for all instants if the file has no transitions. The TZ string is empty (i.e., nothing between the newlines) if there is no proleptic representation for such instants. -If nonempty, the TZ string must agree with the local time +If non-empty, the TZ string must agree with the local time type after the last transition time if present in the eight-byte data; for example, given the string .Dq "WET0WEST,M3.5.0/1,M10.5.0" @@ -218,7 +218,7 @@ the earliest transition time. For version-3-format timezone files, a TZ string (see .Xr newtzset 3 ) may use the following POSIX.1-2024 extensions to POSIX.1-2017: -First, as in TZ="<\*-02>2<\*-01>,M3.5.0/\*-1,M10.5.0/0", +First, as in TZ="<\-02>2<\-01>,M3.5.0/\-1,M10.5.0/0", the hours part of its transition times may be signed and range from \-167 through 167 instead of being limited to unsigned values from 0 through 24. @@ -275,7 +275,7 @@ time did not exist (possibly with an error indication). Time zone designations should consist of at least three (3) and no more than six (6) ASCII characters from the set of alphanumerics, -.Dq "\*-" , +.Dq "\-" , and .Dq "+" . This is for compatibility with POSIX requirements for @@ -300,16 +300,16 @@ through 60 instead of the usual 59; the UTC offset is unaffected. This section documents common problems in reading or writing TZif files. Most of these are problems in generating TZif files for use by older readers. -The goals of this section are: +The goals of this section are to help: .Bl -bullet .It -to help TZif writers output files that avoid common +TZif writers output files that avoid common pitfalls in older or buggy TZif readers, .It -to help TZif readers avoid common pitfalls when reading +TZif readers avoid common pitfalls when reading files generated by future TZif writers, and .It -to help any future specification authors see what sort of +any future specification authors see what sort of problems arise when the TZif format is changed. .El .Pp @@ -320,9 +320,9 @@ reader was designed for. When complete compatibility was not achieved, an attempt was made to limit glitches to rarely used timestamps and allow simple partial workarounds in writers designed to generate -new-version data useful even for older-version readers. +newer-version data useful even for older-version readers. This section attempts to document these compatibility issues and -workarounds, as well as to document other common bugs in +workarounds as well as documenting other common bugs in readers. .Pp Interoperability problems with TZif include the following: @@ -355,15 +355,15 @@ for two time zones east, e.g., for a time zone with a never-used standard time (XXX, \-03) and negative daylight saving time (EDT, \-04) all year. Alternatively, -as a partial workaround a writer can substitute standard time +as a partial workaround, a writer can substitute standard time for the next time zone east \(en e.g., .Dq "AST4" for permanent Atlantic Standard Time (\-04). .It -Some readers designed for version 2 or 3, and that require strict -conformance to RFC 8536, reject version 4 files whose leap second -tables are truncated at the start or that end in expiration times. +Some readers designed for version 2 or 3 and that require strict +conformance to RFC 9636 reject version 4 files whose leap second +tables are truncated at the start or end in expiration times. .It Some readers ignore the footer, and instead predict future timestamps from the time type of the last transition. @@ -378,7 +378,7 @@ and even for current timestamps it can fail for settings like TZ="Africa/Casablanca". This corresponds to a TZif file containing explicit transitions through the year 2087, followed by a footer containing the TZ string -.Dq <+01>\*-1 , +.Dq <+01>\-1 , which should be used only for timestamps after the last explicit transition. .It @@ -389,7 +389,7 @@ As a partial workaround, a writer can output a dummy (no-op) first transition at an early time. .It Some readers mishandle timestamps before the first -transition that has a timestamp not less than \-2**31. +transition that has a timestamp that is not less than \-2**31. Readers that support only 32-bit timestamps are likely to be more prone to this problem, for example, when they process 64-bit transitions only some of which are representable in 32 @@ -401,7 +401,7 @@ Some readers mishandle a transition if its timestamp has the minimum possible signed 64-bit value. Timestamps less than \-2**59 are not recommended. .It -Some readers mishandle TZ strings that +Some readers mishandle proleptic TZ strings that contain .Dq "<" or @@ -418,9 +418,9 @@ non-ASCII characters. These characters are not recommended. .It Some readers may mishandle time zone abbreviations that -contain fewer than 3 or more than 6 characters, or that +contain fewer than 3 or more than 6 characters or that contain ASCII characters other than alphanumerics, -.Dq "\*-", +.Dq "\-", and .Dq "+". These abbreviations are not recommended. @@ -430,7 +430,7 @@ daylight-saving time UT offsets that are less than the UT offsets for the corresponding standard time. These readers do not support locations like Ireland, which uses the equivalent of the TZ string -.Dq "IST\*-1GMT0,M10.5.0,M3.5.0/1", +.Dq "IST\-1GMT0,M10.5.0,M3.5.0/1", observing standard time (IST, +01) in summer and daylight saving time (GMT, +00) in winter. As a partial workaround, a writer can output data for the @@ -443,7 +443,7 @@ abbreviations correctly. .It Some readers generate ambiguous timestamps for positive leap seconds that occur when the UTC offset is not a multiple of 60 seconds. -For example, in a timezone with UTC offset +01:23:45 and with +For example, with UTC offset +01:23:45 and a positive leap second 78796801 (1972-06-30 23:59:60 UTC), some readers will map both 78796800 and 78796801 to 01:23:45 local time the next day instead of mapping the latter to 01:23:46, and they will map 78796815 to @@ -462,15 +462,15 @@ Developers of distributed applications should keep this in mind if they need to deal with pre-1970 data. .It Some readers mishandle timestamps before the first -transition that has a nonnegative timestamp. +transition that has a non-negative timestamp. Readers that do not support negative timestamps are likely to be more prone to this problem. .It Some readers mishandle time zone abbreviations like -.Dq "\*-08" +.Dq "\-08" that contain -.Dq "+" , -.Dq "\*-" , +.Dq "+", +.Dq "\-", or digits. .It Some readers mishandle UT offsets that are out of the @@ -479,7 +479,7 @@ support locations like Kiritimati that are outside this range. .It Some readers mishandle UT offsets in the range [\-3599, \-1] -seconds from UT, because they integer-divide the offset by +seconds from UT because they integer-divide the offset by 3600 to get 0 and then display the hour part as .Dq "+00" . .It @@ -498,8 +498,8 @@ of one hour, or of 15 minutes, or of 1 minute. .%A P. Eggert .%A K. Murchison .%T "The Time Zone Information Format (TZif)" -.%R RFC 8536 -.%D February 2019 -.%U https://datatracker.ietf.org/doc/html/rfc8536 -.%U https://doi.org/10.17487/RFC8536 +.%R RFC 9636 +.%D October 2024 +.%U https://datatracker.ietf.org/doc/html/rfc9636 +.%U https://doi.org/10.17487/RFC9636 .Re diff --git a/contrib/tzcode/tzfile.h b/contrib/tzcode/tzfile.h index c09f39465914..55867b5c260c 100644 --- a/contrib/tzcode/tzfile.h +++ b/contrib/tzcode/tzfile.h @@ -28,7 +28,7 @@ #endif /* !defined TZDEFRULES */ -/* See Internet RFC 8536 for more details about the following format. */ +/* See Internet RFC 9636 for more details about the following format. */ /* ** Each file begins with. . . diff --git a/contrib/tzcode/tzselect.8 b/contrib/tzcode/tzselect.8 index ee031614f3ed..b83f702d5e0d 100644 --- a/contrib/tzcode/tzselect.8 +++ b/contrib/tzcode/tzselect.8 @@ -4,8 +4,6 @@ .SH NAME tzselect \- select a timezone .SH SYNOPSIS -.ie \n(.g .ds - \f(CR-\fP -.el .ds - \- .ds d " degrees .ds m " minutes .ds s " seconds @@ -20,15 +18,15 @@ tzselect \- select a timezone .\} .B tzselect [ -.B \*-c +.B \-c .I coord ] [ -.B \*-n +.B \-n .I limit ] [ -.B \*-\*-help +.B \-\-help ] [ -.B \*-\*-version +.B \-\-version ] .SH DESCRIPTION The @@ -40,7 +38,7 @@ The output is suitable as a value for the TZ environment variable. All interaction with the user is done via standard input and standard error. .SH OPTIONS .TP -.BI "\*-c " coord +.BI "\-c " coord Instead of asking for continent and then country and then city, ask for selection from time zones whose largest cities are closest to the location with geographical coordinates @@ -70,27 +68,27 @@ seconds, with any trailing fractions represent fractional minutes or .I SS is present) seconds. The decimal point is that of the current locale. For example, in the (default) C locale, -.B "\*-c\ +40.689\*-074.045" +.B "\-c\ +40.689\-074.045" specifies 40.689\*d\*_N, 74.045\*d\*_W, -.B "\*-c\ +4041.4\*-07402.7" +.B "\-c\ +4041.4\-07402.7" specifies 40\*d\*_41.4\*m\*_N, 74\*d\*_2.7\*m\*_W, and -.B "\*-c\ +404121\*-0740240" +.B "\-c\ +404121\-0740240" specifies 40\*d\*_41\*m\*_21\*s\*_N, 74\*d\*_2\*m\*_40\*s\*_W. If .I coord is not one of the documented forms, the resulting behavior is unspecified. .TP -.BI "\*-n " limit +.BI "\-n " limit When -.B \*-c +.B \-c is used, display the closest .I limit locations (default 10). .TP -.B "\*-\*-help" +.B "\-\-help" Output help information and exit. .TP -.B "\*-\*-version" +.B "\-\-version" Output version information and exit. .SH "ENVIRONMENT VARIABLES" .TP diff --git a/contrib/tzcode/version b/contrib/tzcode/version index 699e50d4d38e..ef468adcecf9 100644 --- a/contrib/tzcode/version +++ b/contrib/tzcode/version @@ -1 +1 @@ -2024b +2025b diff --git a/contrib/tzcode/zdump.8 b/contrib/tzcode/zdump.8 index 7a78f6b9c040..c5cb092db16f 100644 --- a/contrib/tzcode/zdump.8 +++ b/contrib/tzcode/zdump.8 @@ -28,6 +28,14 @@ The program prints the current time in each .Ar timezone named on the command line. +A +.Ar timezone +of +.Li - +is treated as if it were +.Pa /dev/stdin ; +this can be used to pipe TZif data into +.Nm . .Pp The following options are available: .Bl -tag -width indent @@ -106,7 +114,7 @@ then a line where .Ar string is a double-quoted string giving the timezone, a second line -.Dq "\*- \*- \fIinterval\fP" +.Dq "\- \- \fIinterval\fP" describing the time interval before the first transition if any, and zero or more following lines .Dq "\fIdate time interval\fP", @@ -138,11 +146,11 @@ the seconds are omitted if they are zero, and the minutes are also omitted if they are also zero. Positive UT offsets are east of Greenwich. -The UT offset \*-00 denotes a UT +The UT offset \-00 denotes a UT placeholder in areas where the actual offset is unspecified; by convention, this occurs when the UT offset is zero and the time zone abbreviation begins with -.Dq "-" +.Dq "\-" or is .Dq "zzz". .Pp diff --git a/contrib/tzcode/zdump.c b/contrib/tzcode/zdump.c index a42c337e6d44..a8a8f5aa42ca 100644 --- a/contrib/tzcode/zdump.c +++ b/contrib/tzcode/zdump.c @@ -14,10 +14,6 @@ #include "private.h" #include <stdio.h> -#ifndef HAVE_SNPRINTF -# define HAVE_SNPRINTF (!PORT_TO_C89 || 199901 <= __STDC_VERSION__) -#endif - #ifndef HAVE_LOCALTIME_R # define HAVE_LOCALTIME_R 1 #endif @@ -148,17 +144,6 @@ sumsize(ptrdiff_t a, ptrdiff_t b) size_overflow(); } -/* Return the size of of the string STR, including its trailing NUL. - Report an error and exit if this would exceed INDEX_MAX which means - pointer subtraction wouldn't work. */ -static ptrdiff_t -xstrsize(char const *str) -{ - size_t len = strlen(str); - if (len < INDEX_MAX) - return len + 1; - size_overflow(); -} /* Return a pointer to a newly allocated buffer of size SIZE, exiting on failure. SIZE should be positive. */ @@ -266,7 +251,7 @@ tzalloc(char const *val) static ptrdiff_t fakeenv0size; void *freeable = NULL; char **env = fakeenv, **initial_environ; - ptrdiff_t valsize = xstrsize(val); + ptrdiff_t valsize = strlen(val) + 1; if (fakeenv0size < valsize) { char **e = environ, **to; ptrdiff_t initial_nenvptrs = 1; /* Counting the trailing NULL pointer. */ @@ -427,7 +412,7 @@ saveabbr(char **buf, ptrdiff_t *bufalloc, struct tm const *tmp) if (HAVE_LOCALTIME_RZ) return ab; else { - ptrdiff_t absize = xstrsize(ab); + ptrdiff_t absize = strlen(ab) + 1; if (*bufalloc < absize) { free(*buf); @@ -489,6 +474,7 @@ main(int argc, char *argv[]) register time_t cuthitime; time_t now; bool iflag = false; + size_t arglenmax = 0; cutlotime = absolute_min_time; cuthitime = absolute_max_time; @@ -588,15 +574,21 @@ main(int argc, char *argv[]) now = time(NULL); now |= !now; } - longest = 0; for (i = optind; i < argc; i++) { size_t arglen = strlen(argv[i]); - if (longest < arglen) - longest = min(arglen, INT_MAX); + if (arglenmax < arglen) + arglenmax = arglen; } + if (!HAVE_SETENV && INDEX_MAX <= arglenmax) + size_overflow(); + longest = min(arglenmax, INT_MAX - 2); for (i = optind; i < argc; ++i) { - timezone_t tz = tzalloc(argv[i]); + /* Treat "-" as standard input on platforms with /dev/stdin. + It's not worth the bother of supporting "-" on other + platforms, as that would need temp files. */ + timezone_t tz = tzalloc(strcmp(argv[i], "-") == 0 + ? "/dev/stdin" : argv[i]); char const *ab; time_t t; struct tm tm, newtm; @@ -697,7 +689,7 @@ yeartot(intmax_t y) return absolute_max_time; seconds = diff400 * SECSPER400YEARS; years = diff400 * 400; - } else { + } else { seconds = isleap(myy) ? SECSPERLYEAR : SECSPERNYEAR; years = 1; } @@ -928,13 +920,10 @@ showextrema(timezone_t tz, char *zone, time_t lo, struct tm *lotmp, time_t hi) } } -#if HAVE_SNPRINTF -# define my_snprintf snprintf -#else +/* On pre-C99 platforms, a snprintf substitute good enough for us. */ +#if !HAVE_SNPRINTF # include <stdarg.h> - -/* A substitute for snprintf that is good enough for zdump. */ -static int +ATTRIBUTE_FORMAT((printf, 3, 4)) static int my_snprintf(char *s, size_t size, char const *format, ...) { int n; @@ -962,6 +951,7 @@ my_snprintf(char *s, size_t size, char const *format, ...) va_end(args); return n; } +# define snprintf my_snprintf #endif /* Store into BUF, of size SIZE, a formatted local time taken from *TM. @@ -976,10 +966,10 @@ format_local_time(char *buf, ptrdiff_t size, struct tm const *tm) { int ss = tm->tm_sec, mm = tm->tm_min, hh = tm->tm_hour; return (ss - ? my_snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) + ? snprintf(buf, size, "%02d:%02d:%02d", hh, mm, ss) : mm - ? my_snprintf(buf, size, "%02d:%02d", hh, mm) - : my_snprintf(buf, size, "%02d", hh)); + ? snprintf(buf, size, "%02d:%02d", hh, mm) + : snprintf(buf, size, "%02d", hh)); } /* Store into BUF, of size SIZE, a formatted UT offset for the @@ -1014,10 +1004,10 @@ format_utc_offset(char *buf, ptrdiff_t size, struct tm const *tm, time_t t) mm = off / 60 % 60; hh = off / 60 / 60; return (ss || 100 <= hh - ? my_snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) + ? snprintf(buf, size, "%c%02ld%02d%02d", sign, hh, mm, ss) : mm - ? my_snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) - : my_snprintf(buf, size, "%c%02ld", sign, hh)); + ? snprintf(buf, size, "%c%02ld%02d", sign, hh, mm) + : snprintf(buf, size, "%c%02ld", sign, hh)); } /* Store into BUF (of size SIZE) a quoted string representation of P. @@ -1120,7 +1110,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, for (abp = ab; is_alpha(*abp); abp++) continue; len = (!*abp && *ab - ? my_snprintf(b, s, "%s", ab) + ? snprintf(b, s, "%s", ab) : format_quoted_string(b, s, ab)); if (s <= len) return false; @@ -1128,7 +1118,7 @@ istrftime(char *buf, ptrdiff_t size, char const *time_fmt, } formatted_len = (tm->tm_isdst - ? my_snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) + ? snprintf(b, s, &"\t\t%d"[show_abbr], tm->tm_isdst) : 0); } break; diff --git a/contrib/tzcode/zic.8 b/contrib/tzcode/zic.8 index 3804096dd6f6..d83ff7c4a0b1 100644 --- a/contrib/tzcode/zic.8 +++ b/contrib/tzcode/zic.8 @@ -112,13 +112,13 @@ Link \fItimezone\fP posixrules If .Ar timezone is -.Dq "\*-" +.Dq "\-" (the default), any already-existing link is removed. .Pp Unless .Ar timezone is -.Dq "\*-" , +.Dq "\-" , this option is obsolete and poorly supported. Among other things it should not be used for timestamps after the year 2037, and it should not be combined with @@ -148,6 +148,10 @@ omits data intended for negative timestamps (i.e., before the Epoch), and .Fl r @0/@2147483648 outputs data intended only for nonnegative timestamps that fit into 31-bit signed integers. +On platforms with GNU +.Nm date , +.Dq "zic \-r @$(date +%s)" +omits data intended for past timestamps. Although this option typically reduces the output file's size, the size can increase due to the need to represent the timestamp range boundaries, particularly if @@ -366,7 +370,15 @@ separate script to further restrict in which of years the rule would apply. .It IN Names the month in which the rule takes effect. -Month names may be abbreviated. +Month names may be abbreviated as mentioned previously; +for example, January can appear as +.Dq January , +.Dq JANU +or +.Dq Ja , +but not as +.Dq j +which would be ambiguous with both June and July. .It ON Gives the day on which the rule takes effect. Recognized forms include: @@ -389,7 +401,12 @@ or a weekday name preceded by .Dq "last" (e.g., .Ql "lastSunday" ) -may be abbreviated or spelled out in full. +may be abbreviated as mentioned previously, +e.g., +.Dq Su +for Sunday and +.Dq lastsa +for the last Saturday. There must be no white space characters within the .Ar ON field. @@ -540,7 +557,7 @@ field, giving the amount of time to be added to local standard time and whether the resulting time is standard or daylight saving. Standard time applies if this field is -.Ql \*- +.Ql \- or for timestamps occurring before any rule takes effect. When an amount of time is given, only the sum of standard time and this amount matters. diff --git a/contrib/tzcode/zic.c b/contrib/tzcode/zic.c index 2605f65dcd23..80902ce534a1 100644 --- a/contrib/tzcode/zic.c +++ b/contrib/tzcode/zic.c @@ -526,19 +526,19 @@ memcheck(void *ptr) } static void * -emalloc(size_t size) +xmalloc(size_t size) { return memcheck(malloc(size)); } static void * -erealloc(void *ptr, size_t size) +xrealloc(void *ptr, size_t size) { return memcheck(realloc(ptr, size)); } static char * -estrdup(char const *str) +xstrdup(char const *str) { return memcheck(strdup(str)); } @@ -567,7 +567,7 @@ growalloc(void *ptr, ptrdiff_t itemsize, ptrdiff_t nitems, { return (nitems < *nitems_alloc ? ptr - : erealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); + : xrealloc(ptr, grow_nitems_alloc(nitems_alloc, itemsize))); } /* @@ -654,6 +654,8 @@ close_file(FILE *stream, char const *dir, char const *name, char const *e = (ferror(stream) ? _("I/O error") : fclose(stream) != 0 ? strerror(errno) : NULL); if (e) { + if (name && *name == '/') + dir = NULL; fprintf(stderr, "%s: %s%s%s%s%s\n", progname, dir ? dir : "", dir ? "/" : "", name ? name : "", name ? ": " : "", @@ -961,6 +963,9 @@ static mode_t mflag = (S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR); static const char * tzdefault; +/* True if DIRECTORY ends in '/'. */ +static bool directory_ends_in_slash; + /* -1 if the TZif output file should be slim, 0 if default, 1 if the output should be fat for backward compatibility. ZIC_BLOAT_DEFAULT determines the default. */ @@ -1166,6 +1171,7 @@ _("invalid file mode")); return EXIT_FAILURE; associate(); change_directory(directory); + directory_ends_in_slash = directory[strlen(directory) - 1] == '/'; catch_signals(); for (i = 0; i < nzones; i = j) { /* @@ -1353,7 +1359,7 @@ random_dirent(char const **name, char **namealloc) uint_fast64_t unfair_min = - ((UINTMAX_MAX % base__6 + 1) % base__6); if (!dst) { - dst = emalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); + dst = xmalloc(size_sum(dirlen, prefixlen + suffixlen + 1)); memcpy(dst, src, dirlen); memcpy(dst + dirlen, prefix, prefixlen); dst[dirlen + prefixlen + suffixlen] = '\0'; @@ -1370,6 +1376,20 @@ random_dirent(char const **name, char **namealloc) } } +/* For diagnostics the directory, and file name relative to that + directory, respectively. A diagnostic routine can name FILENAME by + outputting diagdir(FILENAME), then diagslash(FILENAME), then FILENAME. */ +static char const * +diagdir(char const *filename) +{ + return *filename == '/' ? "" : directory; +} +static char const * +diagslash(char const *filename) +{ + return &"/"[*filename == '/' || directory_ends_in_slash]; +} + /* Prepare to write to the file *OUTNAME, using *TEMPNAME to store the name of the temporary file that will eventually be renamed to *OUTNAME. Assign the temporary file's name to both *OUTNAME and @@ -1406,8 +1426,9 @@ open_outfile(char const **outname, char **tempname) } else if (fopen_errno == EEXIST) random_dirent(outname, tempname); else { - fprintf(stderr, _("%s: Can't create %s/%s: %s\n"), - progname, directory, *outname, strerror(fopen_errno)); + fprintf(stderr, _("%s: Can't create %s%s%s: %s\n"), + progname, diagdir(*outname), diagslash(*outname), *outname, + strerror(fopen_errno)); exit(EXIT_FAILURE); } } @@ -1424,9 +1445,10 @@ rename_dest(char *tempname, char const *name) if (tempname) { if (rename(tempname, name) != 0) { int rename_errno = errno; - (void)remove(tempname); - fprintf(stderr, _("%s: rename to %s/%s: %s\n"), - progname, directory, name, strerror(rename_errno)); + remove(tempname); + fprintf(stderr, _("%s: rename to %s%s%s: %s\n"), + progname, diagdir(name), diagslash(name), name, + strerror(rename_errno)); exit(EXIT_FAILURE); } free(tempname); @@ -1436,7 +1458,8 @@ rename_dest(char *tempname, char const *name) /* Create symlink contents suitable for symlinking TARGET to LINKNAME, as a freshly allocated string. TARGET should be a relative file name, and is relative to the global variable DIRECTORY. LINKNAME can be either - relative or absolute. */ + relative or absolute. Return a null pointer if the symlink contents + was not computed because LINKNAME is absolute but DIRECTORY is not. */ static char * relname(char const *target, char const *linkname) { @@ -1449,8 +1472,10 @@ relname(char const *target, char const *linkname) size_t len = strlen(directory); size_t lenslash = len + (len && directory[len - 1] != '/'); size_t targetsize = strlen(target) + 1; + if (*directory != '/') + return NULL; linksize = size_sum(lenslash, targetsize); - f = result = emalloc(linksize); + f = result = xmalloc(linksize); memcpy(result, directory, len); result[len] = '/'; memcpy(result + lenslash, target, targetsize); @@ -1464,7 +1489,7 @@ relname(char const *target, char const *linkname) dotdotetcsize = size_sum(size_product(dotdots, 3), taillen + 1); if (dotdotetcsize <= linksize) { if (!result) - result = emalloc(dotdotetcsize); + result = xmalloc(dotdotetcsize); for (i = 0; i < dotdots; i++) memcpy(result + 3 * i, "../", 3); memmove(result + 3 * dotdots, f + dir_len, taillen + 1); @@ -1500,8 +1525,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) return; else { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't remove %s/%s: %s\n"), - progname, directory, linkname, e); + fprintf(stderr, _("%s: Can't remove %s%s%s: %s\n"), + progname, diagdir(linkname), diagslash(linkname), linkname, + e); exit(EXIT_FAILURE); } } @@ -1544,8 +1570,9 @@ dolink(char const *target, char const *linkname, bool staysymlink) mkdirs(linkname, true); linkdirs_made = true; } else { - fprintf(stderr, _("%s: Can't link %s/%s to %s/%s: %s\n"), - progname, directory, target, directory, outname, + fprintf(stderr, _("%s: Can't link %s%s%s to %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, + diagdir(outname), diagslash(outname), outname, strerror(link_errno)); exit(EXIT_FAILURE); } @@ -1554,21 +1581,23 @@ dolink(char const *target, char const *linkname, bool staysymlink) bool absolute = *target == '/'; char *linkalloc = absolute ? NULL : relname(target, linkname); char const *contents = absolute ? target : linkalloc; - int symlink_errno; + int symlink_errno = -1; - while (true) { - if (symlink(contents, outname) == 0) { - symlink_errno = 0; - break; + if (contents) { + while (true) { + if (symlink(contents, outname) == 0) { + symlink_errno = 0; + break; + } + symlink_errno = errno; + if (symlink_errno == EEXIST) + random_dirent(&outname, &tempname); + else if (symlink_errno == ENOENT && !linkdirs_made) { + mkdirs(linkname, true); + linkdirs_made = true; + } else + break; } - symlink_errno = errno; - if (symlink_errno == EEXIST) - random_dirent(&outname, &tempname); - else if (symlink_errno == ENOENT && !linkdirs_made) { - mkdirs(linkname, true); - linkdirs_made = true; - } else - break; } free(linkalloc); if (symlink_errno == 0) { @@ -1581,8 +1610,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) fp = fopen(target, "rb"); if (!fp) { char const *e = strerror(errno); - fprintf(stderr, _("%s: Can't read %s/%s: %s\n"), - progname, directory, target, e); + fprintf(stderr, _("%s: Can't read %s%s%s: %s\n"), + progname, diagdir(target), diagslash(target), target, e); exit(EXIT_FAILURE); } tp = open_outfile(&outname, &tempname); @@ -1593,6 +1622,8 @@ dolink(char const *target, char const *linkname, bool staysymlink) if (link_errno != ENOTSUP) warning(_("copy used because hard link failed: %s"), strerror(link_errno)); + else if (symlink_errno < 0) + warning(_("copy used because symbolic link not obvious")); else if (symlink_errno != ENOTSUP) warning(_("copy used because symbolic link failed: %s"), strerror(symlink_errno)); @@ -1906,8 +1937,8 @@ inrule(char **fields, int nfields) fields[RF_COMMAND], fields[RF_MONTH], fields[RF_DAY], fields[RF_TOD])) return; - r.r_name = estrdup(fields[RF_NAME]); - r.r_abbrvar = estrdup(fields[RF_ABBRVAR]); + r.r_name = xstrdup(fields[RF_NAME]); + r.r_abbrvar = xstrdup(fields[RF_ABBRVAR]); if (max_abbrvar_len < strlen(r.r_abbrvar)) max_abbrvar_len = strlen(r.r_abbrvar); rules = growalloc(rules, sizeof *rules, nrules, &nrules_alloc); @@ -1990,7 +2021,8 @@ inzsub(char **fields, int nfields, bool iscont) z.z_filenum = filenum; z.z_linenum = linenum; z.z_stdoff = gethms(fields[i_stdoff], _("invalid UT offset")); - if ((cp = strchr(fields[i_format], '%')) != 0) { + cp = strchr(fields[i_format], '%'); + if (cp) { if ((*++cp != 's' && *cp != 'z') || strchr(cp, '%') || strchr(fields[i_format], '/')) { error(_("invalid abbreviation format")); @@ -2028,9 +2060,9 @@ inzsub(char **fields, int nfields, bool iscont) return false; } } - z.z_name = iscont ? NULL : estrdup(fields[ZF_NAME]); - z.z_rule = estrdup(fields[i_rule]); - z.z_format = cp1 = estrdup(fields[i_format]); + z.z_name = iscont ? NULL : xstrdup(fields[ZF_NAME]); + z.z_rule = xstrdup(fields[i_rule]); + z.z_format = cp1 = xstrdup(fields[i_format]); if (z.z_format_specifier == 'z') { cp1[cp - fields[i_format]] = 's'; if (noise) @@ -2173,8 +2205,8 @@ inlink(char **fields, int nfields) return; l.l_filenum = filenum; l.l_linenum = linenum; - l.l_target = estrdup(fields[LF_TARGET]); - l.l_linkname = estrdup(fields[LF_LINKNAME]); + l.l_target = xstrdup(fields[LF_TARGET]); + l.l_linkname = xstrdup(fields[LF_LINKNAME]); links = growalloc(links, sizeof *links, nlinks, &nlinks_alloc); links[nlinks++] = l; } @@ -2197,7 +2229,7 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, rp->r_month = lp->l_value; rp->r_todisstd = false; rp->r_todisut = false; - dp = estrdup(timep); + dp = xstrdup(timep); if (*dp != '\0') { ep = dp + strlen(dp) - 1; switch (lowerit(*ep)) { @@ -2272,19 +2304,23 @@ rulesub(struct rule *rp, const char *loyearp, const char *hiyearp, ** Sun<=20 ** Sun>=7 */ - dp = estrdup(dayp); + dp = xstrdup(dayp); if ((lp = byword(dp, lasts)) != NULL) { rp->r_dycode = DC_DOWLEQ; rp->r_wday = lp->l_value; rp->r_dayofmonth = len_months[1][rp->r_month]; } else { - if ((ep = strchr(dp, '<')) != 0) - rp->r_dycode = DC_DOWLEQ; - else if ((ep = strchr(dp, '>')) != 0) - rp->r_dycode = DC_DOWGEQ; + ep = strchr(dp, '<'); + if (ep) + rp->r_dycode = DC_DOWLEQ; else { + ep = strchr(dp, '>'); + if (ep) + rp->r_dycode = DC_DOWGEQ; + else { ep = dp; rp->r_dycode = DC_DOM; + } } if (rp->r_dycode != DC_DOM) { *ep++ = 0; @@ -2427,7 +2463,7 @@ writezone(const char *const name, const char *const string, char version, /* Allocate the ATS and TYPES arrays via a single malloc, as this is a bit faster. Do not malloc(0) if !timecnt, as that might return NULL even on success. */ - zic_t *ats = emalloc(align_to(size_product(timecnt + !timecnt, + zic_t *ats = xmalloc(align_to(size_product(timecnt + !timecnt, sizeof *ats + 1), alignof(zic_t))); void *typesptr = ats + timecnt; @@ -2802,7 +2838,7 @@ writezone(const char *const name, const char *const string, char version, if (thisleapexpiry) { /* Append a no-op leap correction indicating when the leap second table expires. Although this does not conform to - Internet RFC 8536, most clients seem to accept this and + Internet RFC 9636, most clients seem to accept this and the plan is to amend the RFC to allow this in version 4 TZif files. */ puttzcodepass(leapexpires, fp, pass); @@ -3059,7 +3095,7 @@ stringzone(char *result, struct zone const *zpfirst, ptrdiff_t zonecount) result[0] = '\0'; - /* Internet RFC 8536 section 5.1 says to use an empty TZ string if + /* Internet RFC 9636 section 6.1 says to use an empty TZ string if future timestamps are truncated. */ if (hi_time < max_time) return -1; @@ -3187,9 +3223,9 @@ outzone(const struct zone *zpfirst, ptrdiff_t zonecount) max_abbr_len = 2 + max_format_len + max_abbrvar_len; max_envvar_len = 2 * max_abbr_len + 5 * 9; - startbuf = emalloc(max_abbr_len + 1); - ab = emalloc(max_abbr_len + 1); - envvar = emalloc(max_envvar_len + 1); + startbuf = xmalloc(max_abbr_len + 1); + ab = xmalloc(max_abbr_len + 1); + envvar = xmalloc(max_envvar_len + 1); INITIALIZE(untiltime); INITIALIZE(starttime); /* @@ -3972,7 +4008,7 @@ mkdirs(char const *argname, bool ancestors) if (Dflag) return; - char *name = estrdup(argname); + char *name = xstrdup(argname); char *cp = name; /* On MS-Windows systems, do not worry about drive letters or |