--- /dev/null
+name: CMake CI
+
+on:
+ push:
+ branches: [ master ]
+ pull_request:
+ branches: [ master ]
+
+jobs:
+ # ===========================================
+ # Main build matrix - full test suite
+ # ===========================================
+ build:
+ name: ${{ matrix.os }} - ${{ matrix.compiler }} - ${{ matrix.build_type }}
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ compiler: [gcc, clang, msvc]
+ build_type: [Debug, Release]
+ exclude: &exclude-list
+ - os: windows-latest
+ compiler: gcc
+ - os: windows-latest
+ compiler: clang
+ - os: ubuntu-latest
+ compiler: msvc
+ - os: macos-latest
+ compiler: msvc
+ include: &include-list
+ - os: ubuntu-latest
+ compiler: gcc
+ cc: gcc
+ cxx: g++
+ - os: ubuntu-latest
+ compiler: clang
+ cc: clang-18
+ cxx: clang++-18
+ - os: macos-latest
+ compiler: gcc
+ cc: gcc
+ cxx: g++
+ - os: macos-latest
+ compiler: clang
+ cc: clang
+ cxx: clang++
+ - os: windows-latest
+ compiler: msvc
+ cc: cl
+ cxx: cl
+
+ steps:
+ - &checkout {
+ uses: actions/checkout@v4
+ }
+
+ - &setup-msvc {
+ name: Setup MSBuild,
+ if: runner.os == 'Windows',
+ uses: microsoft/setup-msbuild@v2,
+ }
+
+ - &install-ubuntu {
+ name: "Install dependencies (Ubuntu)",
+ if: runner.os == 'Linux',
+ run: "sudo apt-get update -qq && sudo apt-get install --no-install-recommends -y cmake ninja-build pkg-config check libyaml-dev libltdl-dev ${{ matrix.cc }} ${{ matrix.cxx }}"
+ }
+
+ - &install-macos {
+ name: "Install dependencies (macOS)",
+ if: runner.os == 'macOS',
+ run: "brew update && brew install cmake ninja pkg-config check libyaml gcc@13"
+ }
+
+ - &install-windows {
+ name: "Install dependencies (Windows)",
+ if: runner.os == 'Windows',
+ run: "choco install cmake ninja pkgconfiglite",
+ }
+
+ - &set-env {
+ name: "Set compiler environment (Unix)",
+ if: runner.os != 'Windows',
+ run: "echo \"CC=${{ matrix.cc }}\" >> $GITHUB_ENV && echo \"CXX=${{ matrix.cxx }}\" >> $GITHUB_ENV"
+ }
+
+ - &configure-unix {
+ name: "Configure (Unix)",
+ if: runner.os != 'Windows',
+ run: "cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}"
+ }
+
+ - &configure-windows {
+ name: "Configure (Windows)",
+ if: runner.os == 'Windows',
+ run: "cmake -B build -A x64 -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}"
+ }
+
+ - &build {
+ name: Build,
+ run: "cmake --build build --config ${{ matrix.build_type }}"
+ }
+
+ - &test-unix {
+ name: Test,
+ if: runner.os != 'Windows',
+ working-directory: build,
+ run: "ctest --output-on-failure",
+ }
+
+ - &upload-logs {
+ name: "Upload test logs on failure",
+ if: failure(),
+ uses: actions/upload-artifact@v4,
+ with: {
+ name: "test-logs-${{ matrix.os }}-${{ matrix.compiler }}-${{ matrix.build_type }}",
+ path: "build/Testing/Temporary/\nbuild/**/*.log"
+ }
+ }
+
+ # ===========================================
+ # ASAN builds - Debug only
+ # ===========================================
+ asan:
+ name: ASAN - ${{ matrix.os }} - ${{ matrix.compiler }}
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, macos-latest]
+ compiler: [gcc, clang]
+ build_type: [Debug]
+ exclude:
+ - os: macos-latest
+ compiler: gcc
+ include:
+ - os: ubuntu-latest
+ compiler: gcc
+ cc: gcc
+ cxx: g++
+ - os: ubuntu-latest
+ compiler: clang
+ cc: clang-18
+ cxx: clang++-18
+ - os: macos-latest
+ compiler: clang
+ cc: clang
+ cxx: clang++
+
+ steps:
+ - *checkout
+ - *setup-msvc
+ - *install-ubuntu
+ - *install-macos
+ - *install-windows
+ - *set-env
+ - &configure-unix-asan {
+ name: "Configure ASAN (Unix)",
+ if: runner.os != 'Windows',
+ run: "cmake -B build -G Ninja -DENABLE_ASAN=On -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}"
+ }
+ - *build
+ - *test-unix
+ - *upload-logs
+
+ # ===========================================
+ # Smoke tests - pinned latest versions
+ # ===========================================
+ smoke-pinned:
+ name: Smoke - ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-24.04, ubuntu-22.04, macos-14, windows-2022, ubuntu-24.04-arm]
+ build_type: [Release]
+
+ steps:
+ - *checkout
+ - *setup-msvc
+ - *install-ubuntu
+ - *install-macos
+ - *install-windows
+ - *set-env
+ - &configure-unix-smoke {
+ name: "Configure smoke (Unix)",
+ if: runner.os != 'Windows',
+ run: "cmake -B build -G Ninja -DBUILD_TESTING=Off -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}",
+ }
+ - &configure-windows-smoke {
+ name: "Configure smoke (Windows)",
+ if: runner.os == 'Windows',
+ run: "cmake -B build -A x64 -DBUILD_TESTING=Off -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}"
+ }
+ - *build
+ - *upload-logs
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+## [0.9.4] - 2026-02-03
+
+### Major: Full Windows Support
+
+This release adds **full native Windows support**. libfyaml now builds and runs natively on Windows with MSVC, clang-cl, and Clang compilers.
+
+**Native Windows builds:**
+- Full support for building on Windows using MSVC, clang-cl, or GCC
+- Works with Visual Studio, VSCode, and other Windows development tools
+- All tests pass on Windows
+
+**Cross-compilation from Linux:**
+- Support for msvc-wine to install MSVC redistributables on Linux
+- Compile using `cl.exe` via Wine
+- Compile using `clang-cl` without Wine
+- Compile using Clang cross-compilation triplet
+
+### Major: Comment Support Now Stable
+
+Comment parsing and emission has been moved out of experimental status. Comments can now be reliably preserved and manipulated through the API.
+
+### Added
+
+- `fy_node_set_style()`: Set the style of a node (block, flow, plain, etc.) - Fixes #78
+- `fy_token_set_comment()`: Attach comments to tokens programmatically
+- `fy_event_to_string()`: Convert events to string representation
+- `fy_diag_get_collect_errors()`: Query if error collection is enabled
+- `fy_atom_lines_containing()`: Get lines containing an atom (for diagnostics)
+- `fy_memstream`: Portable `open_memstream` alternative for cross-platform support
+- CMake-based CI workflow with improved matrix coverage
+- Emscripten platform detection for `endian.h`
+
+### Changed
+
+- libclang now defaults to OFF (will be enabled when reflection features are ready)
+- Document start token is now preserved (may contain comments)
+- Walk methods now handle error paths more systematically
+- Removed non-existent experimental function declarations from `libfyaml.h`
+
+### Fixed
+
+- **#193**: Token creation now properly clears memory to avoid undefined behavior on invalid input
+- **#186**: Reference loop nesting now respected when checking link validity
+- **#185**: Fixed crash when setting document root to NULL; also fixed input size clamping for corrupted input
+- **#184**: Walk memory leak fix with improved debugging infrastructure
+- **#183, #191**: Error out early on `FYECF_EXTENDED_CFG` with helper emit methods (prevents crash)
+- **#182**: Walk expression unref bug fix with debug infrastructure
+- **#181**: Walk double-free on node delete
+- **#178, #177**: Walk methods now handle error paths systematically (recursive alias resolution)
+- **#176**: Off-by-one error in `fy_accel_grow`
+- **#175**: Parser crash on corrupted UTF-8 at end of file
+- **#174**: Superfluous document end marker with explicit version/tag directives
+- **#173, #172**: Depth limit for node copy (prevents stack overflow under fuzzing)
+- **#143**: Document root now correctly marked as attached
+- Emit state now properly reset at end of document (fixes multi-document stream markers)
+- Flow quoting error on ANY style (test was backwards)
+- Empty file `fdopen` issue on some platforms
+- Empty stream `realloc(0)` undefined behavior
+- Removed jarring notice when alias is declared multiple times (valid YAML)
+
+### Platform Support
+
+**Supported platforms**: Linux, macOS, FreeBSD, OpenBSD, NetBSD, and **Windows**.
+
+**Windows-specific:**
+- Full native MSVC support (32-bit and 64-bit)
+- clang-cl and Clang cross-compilation support
+- msvc-wine support for Linux-based Windows cross-compilation
+- Proper CRLF (DOS line ending) handling
+- Fixed 32-bit MSVC intrinsics (`_BitScanForward64`, `_BitScanReverse64`, `__popcnt64`)
+
+**Portability fixes:**
+- Fixed void pointer arithmetic (GCC extension) for strict C compliance
+- Fixed GCC ternary operator extension (`x ? : y` -> `x ? x : y`)
+- Fixed `\e` escape sequence (GCC/clang extension) -> `\x1b`
+- Fixed enum comparison warnings across platforms
+- Align mremap initial size to page boundary (fixes BSD crashes)
+
+**macOS:**
+- Fixed ASAN support (requires `-fsanitize=address` at link time)
+- Added extra ASAN flags for Apple's clang (alloca poisoning disabled)
+
+**CI/Build:**
+- New CMake-based GitHub Actions workflow
+- Improved build matrix coverage
+- Fixed distcheck breakage
+
+### Internal
+
+- Walk expression debug infrastructure for easier debugging
+- Portable `fy_memstream` wrapper for `open_memstream`
+- Use `fy_align_alloc/free` wrappers in allocator
+- Fixed allocator `get_caps` return type (enum, not int)
+- Atomic counter function instead of macro
+- General warning cleanup pass
+
+### Statistics
+
+- 58 commits since v0.9.3
+- 18 bug fix issues closed
+- Full Windows platform support added
+
## [0.9.3] - 2026-01-14
### Added
Initial public release with comprehensive YAML 1.2 support.
+[0.9.4]: https://github.com/pantoniou/libfyaml/compare/v0.9.3...v0.9.4
[0.9.3]: https://github.com/pantoniou/libfyaml/compare/v0.9.2...v0.9.3
[0.9.2]: https://github.com/pantoniou/libfyaml/compare/v0.9.1...v0.9.2
[0.9.1]: https://github.com/pantoniou/libfyaml/compare/v0.9...v0.9.1
-cmake_minimum_required(VERSION 3.10)
+cmake_minimum_required(VERSION 3.14)
if (POLICY CMP0048)
cmake_policy(SET CMP0048 NEW) # Allow project(xxx VERSION a.b.c)
set(VERSION_EXTRA "")
endif()
+# Optional MSVC cross-compilation support via msvc-wine
+# Usage: cmake -DMSVC_WINE_DIR=/path/to/msvc [-DMSVC_WINE_COMPILER=cl|clang-cl|clang] ..
+include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/MSVCCrossCompile.cmake OPTIONAL)
+
project(libfyaml LANGUAGES C ASM VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
# Must use GNUInstallDirs to install libraries into correct locations on all platforms
endif()
# Add libclang libraries
- target_link_libraries(${target_name} ${link_scope} ${LIBCLANG_LIBS})
+ target_link_libraries(${target_name} ${link_scope} ${LIBCLANG_LIBS})
endif()
endmacro()
option(ENABLE_NETWORK "Enable tests requiring network access" ON)
option(ENABLE_DEVMODE "Enable development mode only debugging" OFF)
option(BUILD_TESTING "Build tests" ON)
-option(ENABLE_LIBCLANG "Enable libclang support for reflection" ON)
+option(ENABLE_LIBCLANG "Enable libclang support for reflection" OFF)
# Path to LLVM installation (optional, overrides automatic detection)
set(LLVM_ROOT "" CACHE PATH "Path to LLVM installation directory (e.g., /usr/lib/llvm-15)")
endif()
# Check for required dependencies
-set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
-set(THREADS_PREFER_PTHREAD_FLAG TRUE)
-find_package(Threads REQUIRED)
-if(NOT CMAKE_USE_PTHREADS_INIT)
- message(FATAL_ERROR "Missing required pthread support")
+if(NOT WIN32)
+ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
+ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
+ find_package(Threads REQUIRED)
+ if(NOT CMAKE_USE_PTHREADS_INIT)
+ message(FATAL_ERROR "Missing required pthread support")
+ endif()
+else()
+ # Windows uses native threading APIs
+ set(CMAKE_USE_WIN32_THREADS_INIT TRUE)
+endif()
+
+# detect if we're on clang-cl
+if(WIN32 AND MSVC AND CMAKE_C_COMPILER_ID STREQUAL "Clang")
+ set(CLANG_CL TRUE)
endif()
# Check for headers and functions
int main() { return 0; }
" HAVE_DECL_ENVIRON)
+# find PkgConfig
+if(NOT CMAKE_CROSSCOMPILING)
+ find_package(PkgConfig)
+endif()
+
# Check for optional dependencies
# libyaml detection - try CMake config first, then pkg-config
set(LIBYAML_LIBRARIES yaml)
message(STATUS "Found libyaml via CMake config")
else()
- find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(LIBYAML yaml-0.1)
if(LIBYAML_FOUND)
endif()
endif()
-# check framework detection - try CMake config first, then pkg-config
+# check framework detection - try CMake config first, then pkg-config, then FetchContent
set(HAVE_CHECK 0)
set(HAVE_COMPATIBLE_CHECK 0)
-if(BUILD_TESTING)
+if(BUILD_TESTING AND NOT CMAKE_CROSSCOMPILING)
find_package(check QUIET CONFIG)
if(check_FOUND)
set(HAVE_CHECK 1)
endif()
else()
# Fall back to pkg-config
- find_package(PkgConfig)
if(PKG_CONFIG_FOUND)
pkg_check_modules(CHECK check)
if(CHECK_FOUND)
endif()
endif()
endif()
+
+ # Fall back to FetchContent if check not found (useful on Windows)
+ if(NOT HAVE_CHECK)
+ include(FetchContent)
+ message(STATUS "check framework not found, fetching via FetchContent...")
+ FetchContent_Declare(
+ check
+ GIT_REPOSITORY https://github.com/libcheck/check.git
+ GIT_TAG 0.15.2
+ )
+ # Disable check's own tests and docs
+ set(CHECK_ENABLE_TESTS OFF CACHE BOOL "" FORCE)
+ set(CHECK_ENABLE_GCOV OFF CACHE BOOL "" FORCE)
+ FetchContent_MakeAvailable(check)
+
+ set(HAVE_CHECK 1)
+ set(CHECK_LIBRARIES check)
+ set(CHECK_INCLUDE_DIRS "${check_SOURCE_DIR}/src" "${check_BINARY_DIR}" "${check_BINARY_DIR}/src")
+ set(HAVE_SRUNNER_SET_TAP 1) # 0.15.2 has srunner_set_tap
+ set(HAVE_COMPATIBLE_CHECK 1)
+ message(STATUS "Found check framework via FetchContent")
+ endif()
endif()
# Check for libclang (for reflection support)
endif() # ENABLE_LIBCLANG
+# check for bash
+find_program(BASH_EXECUTABLE bash)
+if(BASH_EXECUTABLE)
+ set(HAVE_BASH 1)
+else()
+ set(HAVE_BASH 0)
+endif()
+
# Check for tools
find_program(GIT_EXECUTABLE git)
if(GIT_EXECUTABLE)
set(HAVE_DOCKER 0)
endif()
-# Test suite URLs
+# Test suite URLs and commits
if(NOT TESTSUITEURL)
set(TESTSUITEURL "https://github.com/yaml/yaml-test-suite")
endif()
set(JSONTESTSUITECHECKOUT "d64aefb55228d9584d3e5b2433f720ea8fd00c82")
endif()
+# FetchContent for test suites (downloaded at configure time when network is available)
+include(FetchContent)
+if(ENABLE_NETWORK)
+ FetchContent_Declare(
+ yaml_test_suite
+ GIT_REPOSITORY ${TESTSUITEURL}
+ GIT_TAG ${TESTSUITECHECKOUT}
+ GIT_SHALLOW TRUE
+ )
+ FetchContent_Declare(
+ json_test_suite
+ GIT_REPOSITORY ${JSONTESTSUITEURL}
+ GIT_TAG ${JSONTESTSUITECHECKOUT}
+ GIT_SHALLOW FALSE
+ )
+endif()
+
# SIMD capability detection
set(TARGET_HAS_SSE2 FALSE)
set(TARGET_HAS_SSE41 FALSE)
set(TARGET_HAS_AVX512 FALSE)
set(TARGET_HAS_NEON FALSE)
-if(TARGET_CPU_ANY_X86 AND NOT ENABLE_PORTABLE_TARGET)
+# Disable SIMD assembly on Windows (uses Unix assembly syntax)
+# Use portable implementations instead
+if(WIN32)
+ message(STATUS "Windows detected: using portable SIMD implementations")
+elseif(TARGET_CPU_ANY_X86 AND NOT ENABLE_PORTABLE_TARGET)
check_c_source_compiles("
#include <emmintrin.h>
int main() { __m128i a = _mm_setzero_si128(); return 0; }
endif()
endif()
+set(ASAN_C_FLAGS)
+if(HAVE_ASAN)
+ set(ASAN_C_FLAGS "-fsanitize=address" "-fno-omit-frame-pointer")
+endif()
+
# Build common compiler flags for all targets
set(COMMON_C_FLAGS)
-set(COMMON_C_DEFINITIONS _GNU_SOURCE)
+if(WIN32)
+ set(COMMON_C_DEFINITIONS WIN32_LEAN_AND_MEAN _CRT_SECURE_NO_WARNINGS)
+else()
+ set(COMMON_C_DEFINITIONS _GNU_SOURCE)
+endif()
+
+# MSVC requires C11 for stdatomic.h
+if(MSVC)
+ # Use /std:c17 for better C11/C17 support in MSVC
+ set(CMAKE_C_STANDARD 17)
+ set(CMAKE_C_STANDARD_REQUIRED ON)
+
+ # Enable experimental C11 atomics in MSVC (only)
+ if(NOT CLANG_CL)
+ add_compile_options(/experimental:c11atomics)
+ endif()
+endif()
if(NOT MSVC)
list(APPEND COMMON_C_FLAGS -Wall -Wsign-compare)
# the options for the libs
set(LIB_OPTS "")
-if(BUILD_SHARED_LIBS)
- list(APPEND LIB_OPTS "-fPIC")
+if(NOT MSVC AND NOT WIN32)
+ if(BUILD_SHARED_LIBS)
+ list(APPEND LIB_OPTS "-fPIC")
+ endif()
endif()
# Network tests
src/util/fy-align.h
src/util/fy-bit64.h
src/util/fy-vlsize.h
+ src/util/fy-win32.h
)
set(LIBSRCS
target_sources(fyaml PRIVATE $<TARGET_OBJECTS:${blake3_target}>)
endforeach()
+# On Windows, use a .def file to export only the public API symbols
+# This is needed because libfyaml uses GCC-style suffix attributes for FY_EXPORT
+# which are incompatible with MSVC's __declspec prefix requirement
+if(WIN32 AND BUILD_SHARED_LIBS)
+ # Generate the .def file from the public header during build
+ set(GENERATED_DEF_FILE "${CMAKE_CURRENT_BINARY_DIR}/fyaml.def")
+ add_custom_command(
+ OUTPUT ${GENERATED_DEF_FILE}
+ COMMAND ${CMAKE_COMMAND}
+ -DINPUT_HEADER=${CMAKE_CURRENT_SOURCE_DIR}/include/libfyaml.h
+ -DOUTPUT_DEF=${GENERATED_DEF_FILE}
+ -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/generate-def.cmake
+ DEPENDS
+ ${CMAKE_CURRENT_SOURCE_DIR}/include/libfyaml.h
+ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/generate-def.cmake
+ COMMENT "Generating fyaml.def from libfyaml.h"
+ )
+ target_sources(fyaml PRIVATE "${GENERATED_DEF_FILE}")
+endif()
+
add_library(libfyaml::libfyaml ALIAS fyaml)
# Always build a static library for internal tools (they need access to internal APIs)
${CMAKE_CURRENT_BINARY_DIR}
)
-target_link_libraries(fyaml_static
- PUBLIC
- Threads::Threads
-)
+if(NOT WIN32)
+ target_link_libraries(fyaml_static
+ PUBLIC
+ Threads::Threads
+ )
+endif()
# Add libclang support if available
add_libclang_to_target(fyaml_static INTERFACE)
endif()
if(HAVE_ASAN)
- target_compile_options(fyaml_static PRIVATE -fsanitize=address -fno-omit-frame-pointer)
+ target_compile_options(fyaml_static PRIVATE ${ASAN_C_FLAGS})
# Don't add link options here - executables will link dynamically against libasan
endif()
endif()
${CMAKE_CURRENT_SOURCE_DIR}/src/thread
${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
${CMAKE_CURRENT_SOURCE_DIR}/src/blake3
- ${CMAKE_CURRENT_SOURCE_DIR}/src/generic
- ${CMAKE_CURRENT_SOURCE_DIR}/src/reflection
)
-target_link_libraries(fyaml
- PUBLIC
- Threads::Threads
-)
+if(NOT WIN32)
+ target_link_libraries(fyaml
+ PUBLIC
+ Threads::Threads
+ )
+else()
+ # Windows needs no extra libraries for threading (uses kernel32)
+endif()
# Add libclang support if available
add_libclang_to_target(fyaml PRIVATE)
-# Generate config.h
-configure_file(
- ${CMAKE_SOURCE_DIR}/cmake/config.h.in
- ${CMAKE_BINARY_DIR}/config.h
-)
-
# Generate config.h
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/config.h.in"
target_compile_definitions(fyaml PRIVATE ${COMMON_C_DEFINITIONS})
target_compile_options(fyaml PRIVATE ${COMMON_C_FLAGS})
-# Shared options between GCC and CLANG
-if(NOT MSVC)
- target_compile_options(fyaml PRIVATE ${LIB_OPTS})
+# Shared options between GCC and CLANG (skip for Windows cross-compilation)
+if(NOT MSVC AND NOT WIN32)
target_compile_options(fyaml PRIVATE -fvisibility=hidden)
+ if(BUILD_SHARED_LIBS)
+ target_compile_options(fyaml PRIVATE -fPIC)
+ endif()
+
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
target_compile_options(fyaml PRIVATE -O2)
endif()
if(HAVE_ASAN)
- target_compile_options(fyaml PRIVATE -fsanitize=address -fno-omit-frame-pointer)
+ target_compile_options(fyaml PRIVATE ${ASAN_C_FLAGS} -fno-omit-frame-pointer)
# Use INTERFACE to propagate link flags to executables linking against this library
- target_link_options(fyaml INTERFACE -fsanitize=address)
+ target_link_options(fyaml PRIVATE ${ASAN_C_FLAGS} INTERFACE ${ASAN_C_FLAGS})
endif()
endif()
+# on windows we need a fall-back getopt
+if(WIN32)
+ set(GETOPT_SOURCES src/getopt/getopt.c)
+ set(GETOPT_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/src/getopt")
+else()
+ set(GETOPT_SOURCES)
+ set(GETOPT_INCLUDES)
+endif()
+
# Build fy-tool
-add_executable(fy-tool
+set(FY_TOOL_SOURCES
src/tool/fy-tool.c
src/tool/fy-tool-util.c
src/tool/fy-tool-dump.c
- src/valgrind/fy-valgrind.h
+ ${GETOPT_SOURCES}
)
-target_include_directories(fy-tool PRIVATE
+set(FY_TOOL_INCLUDE_DIRS
${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
+ ${GETOPT_INCLUDES}
)
+if(WIN32)
+ list(APPEND FY_TOOL_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/src/util")
+endif()
+
+add_executable(fy-tool ${FY_TOOL_SOURCES})
+target_include_directories(fy-tool PRIVATE ${FY_TOOL_INCLUDE_DIRS})
+target_compile_definitions(fy-tool PRIVATE ${COMMON_C_DEFINITIONS})
+
target_link_libraries(fy-tool PRIVATE fyaml)
if(ENABLE_STATIC_TOOLS AND NOT MSVC)
# System libraries are dynamically linked (works with or without ASAN)
# Skip when cross-compiling since these tools cannot be executed on build host
-if(NOT CROSS_COMPILING)
+set(INTERNAL_TOOL_INCLUDES
+ ${CMAKE_CURRENT_SOURCE_DIR}/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/util
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/xxhash
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/thread
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${LIBYAML_INCLUDE_DIRS}
+ ${GETOPT_INCLUDES}
+)
# libfyaml-parser requires libyaml
if(HAVE_LIBYAML)
add_executable(libfyaml-parser
src/internal/libfyaml-parser.c
- src/valgrind/fy-valgrind.h
+ ${GETOPT_SOURCES}
)
target_compile_definitions(libfyaml-parser PRIVATE ${COMMON_C_DEFINITIONS})
target_compile_options(libfyaml-parser PRIVATE ${COMMON_C_FLAGS})
- target_include_directories(libfyaml-parser PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
- ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util
- ${CMAKE_CURRENT_SOURCE_DIR}/src/xxhash
- ${CMAKE_CURRENT_SOURCE_DIR}/src/thread
- ${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
- ${CMAKE_CURRENT_BINARY_DIR}
- ${LIBYAML_INCLUDE_DIRS}
- )
+ target_include_directories(libfyaml-parser PRIVATE ${INTERNAL_TOOL_INCLUDES})
target_link_directories(libfyaml-parser PRIVATE ${LIBYAML_LIBRARY_DIRS})
if(NOT MSVC)
# Embed libfyaml code statically, allow dynamic linking for system libraries
)
endif()
if(HAVE_ASAN)
- target_link_options(libfyaml-parser PRIVATE -fsanitize=address)
+ target_link_options(libfyaml-parser PRIVATE ${ASAN_C_FLAGS})
endif()
else()
target_link_libraries(libfyaml-parser PRIVATE fyaml_static ${LIBYAML_LIBRARIES})
add_executable(fy-thread
src/internal/fy-thread.c
- src/valgrind/fy-valgrind.h
-)
-target_include_directories(fy-thread PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
- ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util
- ${CMAKE_CURRENT_SOURCE_DIR}/src/thread
- ${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${GETOPT_SOURCES}
)
+target_include_directories(fy-thread PRIVATE ${INTERNAL_TOOL_INCLUDES})
+target_compile_definitions(fy-thread PRIVATE
+ ${COMMON_C_DEFINITIONS}
+ FY_STATIC)
if(NOT MSVC)
if(APPLE)
target_link_libraries(fy-thread PRIVATE
)
endif()
if(HAVE_ASAN)
- target_link_options(fy-thread PRIVATE -fsanitize=address)
+ target_link_options(fy-thread PRIVATE ${ASAN_C_FLAGS})
endif()
else()
target_link_libraries(fy-thread PRIVATE fyaml_static)
add_executable(fy-b3sum
src/internal/fy-b3sum.c
- src/valgrind/fy-valgrind.h
+ ${GETOPT_SOURCES}
)
target_include_directories(fy-b3sum PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
- ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util
${CMAKE_CURRENT_SOURCE_DIR}/src/blake3
- ${CMAKE_CURRENT_SOURCE_DIR}/src/thread
- ${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${INTERNAL_TOOL_INCLUDES}
)
+target_compile_definitions(fy-b3sum PRIVATE
+ ${COMMON_C_DEFINITIONS}
+ FY_STATIC)
if(NOT MSVC)
if(APPLE)
target_link_libraries(fy-b3sum PRIVATE
)
endif()
if(HAVE_ASAN)
- target_link_options(fy-b3sum PRIVATE -fsanitize=address)
+ target_link_options(fy-b3sum PRIVATE ${ASAN_C_FLAGS})
endif()
else()
target_link_libraries(fy-b3sum PRIVATE fyaml_static)
add_executable(fy-allocators
src/internal/fy-allocators.c
- src/valgrind/fy-valgrind.h
-)
-target_include_directories(fy-allocators PRIVATE
- ${CMAKE_CURRENT_SOURCE_DIR}/include
- ${CMAKE_CURRENT_SOURCE_DIR}/src/valgrind
- ${CMAKE_CURRENT_SOURCE_DIR}/src/lib
- ${CMAKE_CURRENT_SOURCE_DIR}/src/util
- ${CMAKE_CURRENT_SOURCE_DIR}/src/xxhash
- ${CMAKE_CURRENT_SOURCE_DIR}/src/thread
- ${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
- ${CMAKE_CURRENT_BINARY_DIR}
+ ${GETOPT_SOURCES}
)
+target_include_directories(fy-allocators PRIVATE ${INTERNAL_TOOL_INCLUDES})
+target_compile_definitions(fy-allocators PRIVATE
+ ${COMMON_C_DEFINITIONS}
+ FY_STATIC)
if(NOT MSVC)
if(APPLE)
target_link_libraries(fy-allocators PRIVATE
)
endif()
if(HAVE_ASAN)
- target_link_options(fy-allocators PRIVATE -fsanitize=address)
+ target_link_options(fy-allocators PRIVATE ${ASAN_C_FLAGS})
endif()
else()
target_link_libraries(fy-allocators PRIVATE fyaml_static)
endif()
add_dependencies(fy-allocators fyaml_static)
-endif() # NOT CROSS_COMPILING (internal tools)
+if(BUILD_TESTING AND NOT CROSS_COMPILING AND HAVE_CHECK AND HAVE_BASH)
+ set(CAN_TEST 1)
+else()
+ set(CAN_TEST 0)
+endif()
# Testing
-if(BUILD_TESTING AND NOT CROSS_COMPILING)
+if(CAN_TEST)
# Include TAP subtest registration functions
include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/add-tap-subtests.cmake)
# Create src directory for compatibility with test scripts
# Tests expect tools at build/src/
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/src)
- add_custom_command(TARGET fy-tool POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/fy-tool
- ${CMAKE_CURRENT_BINARY_DIR}/src/fy-tool
- COMMENT "Creating symlink for test compatibility"
- )
-
- # Create symlinks for internal tools
- add_custom_command(TARGET fy-thread POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/fy-thread
- ${CMAKE_CURRENT_BINARY_DIR}/src/fy-thread
- )
- add_custom_command(TARGET fy-b3sum POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/fy-b3sum
- ${CMAKE_CURRENT_BINARY_DIR}/src/fy-b3sum
- )
- add_custom_command(TARGET fy-allocators POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/fy-allocators
- ${CMAKE_CURRENT_BINARY_DIR}/src/fy-allocators
- )
- if(HAVE_LIBYAML)
- add_custom_command(TARGET libfyaml-parser POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E create_symlink
- ${CMAKE_CURRENT_BINARY_DIR}/libfyaml-parser
- ${CMAKE_CURRENT_BINARY_DIR}/src/libfyaml-parser
- )
- endif()
# Build libfyaml-test if check is available
if(HAVE_COMPATIBLE_CHECK)
test/libfyaml-test-private-id.c
test/libfyaml-test-parser.c
test/libfyaml-test-thread.c
+ ${GETOPT_SOURCES}
)
target_compile_options(libfyaml-test PRIVATE ${COMMON_C_FLAGS})
${CMAKE_CURRENT_SOURCE_DIR}/src/allocator
${CMAKE_CURRENT_BINARY_DIR}
${CHECK_INCLUDE_DIRS}
+ ${GETOPT_INCLUDES}
)
# Link against static library to access private symbols
)
endif()
if(HAVE_ASAN)
- target_link_options(libfyaml-test PRIVATE -fsanitize=address)
+ target_link_options(libfyaml-test PRIVATE ${ASAN_C_FLAGS})
endif()
else()
target_link_libraries(libfyaml-test PRIVATE fyaml_static ${CHECK_LIBRARIES})
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
)
- # Add libfyaml.test
+ # Add the libfyaml-test binary as the libfyaml test
add_test(NAME libfyaml
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test/libfyaml.test
+ COMMAND $<TARGET_FILE:libfyaml-test>
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
)
- set_tests_properties(libfyaml PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test"
- )
endif()
# Error tests - register individual subtests
add_testemitter_tests(testemitter-streaming "--streaming")
add_testemitter_tests(testemitter-restreaming "--streaming --recreating")
- # Network and git-dependent tests
- if(HAVE_NETWORK AND HAVE_GIT)
- # YAML test suite - setup fixture
- add_test(NAME yaml-test-suite-setup
- COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR}/test
- ${CMAKE_COMMAND}
- -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
- -DTESTSUITEURL=${TESTSUITEURL}
- -DTESTSUITECHECKOUT=${TESTSUITECHECKOUT}
- -DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/test
- -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/setup-yaml-test-suite.cmake
- )
- set_tests_properties(yaml-test-suite-setup PROPERTIES
- FIXTURES_SETUP yaml-test-suite-data
- )
+ # Network-dependent tests using FetchContent
+ if(HAVE_NETWORK)
+ # Download test suites at configure time via FetchContent
+ message(STATUS "Fetching YAML test suite...")
+ FetchContent_MakeAvailable(yaml_test_suite)
+ message(STATUS "Fetching JSON test suite...")
+ FetchContent_MakeAvailable(json_test_suite)
# YAML test suite tests - register individual subtests
- # Three modes (handled automatically by add_testsuite_tests):
- # 1. If test-suite-data exists: scan filesystem and register tests
- # 2. If cmake/testsuite-tests.cmake exists: use pre-generated list
- # 3. Otherwise: use monolithic test (re-run cmake after downloading data)
- # To generate cmake/testsuite-tests.cmake, see cmake/README-testsuite-generation.md
+ # Two modes (handled automatically by add_testsuite_tests):
+ # 1. If test-suite-data exists (via FetchContent symlink): scan filesystem
+ # 2. If cmake/testsuite-tests.cmake exists: use pre-generated list (offline builds)
add_testsuite_tests(testsuite testsuite.test)
add_testsuite_tests(testsuite-evstream testsuite-evstream.test)
add_testsuite_tests(testsuite-resolution testsuite-resolution.test)
add_testsuite_tests(testsuite-json testsuite-json.test)
endif()
- # JSON test suite - setup fixture
- add_test(NAME json-test-suite-setup
- COMMAND ${CMAKE_COMMAND} -E chdir ${CMAKE_CURRENT_BINARY_DIR}/test
- ${CMAKE_COMMAND}
- -DGIT_EXECUTABLE=${GIT_EXECUTABLE}
- -DTESTSUITEURL=${JSONTESTSUITEURL}
- -DTESTSUITECHECKOUT=${JSONTESTSUITECHECKOUT}
- -DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/test
- -DREPO_NAME=json-test-suite-data
- -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/setup-yaml-test-suite.cmake
- )
- set_tests_properties(json-test-suite-setup PROPERTIES
- FIXTURES_SETUP json-test-suite-data
- )
-
# JSON test suite - register individual subtests
- # Three modes (handled automatically by add_jsontestsuite_tests):
- # 1. If json-test-suite-data exists: scan filesystem and register tests
- # 2. If cmake/jsontestsuite-tests.cmake exists: use pre-generated list
- # 3. Otherwise: use monolithic test (re-run cmake after downloading data)
- # To generate cmake/jsontestsuite-tests.cmake, see cmake/README-testsuite-generation.md
add_jsontestsuite_tests()
endif()
- set(TEST_DRIVER ${CMAKE_SOURCE_DIR}/build-aux/tap-driver.sh)
-
# Build all test dependencies as part of default 'all' target
# Note: CMake's 'make test' target doesn't trigger builds by design.
# Use 'make all test' or 'make check-am' or 'make build_and_test' for complete workflow.
list(APPEND TEST_DEPENDENCIES libfyaml-parser)
endif()
- add_custom_target(build_tests ALL
- DEPENDS ${TEST_DEPENDENCIES}
- COMMENT "Building test dependencies"
- )
-
- # Convenience target that builds and runs tests in one command
- add_custom_target(build_and_test
- COMMAND ${CMAKE_CTEST_COMMAND}
- DEPENDS ${TEST_DEPENDENCIES}
- COMMENT "Building and running tests"
- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
- )
-
- # Autotools-compatible test runner using test-driver
- # NOTE: Named 'check-am' instead of 'check' to avoid conflicts with check library target
- add_custom_target(check-am
- COMMENT "Running tests via Automake test-driver"
- )
-
- if(HAVE_COMPATIBLE_CHECK)
- set(TEST_EXECUTABLES
- libfyaml-test
- )
-
- foreach(exe IN LISTS TEST_EXECUTABLES)
- add_custom_target(check_${exe}
- COMMAND ${CMAKE_COMMAND} -E env TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR} TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR} SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test
- ${TEST_DRIVER}
- --test-name ${exe}
- --log-file ${exe}.log
- --trs-file ${exe}.trs
- --comments
- --color-tests yes
- --expect-failure 0
- -- ${CMAKE_CURRENT_BINARY_DIR}/test/${exe}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- COMMENT "Running ${exe}"
- )
- add_dependencies(check_${exe} ${exe})
- add_dependencies(check-am check_${exe})
- endforeach()
- endif()
-
set(TEST_SUITES
testsuite.test
jsontestsuite.test
list(APPEND TEST_SUITES testsuite-json.test)
endif()
- if(HAVE_LIBCLANG)
- list(APPEND TEST_SUITES testreflection.test)
- endif()
-
- foreach(suite IN LISTS TEST_SUITES)
- add_custom_target(check_${suite}
- COMMAND ${CMAKE_COMMAND} -E env TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR} TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR} SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test
- ${TEST_DRIVER}
- --test-name ${suite}
- --log-file ${suite}.log
- --trs-file ${suite}.trs
- --comments
- --color-tests yes
- --expect-failure 0
- -- ${CMAKE_SOURCE_DIR}/test/${suite}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- COMMENT "Running ${suite}"
- )
- add_dependencies(check_${suite} fy-tool)
- add_dependencies(check-am check_${suite})
- endforeach()
-
endif()
# Documentation
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)
-# Create symlinks for fy-tool
-install(CODE "
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-dump WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-filter WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-testsuite WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-join WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-ypath WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
- execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-compose WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
-")
+# Create symlinks for fy-tool (not on Windows - symlinks require special privileges)
+if(NOT WIN32)
+ install(CODE "
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-dump WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-filter WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-testsuite WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-join WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-ypath WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ execute_process(COMMAND ${CMAKE_COMMAND} -E create_symlink fy-tool fy-compose WORKING_DIRECTORY \${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+ ")
+endif()
install(EXPORT libfyaml-targets
FILE libfyaml-targets.cmake
message(STATUS "Cross compiling: ${CROSS_COMPILING}")
message(STATUS "C compiler: ${CMAKE_C_COMPILER}")
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
+message(STATUS "HAVE_BASH: ${HAVE_BASH}")
message(STATUS "HAVE_CHECK: ${HAVE_CHECK}")
message(STATUS "HAVE_COMPATIBLE_CHECK: ${HAVE_COMPATIBLE_CHECK}")
message(STATUS "HAVE_LIBYAML: ${HAVE_LIBYAML}")
message(STATUS "TESTSUITECHECKOUT: ${TESTSUITECHECKOUT}")
message(STATUS "JSONTESTSUITEURL: ${JSONTESTSUITEURL}")
message(STATUS "JSONTESTSUITECHECKOUT: ${JSONTESTSUITECHECKOUT}")
+message(STATUS "CAN_TEST: ${CAN_TEST}")
message(STATUS "")
-if(BUILD_TESTING AND NOT CROSS_COMPILING)
- message(STATUS "Test targets:")
- message(STATUS " make all test - Build everything then run CTest (2464 individual tests)")
- message(STATUS " make build_and_test - Convenience target: build and test in one command")
- message(STATUS " make check-am - Autotools-compatible TAP test runner (~10 test scripts)")
- message(STATUS "")
- message(STATUS "NOTE: 'make test' alone will fail if binaries aren't built. Use 'make all test'.")
- message(STATUS "")
-elseif(CROSS_COMPILING)
+if(CROSS_COMPILING)
message(STATUS "Tests disabled when cross-compiling (target binaries cannot execute on build host)")
message(STATUS "")
endif()
echo $(VERSION) > .tarball-version
# files to keep in the distribution (in case you want to boostrap)
-EXTRA_DIST=bootstrap.sh \
- build-aux/shave.in build-aux/shave-libtool.in \
- build-aux/git-version-gen \
- README.md LICENSE \
- Dockerfile Dockerfile-build-deb \
- Dockerfile.alpine Dockerfile.centos \
- cmake CMakeLists.txt \
- examples
+EXTRA_DIST = \
+ .dockerignore \
+ .github/workflows/ci.yaml \
+ .gitignore \
+ .libtool-version \
+ AUTHORS \
+ CHANGELOG.md \
+ CMakeLists.txt \
+ Dockerfile \
+ Dockerfile-build-deb \
+ Dockerfile.alpine \
+ Dockerfile.centos \
+ LICENSE \
+ Makefile.am \
+ README.md \
+ bootstrap.sh \
+ build-aux/git-version-gen \
+ build-aux/shave-libtool.in \
+ build-aux/shave.in \
+ cmake/CheckClangBlocks.cmake \
+ cmake/CheckLibClang.cmake \
+ cmake/MSVCCrossCompile.cmake \
+ cmake/add-tap-subtests.cmake \
+ cmake/clang-windows-toolchain.cmake \
+ cmake/config.h.in \
+ cmake/fyaml-config.cmake.in \
+ cmake/generate-def.cmake \
+ cmake/generate-jsontestsuite-list.sh \
+ cmake/generate-testsuite-list.sh \
+ cmake/libfyaml-config.cmake.in \
+ cmake/libfyaml.pc.in \
+ cmake/run-single-tap-test.sh \
+ cmake/tags.cmake \
+ examples/CMakeLists.txt \
+ examples/README.md \
+ examples/basic-parsing.c \
+ examples/build-from-scratch.c \
+ examples/config.yaml \
+ examples/document-manipulation.c \
+ examples/event-streaming.c \
+ examples/invoice.yaml \
+ examples/path-queries.c \
+ examples/quick-start.c \
+ libfyaml.pc.in \
+ m4/ax_check_compile_flag.m4 \
+ m4/ax_check_define.m4 \
+ m4/ax_check_enable_debug.m4 \
+ m4/ax_check_flag.m4 \
+ m4/ax_cxx_compile_stdcxx.m4 \
+ m4/ax_cxx_compile_stdcxx_11.m4 \
+ m4/ax_define_dir.m4 \
+ m4/ax_is_release.m4 \
+ m4/ax_pthread.m4 \
+ m4/ax_tls.m4 \
+ m4/shave.m4
MAINTAINERCLEANFILES = \
Makefile.in src/Makefile.in config.h.in configure \
# extra file to put in the distribution
EXTRA_DIST += \
scripts/create-virtual-env \
+ scripts/get-gpg-key-id-by-email.sh \
scripts/install-linuxdoc.sh \
scripts/run-check-errors.sh \
scripts/run-compare-dump.sh \
# libfyaml
-[](https://github.com/pantoniou/libfyaml/actions)
+[](https://github.com/pantoniou/libfyaml/actions?query=workflow%3A%22Standard+Automake+CI%22)
+[](https://github.com/pantoniou/libfyaml/actions?query=workflow%3A%22CMake+CI%22)
[](https://opensource.org/licenses/MIT)
[](https://en.wikipedia.org/wiki/C_(programming_language))
## Platform Support
-**Primary Platform**: Linux (Debian/Ubuntu, Fedora, Arch, etc.)
-**Also Supported**: macOS (via Homebrew)
-**Not Yet Supported**: Windows (contributions welcome!)
+**Natively Supported Platforms**:
+- Linux (Debian/Ubuntu, Fedora, Arch, Alpine, RHEL/Rocky, etc.)
+- macOS (Xcode, Homebrew)
+- Windows (native MSVC, clang-cl, Clang)
+- FreeBSD, NetBSD, OpenBSD
-**Architectures**: x86, x86_64, ARM, ARM64, and others
-**Compilers**: GCC, Clang, ICC
+**Architectures**: x86, x86_64, ARM, ARM64 are tested in CI, but we are portable, all should work as
+long as Linux support is available.
+
+**Compilers**:
+- GCC
+- Clang
+- MSVC (native Windows)
+- clang-cl (Windows)
+- Xcode (macOS)
+
+**Special windows cross-compilation support**:
+- Windows targets via Wine + MSVC
+- Windows targets via clang-cl cross-compile
+- Windows targets via Clang cross-compile
---
## Missing Features
Current limitations:
-- **Windows support**: Not yet implemented (contributions welcome)
- **Unicode**: UTF-8 only, no wide character input support
---
--- /dev/null
+# MSVCCrossCompile.cmake - Auto-configure MSVC cross-compilation from msvc-wine
+#
+# Usage: Set MSVC_WINE_DIR to the msvc-wine installation directory, then include
+# this file before project(). The module will auto-detect versions and set up
+# the environment.
+#
+# Options:
+# MSVC_WINE_DIR - Path to msvc-wine installation (required)
+# MSVC_WINE_COMPILER - Compiler to use: "cl" (Wine) or "clang-cl" (default: cl)
+# MSVC_WINE_ARCH - Target architecture: "x64", "x86", "arm64" (default: x64)
+# MSVC_VERSION - Override MSVC toolchain version (auto-detected if not set)
+# WINSDK_VERSION - Override Windows SDK version (auto-detected if not set)
+#
+# Example:
+# cmake -DMSVC_WINE_DIR=/path/to/msvc -DMSVC_WINE_COMPILER=clang-cl ..
+
+if(NOT DEFINED MSVC_WINE_DIR)
+ return()
+endif()
+
+# Normalize path
+get_filename_component(MSVC_WINE_DIR "${MSVC_WINE_DIR}" ABSOLUTE)
+
+if(NOT EXISTS "${MSVC_WINE_DIR}")
+ message(FATAL_ERROR "MSVC_WINE_DIR does not exist: ${MSVC_WINE_DIR}")
+endif()
+
+# Set defaults
+if(NOT DEFINED MSVC_WINE_COMPILER)
+ set(MSVC_WINE_COMPILER "cl")
+endif()
+
+if(NOT DEFINED MSVC_WINE_ARCH)
+ set(MSVC_WINE_ARCH "x64")
+endif()
+
+# Map architecture to library subdirectory
+if(MSVC_WINE_ARCH STREQUAL "x64")
+ set(_msvc_lib_arch "x64")
+ set(_msvc_bin_arch "x64")
+ set(_clang_triple "x86_64-windows-msvc")
+elseif(MSVC_WINE_ARCH STREQUAL "x86")
+ set(_msvc_lib_arch "x86")
+ set(_msvc_bin_arch "x86")
+ set(_clang_triple "i686-windows-msvc")
+elseif(MSVC_WINE_ARCH STREQUAL "arm64")
+ set(_msvc_lib_arch "arm64")
+ set(_msvc_bin_arch "arm64")
+ set(_clang_triple "aarch64-windows-msvc")
+else()
+ message(FATAL_ERROR "Unsupported MSVC_WINE_ARCH: ${MSVC_WINE_ARCH}")
+endif()
+
+# Auto-detect MSVC version if not specified
+if(NOT DEFINED MSVC_VERSION)
+ file(GLOB _msvc_versions "${MSVC_WINE_DIR}/vc/tools/msvc/*")
+ list(LENGTH _msvc_versions _msvc_version_count)
+ if(_msvc_version_count EQUAL 0)
+ message(FATAL_ERROR "No MSVC toolchain found in ${MSVC_WINE_DIR}/vc/tools/msvc/")
+ endif()
+ # Sort and take the latest version
+ list(SORT _msvc_versions COMPARE NATURAL ORDER DESCENDING)
+ list(GET _msvc_versions 0 _msvc_version_path)
+ get_filename_component(MSVC_VERSION "${_msvc_version_path}" NAME)
+ message(STATUS "Auto-detected MSVC version: ${MSVC_VERSION}")
+endif()
+
+# Auto-detect Windows SDK version if not specified
+if(NOT DEFINED WINSDK_VERSION)
+ file(GLOB _sdk_versions "${MSVC_WINE_DIR}/kits/10/include/*")
+ list(LENGTH _sdk_versions _sdk_version_count)
+ if(_sdk_version_count EQUAL 0)
+ message(FATAL_ERROR "No Windows SDK found in ${MSVC_WINE_DIR}/kits/10/include/")
+ endif()
+ # Sort and take the latest version
+ list(SORT _sdk_versions COMPARE NATURAL ORDER DESCENDING)
+ list(GET _sdk_versions 0 _sdk_version_path)
+ get_filename_component(WINSDK_VERSION "${_sdk_version_path}" NAME)
+ message(STATUS "Auto-detected Windows SDK version: ${WINSDK_VERSION}")
+endif()
+
+# Verify paths exist
+set(_msvc_include "${MSVC_WINE_DIR}/vc/tools/msvc/${MSVC_VERSION}/include")
+set(_msvc_lib "${MSVC_WINE_DIR}/vc/tools/msvc/${MSVC_VERSION}/lib/${_msvc_lib_arch}")
+set(_sdk_include_shared "${MSVC_WINE_DIR}/kits/10/include/${WINSDK_VERSION}/shared")
+set(_sdk_include_ucrt "${MSVC_WINE_DIR}/kits/10/include/${WINSDK_VERSION}/ucrt")
+set(_sdk_include_um "${MSVC_WINE_DIR}/kits/10/include/${WINSDK_VERSION}/um")
+set(_sdk_lib_ucrt "${MSVC_WINE_DIR}/kits/10/lib/${WINSDK_VERSION}/ucrt/${_msvc_lib_arch}")
+set(_sdk_lib_um "${MSVC_WINE_DIR}/kits/10/lib/${WINSDK_VERSION}/um/${_msvc_lib_arch}")
+
+foreach(_path ${_msvc_include} ${_msvc_lib} ${_sdk_include_shared} ${_sdk_include_ucrt} ${_sdk_include_um} ${_sdk_lib_ucrt} ${_sdk_lib_um})
+ if(NOT EXISTS "${_path}")
+ message(FATAL_ERROR "Required path does not exist: ${_path}")
+ endif()
+endforeach()
+
+# Build INCLUDE and LIB paths (semicolon-separated for Windows/MSVC)
+set(MSVC_WINE_INCLUDE "${_msvc_include};${_sdk_include_shared};${_sdk_include_ucrt};${_sdk_include_um}")
+set(MSVC_WINE_LIB "${_msvc_lib};${_sdk_lib_ucrt};${_sdk_lib_um}")
+
+# Build compiler/linker flags for include/lib paths
+# clang-cl uses -imsvc for system includes, regular clang uses -I (not -isystem to avoid replacing builtins)
+set(_include_flags_clangcl "")
+set(_include_flags_clang "")
+foreach(_inc ${_msvc_include} ${_sdk_include_shared} ${_sdk_include_ucrt} ${_sdk_include_um})
+ string(APPEND _include_flags_clangcl " -imsvc \"${_inc}\"")
+ string(APPEND _include_flags_clang " -I\"${_inc}\"")
+endforeach()
+
+# Linker flags: /LIBPATH: for lld-link (clang-cl), -L for regular clang
+set(_lib_flags_lldlink "")
+set(_lib_flags_clang "")
+foreach(_lib ${_msvc_lib} ${_sdk_lib_ucrt} ${_sdk_lib_um})
+ string(APPEND _lib_flags_lldlink " /LIBPATH:\"${_lib}\"")
+ string(APPEND _lib_flags_clang " -L\"${_lib}\"")
+endforeach()
+
+message(STATUS "MSVC cross-compile configuration:")
+message(STATUS " MSVC_WINE_DIR: ${MSVC_WINE_DIR}")
+message(STATUS " MSVC_WINE_COMPILER: ${MSVC_WINE_COMPILER}")
+message(STATUS " MSVC_WINE_ARCH: ${MSVC_WINE_ARCH}")
+message(STATUS " MSVC_VERSION: ${MSVC_VERSION}")
+message(STATUS " WINSDK_VERSION: ${WINSDK_VERSION}")
+
+# Set environment variables for the build (used by cl.exe via Wine)
+set(ENV{INCLUDE} "${MSVC_WINE_INCLUDE}")
+set(ENV{LIB} "${MSVC_WINE_LIB}")
+
+message(STATUS " MSVC_WINE_INCLUDE: ${MSVC_WINE_INCLUDE}")
+message(STATUS " MSVC_WINE_LIB: ${MSVC_WINE_LIB}")
+
+# Configure based on compiler choice
+if(MSVC_WINE_COMPILER STREQUAL "cl")
+ # Use cl.exe via Wine
+ set(_bin_dir "${MSVC_WINE_DIR}/bin/${_msvc_bin_arch}")
+ if(NOT EXISTS "${_bin_dir}/cl")
+ message(FATAL_ERROR "cl wrapper not found in ${_bin_dir}")
+ endif()
+
+ # Default to Release for Wine builds (Debug requires debug runtime DLLs)
+ if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
+ message(STATUS " Defaulting to Release build (Debug requires VCRUNTIME140D.dll)")
+ endif()
+
+ # Prepend to PATH
+ set(ENV{PATH} "${_bin_dir}:$ENV{PATH}")
+
+ set(CMAKE_SYSTEM_NAME Windows CACHE STRING "" FORCE)
+ set(CMAKE_C_COMPILER "${_bin_dir}/cl" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILER "${_bin_dir}/cl" CACHE STRING "" FORCE)
+ set(CMAKE_LINKER "${_bin_dir}/link" CACHE STRING "" FORCE)
+ set(CMAKE_RC_COMPILER "${_bin_dir}/rc" CACHE STRING "" FORCE)
+ set(CMAKE_MT "${_bin_dir}/mt" CACHE STRING "" FORCE)
+
+elseif(MSVC_WINE_COMPILER STREQUAL "clang-cl")
+ # Use clang-cl (native cross-compilation, no Wine needed)
+ # Default to Release (Debug has linker flag issues with lld-link)
+ if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
+ message(STATUS " Defaulting to Release build")
+ endif()
+
+ find_program(CLANG_CL_EXECUTABLE NAMES clang-cl clang-cl-18 clang-cl-17 clang-cl-16 clang-cl-15)
+ if(NOT CLANG_CL_EXECUTABLE)
+ message(FATAL_ERROR "clang-cl not found. Install with: apt install clang")
+ endif()
+
+ find_program(LLD_LINK_EXECUTABLE NAMES lld-link lld-link-18 lld-link-17 lld-link-16 lld-link-15)
+ if(NOT LLD_LINK_EXECUTABLE)
+ message(FATAL_ERROR "lld-link not found. Install with: apt install lld")
+ endif()
+
+ find_program(LLVM_RC_EXECUTABLE NAMES llvm-rc llvm-rc-18 llvm-rc-17 llvm-rc-16 llvm-rc-15)
+ if(NOT LLVM_RC_EXECUTABLE)
+ message(FATAL_ERROR "llvm-rc not found. Install with: apt install llvm")
+ endif()
+
+ find_program(LLVM_MT_EXECUTABLE NAMES llvm-mt llvm-mt-18 llvm-mt-17 llvm-mt-16 llvm-mt-15)
+ if(NOT LLVM_MT_EXECUTABLE)
+ message(FATAL_ERROR "llvm-mt not found. Install with: apt install llvm")
+ endif()
+
+ set(CMAKE_SYSTEM_NAME Windows CACHE STRING "" FORCE)
+ set(CMAKE_C_COMPILER "${CLANG_CL_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILER "${CLANG_CL_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_LINKER "${LLD_LINK_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_RC_COMPILER "${LLVM_RC_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_MT "${LLVM_MT_EXECUTABLE}" CACHE STRING "" FORCE)
+
+ # Pass include paths via compiler flags (env vars don't persist to build)
+ set(CMAKE_C_FLAGS_INIT "${_include_flags_clangcl}" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_FLAGS_INIT "${_include_flags_clangcl}" CACHE STRING "" FORCE)
+ set(CMAKE_EXE_LINKER_FLAGS_INIT "${_lib_flags_lldlink}" CACHE STRING "" FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_INIT "${_lib_flags_lldlink}" CACHE STRING "" FORCE)
+ set(CMAKE_STATIC_LINKER_FLAGS_INIT "" CACHE STRING "" FORCE)
+
+ message(STATUS " Using clang-cl: ${CLANG_CL_EXECUTABLE}")
+ message(STATUS " Using lld-link: ${LLD_LINK_EXECUTABLE}")
+ message(STATUS " Using llvm-rc: ${LLVM_RC_EXECUTABLE}")
+ message(STATUS " Using llvm-mt: ${LLVM_MT_EXECUTABLE}")
+
+elseif(MSVC_WINE_COMPILER STREQUAL "clang")
+ # Use regular clang with Windows target triplet (no Wine needed)
+ # Default to Release
+ if(NOT CMAKE_BUILD_TYPE)
+ set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
+ message(STATUS " Defaulting to Release build")
+ endif()
+
+ # Find clang
+ find_program(CLANG_EXECUTABLE NAMES clang clang-18 clang-17 clang-16 clang-15)
+ if(NOT CLANG_EXECUTABLE)
+ message(FATAL_ERROR "clang not found. Install with: apt install clang")
+ endif()
+
+ find_program(CLANGXX_EXECUTABLE NAMES clang++ clang++-18 clang++-17 clang++-16 clang++-15)
+ if(NOT CLANGXX_EXECUTABLE)
+ message(FATAL_ERROR "clang++ not found. Install with: apt install clang")
+ endif()
+
+ find_program(LLD_LINK_EXECUTABLE NAMES lld-link lld-link-18 lld-link-17 lld-link-16 lld-link-15)
+ if(NOT LLD_LINK_EXECUTABLE)
+ message(FATAL_ERROR "lld-link not found. Install with: apt install lld")
+ endif()
+
+ find_program(LLVM_RC_EXECUTABLE NAMES llvm-rc llvm-rc-18 llvm-rc-17 llvm-rc-16 llvm-rc-15)
+ if(NOT LLVM_RC_EXECUTABLE)
+ message(FATAL_ERROR "llvm-rc not found. Install with: apt install llvm")
+ endif()
+
+ find_program(LLVM_MT_EXECUTABLE NAMES llvm-mt llvm-mt-18 llvm-mt-17 llvm-mt-16 llvm-mt-15)
+ if(NOT LLVM_MT_EXECUTABLE)
+ message(FATAL_ERROR "llvm-mt not found. Install with: apt install llvm")
+ endif()
+
+ set(CMAKE_SYSTEM_NAME Windows CACHE STRING "" FORCE)
+ set(CMAKE_SYSTEM_PROCESSOR AMD64 CACHE STRING "" FORCE)
+ set(CMAKE_C_COMPILER "${CLANG_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILER "${CLANGXX_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_C_COMPILER_TARGET "x86_64-windows-msvc" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILER_TARGET "x86_64-windows-msvc" CACHE STRING "" FORCE)
+ set(CMAKE_LINKER "${LLD_LINK_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_RC_COMPILER "${LLVM_RC_EXECUTABLE}" CACHE STRING "" FORCE)
+ set(CMAKE_MT "${LLVM_MT_EXECUTABLE}" CACHE STRING "" FORCE)
+
+ # Configure linking - clang needs explicit link command for lld-link
+ set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -out:<TARGET> <LINK_LIBRARIES>" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -out:<TARGET> <LINK_LIBRARIES>" CACHE STRING "" FORCE)
+ set(CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_LINKER> -dll <LINK_FLAGS> <OBJECTS> -out:<TARGET> -implib:<TARGET_IMPLIB> <LINK_LIBRARIES>" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_LINKER> -dll <LINK_FLAGS> <OBJECTS> -out:<TARGET> -implib:<TARGET_IMPLIB> <LINK_LIBRARIES>" CACHE STRING "" FORCE)
+
+ # Disable Unix-specific flags
+ set(CMAKE_C_COMPILE_OPTIONS_PIC "" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILE_OPTIONS_PIC "" CACHE STRING "" FORCE)
+ set(CMAKE_SHARED_LIBRARY_C_FLAGS "" CACHE STRING "" FORCE)
+ set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "" CACHE STRING "" FORCE)
+
+ # Use env launcher to set INCLUDE/LIB for each compiler invocation
+ # (clang with MSVC target reads INCLUDE env var, -I flags don't work the same way)
+ string(REPLACE ";" "\\;" _include_env "${MSVC_WINE_INCLUDE}")
+ string(REPLACE ";" "\\;" _lib_env "${MSVC_WINE_LIB}")
+ set(CMAKE_C_COMPILER_LAUNCHER "env" "INCLUDE=${_include_env}" "LIB=${_lib_env}" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_COMPILER_LAUNCHER "env" "INCLUDE=${_include_env}" "LIB=${_lib_env}" CACHE STRING "" FORCE)
+
+ set(CMAKE_C_FLAGS_INIT "-fuse-ld=lld" CACHE STRING "" FORCE)
+ set(CMAKE_CXX_FLAGS_INIT "-fuse-ld=lld" CACHE STRING "" FORCE)
+ set(CMAKE_EXE_LINKER_FLAGS_INIT "${_lib_flags_clang}" CACHE STRING "" FORCE)
+ set(CMAKE_SHARED_LINKER_FLAGS_INIT "${_lib_flags_clang}" CACHE STRING "" FORCE)
+
+ message(STATUS " Using clang: ${CLANG_EXECUTABLE}")
+ message(STATUS " Using lld-link: ${LLD_LINK_EXECUTABLE}")
+ message(STATUS " Using llvm-rc: ${LLVM_RC_EXECUTABLE}")
+ message(STATUS " Using llvm-mt: ${LLVM_MT_EXECUTABLE}")
+
+else()
+ message(FATAL_ERROR "Unknown MSVC_WINE_COMPILER: ${MSVC_WINE_COMPILER} (use 'cl', 'clang-cl', or 'clang')")
+endif()
+
+# Export variables for use in the project
+set(MSVC_WINE_CONFIGURED TRUE CACHE INTERNAL "MSVC Wine cross-compilation configured")
# Helper function to add individual TAP subtests from test scripts
# This mimics the behavior of autotools tap-driver.sh by registering each subtest individually
+# Helper function to add a TAP test with fy-tool path via generator expression
+# This enables proper support for multi-config generators (Visual Studio, Xcode)
+# by passing the actual tool path at runtime rather than relying on hardcoded paths.
+function(add_tap_test test_name suite_name test_id)
+ cmake_parse_arguments(TAP "DISABLED;WILL_FAIL" "" "LABELS;EXTRA_ENV" ${ARGN})
+
+ add_test(
+ NAME "${test_name}"
+ COMMAND "${BASH_EXECUTABLE}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh"
+ "$<TARGET_FILE:fy-tool>"
+ "${suite_name}" "${test_id}"
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
+ )
+
+ # Build environment
+ set(base_env
+ "TEST_DIR=${CMAKE_CURRENT_SOURCE_DIR}/test"
+ "YAML_TEST_SUITE=${yaml_test_suite_SOURCE_DIR}"
+ "JSON_TEST_SUITE=${json_test_suite_SOURCE_DIR}"
+ )
+ if(TAP_EXTRA_ENV)
+ list(APPEND base_env ${TAP_EXTRA_ENV})
+ endif()
+
+ set_tests_properties("${test_name}" PROPERTIES DEPENDS fy-tool)
+
+ set_tests_properties("${test_name}" PROPERTIES ENVIRONMENT "${base_env}")
+
+ if(TAP_LABELS)
+ set_tests_properties("${test_name}" PROPERTIES LABELS "${TAP_LABELS}")
+ endif()
+ if(TAP_DISABLED)
+ set_tests_properties("${test_name}" PROPERTIES DISABLED TRUE)
+ endif()
+ if(TAP_WILL_FAIL)
+ set_tests_properties("${test_name}" PROPERTIES WILL_FAIL TRUE)
+ endif()
+endfunction()
+
+# Helper macro to register a single testsuite test
+# Used by add_testsuite_tests to avoid code duplication
+macro(_register_testsuite_test test_name test_dir test_id skip_list xfail_list extra_env)
+ if(EXISTS "${test_dir}/===")
+ # Read description from === file
+ file(READ "${test_dir}/===" _test_desc)
+ string(STRIP "${_test_desc}" _test_desc)
+
+ # Build test name with description if available
+ if(_test_desc)
+ set(_test_name_full "${test_name}/${test_id} - ${_test_desc}")
+ else()
+ set(_test_name_full "${test_name}/${test_id}")
+ endif()
+
+ # Set basic properties
+ set(_test_labels "${test_name}")
+ set(_test_disabled FALSE)
+
+ # Check if test should be skipped
+ if(test_id IN_LIST skip_list)
+ set(_test_disabled TRUE)
+ set(_test_labels "${test_name};skipped")
+ endif()
+
+ # Check if test is expected to fail (xfail)
+ if(test_id IN_LIST xfail_list)
+ set(_test_labels "${test_name};xfail")
+ endif()
+
+ if(_test_disabled)
+ add_tap_test("${_test_name_full}" "${test_name}" "${test_id}"
+ LABELS "${_test_labels}"
+ EXTRA_ENV "${extra_env}"
+ DISABLED
+ )
+ else()
+ add_tap_test("${_test_name_full}" "${test_name}" "${test_id}"
+ LABELS "${_test_labels}"
+ EXTRA_ENV "${extra_env}"
+ )
+ endif()
+ endif()
+endmacro()
+
# Function to run a single test from testerrors.test
function(add_testerrors_tests)
- file(GLOB error_dirs "${CMAKE_CURRENT_SOURCE_DIR}/test/test-errors/[0-9][0-9][0-9][0-9]")
+ # Use wildcard glob and filter with regex (Windows-compatible)
+ file(GLOB all_dirs "${CMAKE_CURRENT_SOURCE_DIR}/test/test-errors/*")
- foreach(dir ${error_dirs})
+ foreach(dir ${all_dirs})
+ if(NOT IS_DIRECTORY "${dir}")
+ continue()
+ endif()
get_filename_component(test_id "${dir}" NAME)
+ # Filter: must be 4 digits
+ if(NOT test_id MATCHES "^[0-9][0-9][0-9][0-9]$")
+ continue()
+ endif()
# Read description from === file
set(desc_file "${dir}/===")
set(test_name_full "testerrors/${test_id}")
endif()
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- testerrors "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set properties
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test"
+ add_tap_test("${test_name_full}" testerrors "${test_id}"
LABELS "testerrors"
)
endforeach()
foreach(yaml_file ${yaml_files})
get_filename_component(test_id "${yaml_file}" NAME)
- add_test(
- NAME "${test_name}/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- "${test_name}" "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- set_tests_properties("${test_name}/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;EXTRA_DUMP_ARGS=${extra_args}"
+ add_tap_test("${test_name}/${test_id}" "${test_name}" "${test_id}"
LABELS "${test_name}"
+ EXTRA_ENV "EXTRA_DUMP_ARGS=${extra_args}"
)
endforeach()
endfunction()
# Function to add testsuite tests (yaml test suite)
-# Can work either by scanning the test-suite-data directory (if it exists)
-# or by using a pre-generated list of tests from testsuite-tests.cmake
+# Scans test-suite-data directory (populated by FetchContent at configure time)
function(add_testsuite_tests test_name test_script)
- set(test_dir "${CMAKE_CURRENT_BINARY_DIR}/test/test-suite-data")
- set(use_pregenerated_list FALSE)
+ set(test_dir "${yaml_test_suite_SOURCE_DIR}")
# Define skip/xfail lists based on test suite variant
# These match the lists in test/*.test scripts
set(xfail_list "")
endif()
- # Check if we should use the pre-generated list
- if(NOT EXISTS "${test_dir}")
- # Try to use pre-generated list if available
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/testsuite-tests.cmake")
- message(STATUS "Using pre-generated test list from cmake/testsuite-tests.cmake for ${test_name}")
- include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/testsuite-tests.cmake")
- set(use_pregenerated_list TRUE)
- else()
- # Neither data nor pre-generated list exists, register monolithic fallback
- message(STATUS "Test suite data not found - registering monolithic ${test_name} test")
- message(STATUS "Run 'ctest -R yaml-test-suite-setup' then re-run cmake to register individual subtests")
+ set(extra_env "JQ=${JQ_EXECUTABLE}")
- add_test(NAME ${test_name}
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test/${test_script}
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
- set_tests_properties(${test_name} PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- FIXTURES_REQUIRED yaml-test-suite-data
- )
- return()
+ message(STATUS "Registering individual ${test_name} subtests")
+
+ # Use wildcard glob and filter with regex (Windows-compatible)
+ file(GLOB all_base_dirs "${test_dir}/*")
+
+ foreach(base_test ${all_base_dirs})
+ if(NOT IS_DIRECTORY "${base_test}")
+ continue()
+ endif()
+ get_filename_component(base_id "${base_test}" NAME)
+ # Filter: must be 4 alphanumeric chars (YAML test suite IDs like "229Q", "2JQS")
+ if(NOT base_id MATCHES "^[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]$")
+ continue()
endif()
- else()
- message(STATUS "Registering individual ${test_name} subtests from filesystem")
- endif()
- if(use_pregenerated_list)
- # Use pre-generated TESTSUITE_ALL_TESTS list
- foreach(test_id ${TESTSUITE_ALL_TESTS})
- # test_id is either "BASE" or "BASE/SUBTEST"
- string(REPLACE "/" ";" test_parts "${test_id}")
- list(LENGTH test_parts parts_count)
-
- add_test(
- NAME "${test_name}/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- "${test_name}" "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+ # Register base test
+ _register_testsuite_test("${test_name}" "${base_test}" "${base_id}"
+ "${skip_list}" "${xfail_list}" "${extra_env}")
- set_tests_properties("${test_name}/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "${test_name}"
- FIXTURES_REQUIRED "yaml-test-suite-data"
- )
- endforeach()
- else()
- # Scan the filesystem (original behavior)
- file(GLOB base_tests "${test_dir}/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]")
-
- foreach(base_test ${base_tests})
- get_filename_component(test_id "${base_test}" NAME)
-
- # Check for main test
- if(EXISTS "${base_test}/===")
- # Read description from === file
- file(READ "${base_test}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "${test_name}/${test_id} - ${test_desc}")
- else()
- set(test_name_full "${test_name}/${test_id}")
- endif()
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- "${test_name}" "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set basic properties
- set(test_labels "${test_name}")
- set(test_disabled FALSE)
-
- # Check if test should be skipped
- if(test_id IN_LIST skip_list)
- set(test_disabled TRUE)
- set(test_labels "${test_name};skipped")
- endif()
-
- # Check if test is expected to fail (xfail)
- # Note: TAP xfail (TODO) tests still pass (exit 0), they just mark the result as TODO
- # So we don't use WILL_FAIL here, just add a label for filtering
- if(test_id IN_LIST xfail_list)
- set(test_labels "${test_name};xfail")
- endif()
-
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "${test_labels}"
- FIXTURES_REQUIRED "yaml-test-suite-data"
- DISABLED ${test_disabled}
- )
+ # Check for subtests (2-digit or 3-digit subdirectories)
+ file(GLOB all_subtests "${base_test}/*")
+ foreach(subtest ${all_subtests})
+ if(NOT IS_DIRECTORY "${subtest}")
+ continue()
+ endif()
+ get_filename_component(subtest_id "${subtest}" NAME)
+ # Filter: must be 2 or 3 digits
+ if(NOT subtest_id MATCHES "^[0-9][0-9][0-9]?$")
+ continue()
endif()
- # Check for 2-digit subtests
- file(GLOB subtests_2d "${base_test}/[0-9][0-9]")
- foreach(subtest ${subtests_2d})
- if(EXISTS "${subtest}/===")
- get_filename_component(subtest_id "${subtest}" NAME)
- set(full_test_id "${test_id}/${subtest_id}")
-
- # Read description from === file
- file(READ "${subtest}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "${test_name}/${full_test_id} - ${test_desc}")
- else()
- set(test_name_full "${test_name}/${full_test_id}")
- endif()
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- "${test_name}" "${full_test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set basic properties
- set(test_labels "${test_name}")
- set(test_disabled FALSE)
-
- # Check if test should be skipped
- if(full_test_id IN_LIST skip_list)
- set(test_disabled TRUE)
- set(test_labels "${test_name};skipped")
- endif()
-
- # Check if test is expected to fail (xfail)
- # Note: TAP xfail (TODO) tests still pass (exit 0), they just mark the result as TODO
- # So we don't use WILL_FAIL here, just add a label for filtering
- if(full_test_id IN_LIST xfail_list)
- set(test_labels "${test_name};xfail")
- endif()
-
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "${test_labels}"
- FIXTURES_REQUIRED "yaml-test-suite-data"
- DISABLED ${test_disabled}
- )
- endif()
- endforeach()
-
- # Check for 3-digit subtests
- file(GLOB subtests_3d "${base_test}/[0-9][0-9][0-9]")
- foreach(subtest ${subtests_3d})
- if(EXISTS "${subtest}/===")
- get_filename_component(subtest_id "${subtest}" NAME)
- set(full_test_id "${test_id}/${subtest_id}")
-
- # Read description from === file
- file(READ "${subtest}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "${test_name}/${full_test_id} - ${test_desc}")
- else()
- set(test_name_full "${test_name}/${full_test_id}")
- endif()
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- "${test_name}" "${full_test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set basic properties
- set(test_labels "${test_name}")
- set(test_disabled FALSE)
-
- # Check if test should be skipped
- if(full_test_id IN_LIST skip_list)
- set(test_disabled TRUE)
- set(test_labels "${test_name};skipped")
- endif()
-
- # Check if test is expected to fail (xfail)
- # Note: TAP xfail (TODO) tests still pass (exit 0), they just mark the result as TODO
- # So we don't use WILL_FAIL here, just add a label for filtering
- if(full_test_id IN_LIST xfail_list)
- set(test_labels "${test_name};xfail")
- endif()
-
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "${test_labels}"
- FIXTURES_REQUIRED "yaml-test-suite-data"
- DISABLED ${test_disabled}
- )
- endif()
- endforeach()
+ set(full_test_id "${base_id}/${subtest_id}")
+ _register_testsuite_test("${test_name}" "${subtest}" "${full_test_id}"
+ "${skip_list}" "${xfail_list}" "${extra_env}")
endforeach()
- endif()
+ endforeach()
endfunction()
# Function to add jsontestsuite tests
-# Can work either by scanning the json-test-suite-data directory (if it exists)
-# or by using a pre-generated list of tests from jsontestsuite-tests.cmake
+# Scans json-test-suite-data directory (populated by FetchContent at configure time)
function(add_jsontestsuite_tests)
- set(test_dir "${CMAKE_CURRENT_BINARY_DIR}/test/json-test-suite-data/test_parsing")
- set(use_pregenerated_list FALSE)
-
- # Check if we should use the pre-generated list
- if(NOT EXISTS "${test_dir}")
- # Try to use pre-generated list if available
- if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/jsontestsuite-tests.cmake")
- message(STATUS "Using pre-generated test list from cmake/jsontestsuite-tests.cmake")
- include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/jsontestsuite-tests.cmake")
- set(use_pregenerated_list TRUE)
+ set(test_dir "${json_test_suite_SOURCE_DIR}/test_parsing")
+
+ message(STATUS "Registering individual jsontestsuite subtests")
+
+ # Scan for all .json files and categorize by prefix
+ file(GLOB all_tests "${test_dir}/*.json")
+ foreach(test_file ${all_tests})
+ get_filename_component(test_id "${test_file}" NAME)
+
+ # Categorize by first character: y=pass, n=fail, i=impl-defined
+ string(SUBSTRING "${test_id}" 0 1 prefix)
+ if(prefix STREQUAL "y")
+ set(label "jsontestsuite;jsontestsuite-pass")
+ elseif(prefix STREQUAL "n")
+ set(label "jsontestsuite;jsontestsuite-fail")
+ elseif(prefix STREQUAL "i")
+ set(label "jsontestsuite;jsontestsuite-impl")
else()
- # Neither data nor pre-generated list exists, register monolithic fallback
- message(STATUS "JSON test suite data not found - registering monolithic jsontestsuite test")
- message(STATUS "Run 'ctest -R json-test-suite-setup' then re-run cmake to register individual subtests")
-
- add_test(NAME jsontestsuite
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test/jsontestsuite.test
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
- set_tests_properties(jsontestsuite PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- FIXTURES_REQUIRED json-test-suite-data
- )
- return()
+ continue()
endif()
- else()
- message(STATUS "Registering individual jsontestsuite subtests from filesystem")
- endif()
- if(use_pregenerated_list)
- # Use pre-generated lists
- # Expected to pass (y_*.json)
- foreach(test_id ${JSONTESTSUITE_PASS_TESTS})
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-pass"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
-
- # Expected to fail (n_*.json)
- foreach(test_id ${JSONTESTSUITE_FAIL_TESTS})
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-fail"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
-
- # Implementation defined (i_*.json)
- foreach(test_id ${JSONTESTSUITE_IMPL_TESTS})
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+ add_tap_test("jsontestsuite/${test_id}" jsontestsuite "${test_id}"
+ LABELS "${label}"
+ EXTRA_ENV "JQ=${JQ_EXECUTABLE}"
+ )
+ endforeach()
+endfunction()
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-impl"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
- else()
- # Scan the filesystem (original behavior)
- # Expected to pass (y_*.json)
- file(GLOB pass_tests "${test_dir}/y_*.json")
- foreach(test_file ${pass_tests})
- get_filename_component(test_id "${test_file}" NAME)
-
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+# Helper macro for checking if a reflection test should be skipped based on env file
+macro(_should_skip_reflection_test test_path result_var)
+ set(${result_var} FALSE)
+ set(_env_file "${test_path}/env")
+ if(EXISTS "${_env_file}")
+ file(READ "${_env_file}" _env_contents)
+ string(STRIP "${_env_contents}" _env_contents)
+
+ # Parse env file for requirements
+ if(_env_contents MATCHES "intbits=([0-9]+)")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_intbits}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ if(_env_contents MATCHES "shortbits=([0-9]+)")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_shortbits}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ if(_env_contents MATCHES "longbits=([0-9]+)")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_longbits}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ if(_env_contents MATCHES "charbits=([0-9]+)")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_charbits}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ if(_env_contents MATCHES "longlongbits=([0-9]+)")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_longlongbits}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ if(_env_contents MATCHES "charsigned=([yn])")
+ if(NOT "${CMAKE_MATCH_1}" STREQUAL "${_refl_charsigned}")
+ set(${result_var} TRUE)
+ endif()
+ endif()
+ endif()
+endmacro()
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-pass"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
+# Helper macro to register a single reflection test
+macro(_register_reflection_test test_dir test_id xfail_list)
+ if(EXISTS "${test_dir}/===")
+ # Read description from === file
+ file(READ "${test_dir}/===" _test_desc)
+ string(STRIP "${_test_desc}" _test_desc)
- # Expected to fail (n_*.json)
- file(GLOB fail_tests "${test_dir}/n_*.json")
- foreach(test_file ${fail_tests})
- get_filename_component(test_id "${test_file}" NAME)
+ # Build test name with description if available
+ if(_test_desc)
+ set(_test_name_full "testreflection/${test_id} - ${_test_desc}")
+ else()
+ set(_test_name_full "testreflection/${test_id}")
+ endif()
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+ # Check if test should be skipped based on environment
+ _should_skip_reflection_test("${test_dir}" _test_should_skip)
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-fail"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
+ # Set basic properties
+ set(_test_labels "testreflection")
+ set(_test_disabled FALSE)
+ set(_test_will_fail FALSE)
- # Implementation defined (i_*.json)
- file(GLOB impl_tests "${test_dir}/i_*.json")
- foreach(test_file ${impl_tests})
- get_filename_component(test_id "${test_file}" NAME)
+ if(_test_should_skip)
+ set(_test_disabled TRUE)
+ set(_test_labels "testreflection;skipped")
+ endif()
- add_test(
- NAME "jsontestsuite/${test_id}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- jsontestsuite "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+ if(test_id IN_LIST xfail_list)
+ set(_test_labels "testreflection;xfail")
+ set(_test_will_fail TRUE)
+ endif()
- set_tests_properties("jsontestsuite/${test_id}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test;JQ=${JQ_EXECUTABLE}"
- LABELS "jsontestsuite;jsontestsuite-impl"
- FIXTURES_REQUIRED "json-test-suite-data"
- )
- endforeach()
+ # Register the test with appropriate flags
+ if(_test_disabled AND _test_will_fail)
+ add_tap_test("${_test_name_full}" testreflection "${test_id}"
+ LABELS "${_test_labels}" DISABLED WILL_FAIL)
+ elseif(_test_disabled)
+ add_tap_test("${_test_name_full}" testreflection "${test_id}"
+ LABELS "${_test_labels}" DISABLED)
+ elseif(_test_will_fail)
+ add_tap_test("${_test_name_full}" testreflection "${test_id}"
+ LABELS "${_test_labels}" WILL_FAIL)
+ else()
+ add_tap_test("${_test_name_full}" testreflection "${test_id}"
+ LABELS "${_test_labels}")
+ endif()
endif()
-endfunction()
+endmacro()
# Function to add reflection tests
function(add_testreflection_tests)
set(test_dir "${CMAKE_CURRENT_SOURCE_DIR}/test/reflection-data")
# Skip/xfail lists from testreflection.test
- # xfaillist="025PB08/00 025UXE6/00 025VL2J/00"
set(xfail_list "025PB08/00" "025UXE6/00" "025VL2J/00")
# Probe system characteristics (matching testreflection.test logic)
check_type_size("unsigned char" SIZEOF_UCHAR)
check_type_size("long long" SIZEOF_LONGLONG)
- # Calculate bit sizes
- math(EXPR intbits "${SIZEOF_UINT} * 8")
- math(EXPR shortbits "${SIZEOF_USHORT} * 8")
- math(EXPR longbits "${SIZEOF_ULONG} * 8")
- math(EXPR charbits "${SIZEOF_UCHAR} * 8")
- set(longlongbits 64) # Always 64 bits as per testreflection.test
+ # Calculate bit sizes (store in _refl_ prefixed vars for macro access)
+ math(EXPR _refl_intbits "${SIZEOF_UINT} * 8")
+ math(EXPR _refl_shortbits "${SIZEOF_USHORT} * 8")
+ math(EXPR _refl_longbits "${SIZEOF_ULONG} * 8")
+ math(EXPR _refl_charbits "${SIZEOF_UCHAR} * 8")
+ set(_refl_longlongbits 64)
# Check if char is signed
include(CheckCSourceRuns)
int main() { return (CHAR_MIN < 0) ? 0 : 1; }
" CHAR_IS_SIGNED)
if(CHAR_IS_SIGNED)
- set(charsigned "y")
+ set(_refl_charsigned "y")
else()
- set(charsigned "n")
+ set(_refl_charsigned "n")
endif()
message(STATUS "Reflection test system characteristics:")
- message(STATUS " intbits=${intbits} shortbits=${shortbits} longbits=${longbits}")
- message(STATUS " charbits=${charbits} longlongbits=${longlongbits} charsigned=${charsigned}")
-
- # Helper function to check if test should be skipped based on env file
- macro(should_skip_test test_path result_var)
- set(${result_var} FALSE)
- set(env_file "${test_path}/env")
- if(EXISTS "${env_file}")
- file(READ "${env_file}" env_contents)
- string(STRIP "${env_contents}" env_contents)
-
- # Parse env file for requirements
- if(env_contents MATCHES "intbits=([0-9]+)")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${intbits}")
- set(${result_var} TRUE)
- endif()
- endif()
- if(env_contents MATCHES "shortbits=([0-9]+)")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${shortbits}")
- set(${result_var} TRUE)
- endif()
- endif()
- if(env_contents MATCHES "longbits=([0-9]+)")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${longbits}")
- set(${result_var} TRUE)
- endif()
- endif()
- if(env_contents MATCHES "charbits=([0-9]+)")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${charbits}")
- set(${result_var} TRUE)
- endif()
- endif()
- if(env_contents MATCHES "longlongbits=([0-9]+)")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${longlongbits}")
- set(${result_var} TRUE)
- endif()
- endif()
- if(env_contents MATCHES "charsigned=([yn])")
- if(NOT "${CMAKE_MATCH_1}" STREQUAL "${charsigned}")
- set(${result_var} TRUE)
- endif()
- endif()
- endif()
- endmacro()
-
- # Scan reflection-data directory for tests
- # Note: CMake GLOB doesn't support [A-Z0-9] ranges like shell globs do
- # We need to use a wildcard and filter in the loop
- file(GLOB base_tests "${test_dir}/*")
-
- # Filter to only include directories matching the pattern [0-9][0-9][0-9][A-Z][A-Z0-9][A-Z0-9][A-Z0-9]
- set(filtered_base_tests)
- foreach(test_candidate ${base_tests})
- if(IS_DIRECTORY "${test_candidate}")
- get_filename_component(test_name "${test_candidate}" NAME)
- # Check if the name matches the pattern: 3 digits followed by 4 alphanumeric chars (starting with letter)
- if(test_name MATCHES "^[0-9][0-9][0-9][A-Z][A-Z0-9][A-Z0-9][A-Z0-9]$")
- list(APPEND filtered_base_tests "${test_candidate}")
- endif()
- endif()
- endforeach()
- set(base_tests ${filtered_base_tests})
+ message(STATUS " intbits=${_refl_intbits} shortbits=${_refl_shortbits} longbits=${_refl_longbits}")
+ message(STATUS " charbits=${_refl_charbits} longlongbits=${_refl_longlongbits} charsigned=${_refl_charsigned}")
- foreach(base_test ${base_tests})
- get_filename_component(test_id "${base_test}" NAME)
+ # Use wildcard glob and filter with regex (Windows-compatible)
+ file(GLOB all_base_dirs "${test_dir}/*")
- # Check for main test (base directory with === file)
- if(EXISTS "${base_test}/===")
- # Read description from === file
- file(READ "${base_test}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "testreflection/${test_id} - ${test_desc}")
- else()
- set(test_name_full "testreflection/${test_id}")
- endif()
-
- # Check if test should be skipped based on environment
- should_skip_test("${base_test}" test_should_skip)
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- testreflection "${test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
+ foreach(base_test ${all_base_dirs})
+ if(NOT IS_DIRECTORY "${base_test}")
+ continue()
+ endif()
+ get_filename_component(base_id "${base_test}" NAME)
+ # Filter: 3 digits followed by 4 alphanumeric chars (starting with letter)
+ if(NOT base_id MATCHES "^[0-9][0-9][0-9][A-Z][A-Z0-9][A-Z0-9][A-Z0-9]$")
+ continue()
+ endif()
- # Set basic properties
- set(test_labels "testreflection")
- set(test_disabled FALSE)
- set(test_will_fail FALSE)
+ # Register base test
+ _register_reflection_test("${base_test}" "${base_id}" "${xfail_list}")
- # Check if test should be skipped
- if(test_should_skip)
- set(test_disabled TRUE)
- set(test_labels "testreflection;skipped")
+ # Check for subtests (2-digit or 3-digit subdirectories)
+ file(GLOB all_subtests "${base_test}/*")
+ foreach(subtest ${all_subtests})
+ if(NOT IS_DIRECTORY "${subtest}")
+ continue()
endif()
-
- # Check if test is expected to fail (xfail)
- if(test_id IN_LIST xfail_list)
- set(test_labels "testreflection;xfail")
- set(test_will_fail TRUE)
+ get_filename_component(subtest_id "${subtest}" NAME)
+ # Filter: must be 2 or 3 digits
+ if(NOT subtest_id MATCHES "^[0-9][0-9][0-9]?$")
+ continue()
endif()
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test"
- LABELS "${test_labels}"
- DISABLED ${test_disabled}
- WILL_FAIL ${test_will_fail}
- )
- endif()
-
- # Check for 2-digit subtests
- file(GLOB subtests_2d "${base_test}/[0-9][0-9]")
- foreach(subtest ${subtests_2d})
- if(EXISTS "${subtest}/===")
- get_filename_component(subtest_id "${subtest}" NAME)
- set(full_test_id "${test_id}/${subtest_id}")
-
- # Read description from === file
- file(READ "${subtest}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "testreflection/${full_test_id} - ${test_desc}")
- else()
- set(test_name_full "testreflection/${full_test_id}")
- endif()
-
- # Check if test should be skipped based on environment
- should_skip_test("${subtest}" test_should_skip)
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- testreflection "${full_test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set basic properties
- set(test_labels "testreflection")
- set(test_disabled FALSE)
- set(test_will_fail FALSE)
-
- # Check if test should be skipped
- if(test_should_skip)
- set(test_disabled TRUE)
- set(test_labels "testreflection;skipped")
- endif()
-
- # Check if test is expected to fail (xfail)
- if(full_test_id IN_LIST xfail_list)
- set(test_labels "testreflection;xfail")
- set(test_will_fail TRUE)
- endif()
-
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test"
- LABELS "${test_labels}"
- DISABLED ${test_disabled}
- WILL_FAIL ${test_will_fail}
- )
- endif()
- endforeach()
-
- # Check for 3-digit subtests
- file(GLOB subtests_3d "${base_test}/[0-9][0-9][0-9]")
- foreach(subtest ${subtests_3d})
- if(EXISTS "${subtest}/===")
- get_filename_component(subtest_id "${subtest}" NAME)
- set(full_test_id "${test_id}/${subtest_id}")
-
- # Read description from === file
- file(READ "${subtest}/===" test_desc)
- string(STRIP "${test_desc}" test_desc)
-
- # Build test name with description if available
- if(test_desc)
- set(test_name_full "testreflection/${full_test_id} - ${test_desc}")
- else()
- set(test_name_full "testreflection/${full_test_id}")
- endif()
-
- # Check if test should be skipped based on environment
- should_skip_test("${subtest}" test_should_skip)
-
- add_test(
- NAME "${test_name_full}"
- COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/cmake/run-single-tap-test.sh
- testreflection "${full_test_id}"
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/test
- )
-
- # Set basic properties
- set(test_labels "testreflection")
- set(test_disabled FALSE)
- set(test_will_fail FALSE)
-
- # Check if test should be skipped
- if(test_should_skip)
- set(test_disabled TRUE)
- set(test_labels "testreflection;skipped")
- endif()
-
- # Check if test is expected to fail (xfail)
- if(full_test_id IN_LIST xfail_list)
- set(test_labels "testreflection;xfail")
- set(test_will_fail TRUE)
- endif()
-
- set_tests_properties("${test_name_full}" PROPERTIES
- ENVIRONMENT "TOP_SRCDIR=${CMAKE_CURRENT_SOURCE_DIR};TOP_BUILDDIR=${CMAKE_CURRENT_BINARY_DIR};SRCDIR=${CMAKE_CURRENT_SOURCE_DIR}/test;BUILDDIR=${CMAKE_CURRENT_BINARY_DIR}/test"
- LABELS "${test_labels}"
- DISABLED ${test_disabled}
- WILL_FAIL ${test_will_fail}
- )
- endif()
+ set(full_test_id "${base_id}/${subtest_id}")
+ _register_reflection_test("${subtest}" "${full_test_id}" "${xfail_list}")
endforeach()
endforeach()
endfunction()
--- /dev/null
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR AMD64)
+
+set(CMAKE_C_COMPILER clang)
+set(CMAKE_CXX_COMPILER clang++)
+
+set(triple x86_64-windows-msvc)
+set(CMAKE_C_COMPILER_TARGET ${triple})
+set(CMAKE_CXX_COMPILER_TARGET ${triple})
+
+set(CMAKE_LINKER lld-link)
+set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -out:<TARGET> <LINK_LIBRARIES>")
+set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_LINKER> <LINK_FLAGS> <OBJECTS> -out:<TARGET> <LINK_LIBRARIES>")
+
+set(CMAKE_C_CREATE_SHARED_LIBRARY "<CMAKE_LINKER> -dll <LINK_FLAGS> <OBJECTS> -out:<TARGET> -implib:<TARGET_IMPLIB> <LINK_LIBRARIES>")
+set(CMAKE_CXX_CREATE_SHARED_LIBRARY "<CMAKE_LINKER> -dll <LINK_FLAGS> <OBJECTS> -out:<TARGET> -implib:<TARGET_IMPLIB> <LINK_LIBRARIES>")
+
+# Disable Unix-specific flags
+set(CMAKE_C_COMPILE_OPTIONS_PIC "")
+set(CMAKE_CXX_COMPILE_OPTIONS_PIC "")
+set(CMAKE_SHARED_LIBRARY_C_FLAGS "")
+set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "")
+
+# Add -fuse-ld=lld to ensure clang uses lld
+set(CMAKE_C_FLAGS_INIT "-fuse-ld=lld")
+set(CMAKE_CXX_FLAGS_INIT "-fuse-ld=lld")
--- /dev/null
+# generate-def.cmake
+# Generates fyaml.def from libfyaml.h by extracting FY_EXPORT functions
+#
+# Usage: cmake -DINPUT_HEADER=path/to/libfyaml.h -DOUTPUT_DEF=path/to/fyaml.def -P generate-def.cmake
+
+if(NOT INPUT_HEADER)
+ message(FATAL_ERROR "INPUT_HEADER not specified")
+endif()
+
+if(NOT OUTPUT_DEF)
+ message(FATAL_ERROR "OUTPUT_DEF not specified")
+endif()
+
+# Functions declared with FY_EXPORT but not implemented as standalone functions
+# (they may be inline, macros, or not implemented)
+# These are determined by linker errors - if the symbol is unresolved, add it here
+set(EXCLUDE_FUNCTIONS)
+
+# Read the header file
+file(READ "${INPUT_HEADER}" HEADER_CONTENT)
+
+# Find all function names that have FY_EXPORT
+# Pattern: function_name(...) followed by FY_EXPORT on same or next line
+# There may be FY_FORMAT(...) or other attributes between function and FY_EXPORT
+# We look for: word( ... ) whitespace [optional FY_FORMAT(...)] whitespace FY_EXPORT
+string(REGEX MATCHALL "[a-z_][a-z0-9_]*[ \t]*\\([^)]*\\)[\r\n\t ]+(FY_FORMAT\\([^)]*\\)[\r\n\t ]+)?FY_EXPORT" MATCHES "${HEADER_CONTENT}")
+
+# Extract just the function names
+set(FUNCTION_NAMES "")
+foreach(MATCH ${MATCHES})
+ # Extract function name (everything before the opening paren)
+ string(REGEX REPLACE "[ \t]*\\(.*" "" FUNC_NAME "${MATCH}")
+ list(APPEND FUNCTION_NAMES "${FUNC_NAME}")
+endforeach()
+
+# Remove duplicates and sort
+list(REMOVE_DUPLICATES FUNCTION_NAMES)
+list(SORT FUNCTION_NAMES)
+
+# Remove excluded functions
+foreach(EXCLUDE ${EXCLUDE_FUNCTIONS})
+ list(REMOVE_ITEM FUNCTION_NAMES "${EXCLUDE}")
+endforeach()
+
+# Generate the .def file content
+set(DEF_CONTENT "; fyaml.def - Auto-generated module definition file for fyaml.dll
+; Generated from libfyaml.h - DO NOT EDIT MANUALLY
+;
+; This file exports the public API symbols marked with FY_EXPORT.
+; Regenerate with: cmake -DINPUT_HEADER=include/libfyaml.h -DOUTPUT_DEF=src/lib/fyaml.def -P cmake/generate-def.cmake
+
+LIBRARY fyaml
+EXPORTS
+")
+
+foreach(FUNC ${FUNCTION_NAMES})
+ string(APPEND DEF_CONTENT " ${FUNC}\n")
+endforeach()
+
+# Write the output file
+file(WRITE "${OUTPUT_DEF}" "${DEF_CONTENT}")
+
+# Report
+list(LENGTH FUNCTION_NAMES NUM_FUNCS)
+message(STATUS "Generated ${OUTPUT_DEF} with ${NUM_FUNCS} exported functions")
+++ /dev/null
-# Auto-generated file - do not edit manually
-# Generated by cmake/generate-jsontestsuite-list.sh
-#
-# This file contains lists of tests from the JSON test suite
-# It allows registering individual tests without requiring the test data
-# to be downloaded first.
-
-# Test suite checkout: d64aefb55228d9584d3e5b2433f720ea8fd00c82
-# Generated on: 2025-10-24 08:05:59 UTC
-# Pass tests: 95
-# Fail tests: 188
-# Impl tests: 35
-
-# Tests expected to pass (y_*.json)
-set(JSONTESTSUITE_PASS_TESTS
- "y_array_arraysWithSpaces.json"
- "y_array_empty.json"
- "y_array_empty-string.json"
- "y_array_ending_with_newline.json"
- "y_array_false.json"
- "y_array_heterogeneous.json"
- "y_array_null.json"
- "y_array_with_1_and_newline.json"
- "y_array_with_leading_space.json"
- "y_array_with_several_null.json"
- "y_array_with_trailing_space.json"
- "y_number_0e+1.json"
- "y_number_0e1.json"
- "y_number_after_space.json"
- "y_number_double_close_to_zero.json"
- "y_number_int_with_exp.json"
- "y_number.json"
- "y_number_minus_zero.json"
- "y_number_negative_int.json"
- "y_number_negative_one.json"
- "y_number_negative_zero.json"
- "y_number_real_capital_e.json"
- "y_number_real_capital_e_neg_exp.json"
- "y_number_real_capital_e_pos_exp.json"
- "y_number_real_exponent.json"
- "y_number_real_fraction_exponent.json"
- "y_number_real_neg_exp.json"
- "y_number_real_pos_exponent.json"
- "y_number_simple_int.json"
- "y_number_simple_real.json"
- "y_object_basic.json"
- "y_object_duplicated_key_and_value.json"
- "y_object_duplicated_key.json"
- "y_object_empty.json"
- "y_object_empty_key.json"
- "y_object_escaped_null_in_key.json"
- "y_object_extreme_numbers.json"
- "y_object.json"
- "y_object_long_strings.json"
- "y_object_simple.json"
- "y_object_string_unicode.json"
- "y_object_with_newlines.json"
- "y_string_1_2_3_bytes_UTF-8_sequences.json"
- "y_string_accepted_surrogate_pair.json"
- "y_string_accepted_surrogate_pairs.json"
- "y_string_allowed_escapes.json"
- "y_string_backslash_and_u_escaped_zero.json"
- "y_string_backslash_doublequotes.json"
- "y_string_comments.json"
- "y_string_double_escape_a.json"
- "y_string_double_escape_n.json"
- "y_string_escaped_control_character.json"
- "y_string_escaped_noncharacter.json"
- "y_string_in_array.json"
- "y_string_in_array_with_leading_space.json"
- "y_string_last_surrogates_1_and_2.json"
- "y_string_nbsp_uescaped.json"
- "y_string_nonCharacterInUTF-8_U+10FFFF.json"
- "y_string_nonCharacterInUTF-8_U+FFFF.json"
- "y_string_null_escape.json"
- "y_string_one-byte-utf-8.json"
- "y_string_pi.json"
- "y_string_reservedCharacterInUTF-8_U+1BFFF.json"
- "y_string_simple_ascii.json"
- "y_string_space.json"
- "y_string_surrogates_U+1D11E_MUSICAL_SYMBOL_G_CLEF.json"
- "y_string_three-byte-utf-8.json"
- "y_string_two-byte-utf-8.json"
- "y_string_u+2028_line_sep.json"
- "y_string_u+2029_par_sep.json"
- "y_string_uescaped_newline.json"
- "y_string_uEscape.json"
- "y_string_unescaped_char_delete.json"
- "y_string_unicode_2.json"
- "y_string_unicodeEscapedBackslash.json"
- "y_string_unicode_escaped_double_quote.json"
- "y_string_unicode.json"
- "y_string_unicode_U+10FFFE_nonchar.json"
- "y_string_unicode_U+1FFFE_nonchar.json"
- "y_string_unicode_U+200B_ZERO_WIDTH_SPACE.json"
- "y_string_unicode_U+2064_invisible_plus.json"
- "y_string_unicode_U+FDD0_nonchar.json"
- "y_string_unicode_U+FFFE_nonchar.json"
- "y_string_utf8.json"
- "y_string_with_del_character.json"
- "y_structure_lonely_false.json"
- "y_structure_lonely_int.json"
- "y_structure_lonely_negative_real.json"
- "y_structure_lonely_null.json"
- "y_structure_lonely_string.json"
- "y_structure_lonely_true.json"
- "y_structure_string_empty.json"
- "y_structure_trailing_newline.json"
- "y_structure_true_in_array.json"
- "y_structure_whitespace_array.json"
-)
-
-# Tests expected to fail (n_*.json)
-set(JSONTESTSUITE_FAIL_TESTS
- "n_array_1_true_without_comma.json"
- "n_array_a_invalid_utf8.json"
- "n_array_colon_instead_of_comma.json"
- "n_array_comma_after_close.json"
- "n_array_comma_and_number.json"
- "n_array_double_comma.json"
- "n_array_double_extra_comma.json"
- "n_array_extra_close.json"
- "n_array_extra_comma.json"
- "n_array_incomplete_invalid_value.json"
- "n_array_incomplete.json"
- "n_array_inner_array_no_comma.json"
- "n_array_invalid_utf8.json"
- "n_array_items_separated_by_semicolon.json"
- "n_array_just_comma.json"
- "n_array_just_minus.json"
- "n_array_missing_value.json"
- "n_array_newlines_unclosed.json"
- "n_array_number_and_comma.json"
- "n_array_number_and_several_commas.json"
- "n_array_spaces_vertical_tab_formfeed.json"
- "n_array_star_inside.json"
- "n_array_unclosed.json"
- "n_array_unclosed_trailing_comma.json"
- "n_array_unclosed_with_new_lines.json"
- "n_array_unclosed_with_object_inside.json"
- "n_incomplete_false.json"
- "n_incomplete_null.json"
- "n_incomplete_true.json"
- "n_multidigit_number_then_00.json"
- "n_number_0.1.2.json"
- "n_number_-01.json"
- "n_number_0.3e+.json"
- "n_number_0.3e.json"
- "n_number_0_capital_E+.json"
- "n_number_0_capital_E.json"
- "n_number_0.e1.json"
- "n_number_0e+.json"
- "n_number_0e.json"
- "n_number_1_000.json"
- "n_number_1.0e+.json"
- "n_number_1.0e-.json"
- "n_number_1.0e.json"
- "n_number_-1.0..json"
- "n_number_1eE2.json"
- "n_number_+1.json"
- "n_number_.-1.json"
- "n_number_2.e+3.json"
- "n_number_2.e-3.json"
- "n_number_2.e3.json"
- "n_number_.2e-3.json"
- "n_number_-2..json"
- "n_number_9.e+.json"
- "n_number_expression.json"
- "n_number_hex_1_digit.json"
- "n_number_hex_2_digits.json"
- "n_number_infinity.json"
- "n_number_+Inf.json"
- "n_number_Inf.json"
- "n_number_invalid+-.json"
- "n_number_invalid-negative-real.json"
- "n_number_invalid-utf-8-in-bigger-int.json"
- "n_number_invalid-utf-8-in-exponent.json"
- "n_number_invalid-utf-8-in-int.json"
- "n_number_++.json"
- "n_number_minus_infinity.json"
- "n_number_minus_sign_with_trailing_garbage.json"
- "n_number_minus_space_1.json"
- "n_number_-NaN.json"
- "n_number_NaN.json"
- "n_number_neg_int_starting_with_zero.json"
- "n_number_neg_real_without_int_part.json"
- "n_number_neg_with_garbage_at_end.json"
- "n_number_real_garbage_after_e.json"
- "n_number_real_with_invalid_utf8_after_e.json"
- "n_number_real_without_fractional_part.json"
- "n_number_starting_with_dot.json"
- "n_number_U+FF11_fullwidth_digit_one.json"
- "n_number_with_alpha_char.json"
- "n_number_with_alpha.json"
- "n_number_with_leading_zero.json"
- "n_object_bad_value.json"
- "n_object_bracket_key.json"
- "n_object_comma_instead_of_colon.json"
- "n_object_double_colon.json"
- "n_object_emoji.json"
- "n_object_garbage_at_end.json"
- "n_object_key_with_single_quotes.json"
- "n_object_lone_continuation_byte_in_key_and_trailing_comma.json"
- "n_object_missing_colon.json"
- "n_object_missing_key.json"
- "n_object_missing_semicolon.json"
- "n_object_missing_value.json"
- "n_object_no-colon.json"
- "n_object_non_string_key_but_huge_number_instead.json"
- "n_object_non_string_key.json"
- "n_object_repeated_null_null.json"
- "n_object_several_trailing_commas.json"
- "n_object_single_quote.json"
- "n_object_trailing_comma.json"
- "n_object_trailing_comment.json"
- "n_object_trailing_comment_open.json"
- "n_object_trailing_comment_slash_open_incomplete.json"
- "n_object_trailing_comment_slash_open.json"
- "n_object_two_commas_in_a_row.json"
- "n_object_unquoted_key.json"
- "n_object_unterminated-value.json"
- "n_object_with_single_string.json"
- "n_object_with_trailing_garbage.json"
- "n_single_space.json"
- "n_string_1_surrogate_then_escape.json"
- "n_string_1_surrogate_then_escape_u1.json"
- "n_string_1_surrogate_then_escape_u1x.json"
- "n_string_1_surrogate_then_escape_u.json"
- "n_string_accentuated_char_no_quotes.json"
- "n_string_backslash_00.json"
- "n_string_escaped_backslash_bad.json"
- "n_string_escaped_ctrl_char_tab.json"
- "n_string_escaped_emoji.json"
- "n_string_escape_x.json"
- "n_string_incomplete_escaped_character.json"
- "n_string_incomplete_escape.json"
- "n_string_incomplete_surrogate_escape_invalid.json"
- "n_string_incomplete_surrogate.json"
- "n_string_invalid_backslash_esc.json"
- "n_string_invalid_unicode_escape.json"
- "n_string_invalid_utf8_after_escape.json"
- "n_string_invalid-utf-8-in-escape.json"
- "n_string_leading_uescaped_thinspace.json"
- "n_string_no_quotes_with_bad_escape.json"
- "n_string_single_doublequote.json"
- "n_string_single_quote.json"
- "n_string_single_string_no_double_quotes.json"
- "n_string_start_escape_unclosed.json"
- "n_string_unescaped_ctrl_char.json"
- "n_string_unescaped_newline.json"
- "n_string_unescaped_tab.json"
- "n_string_unicode_CapitalU.json"
- "n_string_with_trailing_garbage.json"
- "n_structure_100000_opening_arrays.json"
- "n_structure_angle_bracket_..json"
- "n_structure_angle_bracket_null.json"
- "n_structure_array_trailing_garbage.json"
- "n_structure_array_with_extra_array_close.json"
- "n_structure_array_with_unclosed_string.json"
- "n_structure_ascii-unicode-identifier.json"
- "n_structure_capitalized_True.json"
- "n_structure_close_unopened_array.json"
- "n_structure_comma_instead_of_closing_brace.json"
- "n_structure_double_array.json"
- "n_structure_end_array.json"
- "n_structure_incomplete_UTF8_BOM.json"
- "n_structure_lone-invalid-utf-8.json"
- "n_structure_lone-open-bracket.json"
- "n_structure_no_data.json"
- "n_structure_null-byte-outside-string.json"
- "n_structure_number_with_trailing_garbage.json"
- "n_structure_object_followed_by_closing_object.json"
- "n_structure_object_unclosed_no_value.json"
- "n_structure_object_with_comment.json"
- "n_structure_object_with_trailing_garbage.json"
- "n_structure_open_array_apostrophe.json"
- "n_structure_open_array_comma.json"
- "n_structure_open_array_object.json"
- "n_structure_open_array_open_object.json"
- "n_structure_open_array_open_string.json"
- "n_structure_open_array_string.json"
- "n_structure_open_object_close_array.json"
- "n_structure_open_object_comma.json"
- "n_structure_open_object.json"
- "n_structure_open_object_open_array.json"
- "n_structure_open_object_open_string.json"
- "n_structure_open_object_string_with_apostrophes.json"
- "n_structure_open_open.json"
- "n_structure_single_eacute.json"
- "n_structure_single_star.json"
- "n_structure_trailing_#.json"
- "n_structure_U+2060_word_joined.json"
- "n_structure_uescaped_LF_before_string.json"
- "n_structure_unclosed_array.json"
- "n_structure_unclosed_array_partial_null.json"
- "n_structure_unclosed_array_unfinished_false.json"
- "n_structure_unclosed_array_unfinished_true.json"
- "n_structure_unclosed_object.json"
- "n_structure_unicode-identifier.json"
- "n_structure_UTF8_BOM_no_data.json"
- "n_structure_whitespace_formfeed.json"
- "n_structure_whitespace_U+2060_word_joiner.json"
-)
-
-# Implementation-defined tests (i_*.json)
-set(JSONTESTSUITE_IMPL_TESTS
- "i_number_double_huge_neg_exp.json"
- "i_number_huge_exp.json"
- "i_number_neg_int_huge_exp.json"
- "i_number_pos_double_huge_exp.json"
- "i_number_real_neg_overflow.json"
- "i_number_real_pos_overflow.json"
- "i_number_real_underflow.json"
- "i_number_too_big_neg_int.json"
- "i_number_too_big_pos_int.json"
- "i_number_very_big_negative_int.json"
- "i_object_key_lone_2nd_surrogate.json"
- "i_string_1st_surrogate_but_2nd_missing.json"
- "i_string_1st_valid_surrogate_2nd_invalid.json"
- "i_string_incomplete_surrogate_and_escape_valid.json"
- "i_string_incomplete_surrogate_pair.json"
- "i_string_incomplete_surrogates_escape_valid.json"
- "i_string_invalid_lonely_surrogate.json"
- "i_string_invalid_surrogate.json"
- "i_string_invalid_utf-8.json"
- "i_string_inverted_surrogates_U+1D11E.json"
- "i_string_iso_latin_1.json"
- "i_string_lone_second_surrogate.json"
- "i_string_lone_utf8_continuation_byte.json"
- "i_string_not_in_unicode_range.json"
- "i_string_overlong_sequence_2_bytes.json"
- "i_string_overlong_sequence_6_bytes.json"
- "i_string_overlong_sequence_6_bytes_null.json"
- "i_string_truncated-utf-8.json"
- "i_string_utf16BE_no_BOM.json"
- "i_string_utf16LE_no_BOM.json"
- "i_string_UTF-16LE_with_BOM.json"
- "i_string_UTF-8_invalid_sequence.json"
- "i_string_UTF8_surrogate_U+D800.json"
- "i_structure_500_nested_arrays.json"
- "i_structure_UTF-8_BOM_empty_object.json"
-)
#!/usr/bin/env bash
# Wrapper script to run a single TAP subtest
-# Usage: run-single-tap-test.sh <test_suite_name> <test_id>
-
-test_suite="$1"
-test_id="$2"
+# Usage: run-single-tap-test.sh <fy_tool_path> <test_suite_name> <test_id>
+
+FY_TOOL="$1"
+test_suite="$2"
+test_id="$3"
+
+if [ x"$FY_TOOL" = x -o x"$TEST_DIR" = x -o x"$test_suite" = x -o x"$test_id" = x ]; then
+ echo "Error: FY_TOOL, TEST_DIR, test_suite, test_id must exist"
+fi
+
+function is_windows_bash() {
+ case "$OSTYPE" in
+ msys*|cygwin*) return 0 ;;
+ *) return 1 ;;
+ esac
+}
+
+# convert to proper posix paths
+if is_windows_bash; then
+ FY_TOOL=`cygpath $FY_TOOL`
+ TEST_DIR=`cygpath $TEST_DIR`
+ YAML_TEST_SUITE=`cygpath $YAML_TEST_SUITE`
+ JSON_TEST_SUITE=`cygpath $JSON_TEST_SUITE`
+fi
+
+# if not given in the environment try to adjust
+if [ x"$YAML_TEST_SUITE" = x ]; then
+ YAML_TEST_SUITE="${TEST_DIR}/test-suite-data"
+fi
+
+if [ x"$JSON_TEST_SUITE" = x ]; then
+ JSON_TEST_SUITE="${TEST_DIR}/json-test-suite-data"
+fi
+
+# Validate tool exists
+if [ ! -x "$FY_TOOL" ]; then
+ echo "Error: fy-tool not found or not executable: $FY_TOOL" >&2
+ exit 1
+fi
+
+# Validate TEST_DIR exists
+if [ ! -d "$TEST_DIR" ]; then
+ echo "Error: TEST_DIR not found: $TEST_DIR" >&2
+ exit 1
+fi
case "$test_suite" in
testerrors)
- dir="${SRCDIR}/test-errors/${test_id}"
+ dir="${TEST_DIR}/test-errors/${test_id}"
desctxt=$(cat 2>/dev/null "$dir/===")
t=$(mktemp)
res="not ok"
pass_yaml=0
- ${TOP_BUILDDIR}/src/fy-tool --dump -r --no-streaming "$dir/in.yaml" >"$t" 2>&1
+ ${FY_TOOL} --dump -r --no-streaming "$dir/in.yaml" >"$t" 2>&1
if [ $? -eq 0 ]; then
pass_yaml=1
fi
- errmsg=$(cat "$t" | head -n1 | sed -e 's/^[^:]*//')
+ errmsg=$(cat "$t" | head -n1 | sed -e 's/^.*\(:[0-9]\{1,\}:[0-9]\{1,\}:\)/\1/')
echo "errmsg: $errmsg" >&2
# Replace with error message
# diff is pointless under valgrind
if [ "x$USE_VALGRIND" == "x" ]; then
diff_err=0
- diff -u "$dir/test.error" "$t"
+ diff -uw "$dir/test.error" "$t"
if [ $? -eq 0 ]; then
res="ok"
else
;;
testemitter)
- f="${SRCDIR}/emitter-examples/${test_id}"
+ f="${TEST_DIR}/emitter-examples/${test_id}"
t1=$(mktemp)
t2=$(mktemp)
res="not ok"
pass_parse=0
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers "$f" >"$t1"
+ ${FY_TOOL} --testsuite --disable-flow-markers "$f" >"$t1"
if [ $? -eq 0 ]; then
- ${TOP_BUILDDIR}/src/fy-tool --dump "$f" | \
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers - >"$t2"
+ ${FY_TOOL} --dump "$f" | \
+ ${FY_TOOL} --testsuite --disable-flow-markers - >"$t2"
if [ $? -eq 0 ]; then
pass_parse=1
fi
;;
testemitter-streaming)
- f="${SRCDIR}/emitter-examples/${test_id}"
+ f="${TEST_DIR}/emitter-examples/${test_id}"
t1=$(mktemp)
t2=$(mktemp)
res="not ok"
pass_parse=0
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers "$f" >"$t1"
+ ${FY_TOOL} --testsuite --disable-flow-markers "$f" >"$t1"
if [ $? -eq 0 ]; then
- ${TOP_BUILDDIR}/src/fy-tool --dump --streaming "$f" | \
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers - >"$t2"
+ ${FY_TOOL} --dump --streaming "$f" | \
+ ${FY_TOOL} --testsuite --disable-flow-markers - >"$t2"
if [ $? -eq 0 ]; then
pass_parse=1
fi
;;
testemitter-restreaming)
- f="${SRCDIR}/emitter-examples/${test_id}"
+ f="${TEST_DIR}/emitter-examples/${test_id}"
t1=$(mktemp)
t2=$(mktemp)
res="not ok"
pass_parse=0
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers "$f" >"$t1"
+ ${FY_TOOL} --testsuite --disable-flow-markers "$f" >"$t1"
if [ $? -eq 0 ]; then
- ${TOP_BUILDDIR}/src/fy-tool --dump --streaming --recreating "$f" | \
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers - >"$t2"
+ ${FY_TOOL} --dump --streaming --recreating "$f" | \
+ ${FY_TOOL} --testsuite --disable-flow-markers - >"$t2"
if [ $? -eq 0 ]; then
pass_parse=1
fi
;;
testsuite|testsuite-json|testsuite-resolution)
- tst="test-suite-data/${test_id}"
+ tst="${YAML_TEST_SUITE}/${test_id}"
desctxt=$(cat 2>/dev/null "$tst/===")
t=$(mktemp)
res="not ok"
pass_yaml=0
- ${TOP_BUILDDIR}/src/fy-tool --testsuite "$tst/in.yaml" >"$t"
+ ${FY_TOOL} --testsuite "$tst/in.yaml" >"$t"
if [ $? -eq 0 ]; then
pass_yaml=1
fi
;;
testsuite-evstream)
- tst="test-suite-data/${test_id}"
+ tst="${YAML_TEST_SUITE}/${test_id}"
desctxt=$(cat 2>/dev/null "$tst/===")
# Skip tests that are expected to fail
res="not ok"
# run the test using document-event-stream
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --document-event-stream "$tst/in.yaml" >"$t" 2>/dev/null
+ ${FY_TOOL} --testsuite --document-event-stream "$tst/in.yaml" >"$t" 2>/dev/null
if [ $? -eq 0 ]; then
diff -u "$tst/test.event" "$t"
if [ $? -eq 0 ]; then
jsontestsuite)
tf="$test_id"
- f="json-test-suite-data/test_parsing/${tf}"
+ f="${JSON_TEST_SUITE}/test_parsing/${tf}"
# Determine expected result based on prefix
case "$tf" in
y_*)
# Expected to pass
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --streaming "$f" >/dev/null 2>&1
+ ${FY_TOOL} --testsuite --streaming "$f" >/dev/null 2>&1
if [ $? -eq 0 ]; then
res="ok"
else
;;
n_*)
# Expected to fail
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --streaming "$f" >/dev/null 2>&1
+ ${FY_TOOL} --testsuite --streaming "$f" >/dev/null 2>&1
if [ $? -eq 0 ]; then
res="not ok"
else
;;
i_*)
# Implementation defined - we'll accept either result as ok
- ${TOP_BUILDDIR}/src/fy-tool --testsuite --streaming "$f" >/dev/null 2>&1
+ ${FY_TOOL} --testsuite --streaming "$f" >/dev/null 2>&1
res="ok"
;;
*)
+++ /dev/null
-# Script to set up test suite data in an idempotent way
-
-if(NOT DEFINED REPO_NAME)
- set(REPO_NAME "test-suite-data")
-endif()
-
-set(REPO_DIR "${TEST_DIR}/${REPO_NAME}")
-
-# Check if the repository already exists
-if(EXISTS "${REPO_DIR}/.git")
- message(STATUS "Repository ${REPO_NAME} already exists, updating...")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} fetch -q origin
- WORKING_DIRECTORY ${REPO_DIR}
- RESULT_VARIABLE GIT_FETCH_RESULT
- )
- if(NOT GIT_FETCH_RESULT EQUAL 0)
- message(WARNING "Failed to fetch updates for ${REPO_NAME}")
- endif()
-else()
- message(STATUS "Cloning ${REPO_NAME}...")
- execute_process(
- COMMAND ${GIT_EXECUTABLE} clone -q "${TESTSUITEURL}" ${REPO_NAME}
- WORKING_DIRECTORY ${TEST_DIR}
- RESULT_VARIABLE GIT_CLONE_RESULT
- )
- if(NOT GIT_CLONE_RESULT EQUAL 0)
- message(FATAL_ERROR "Failed to clone ${REPO_NAME}")
- endif()
-endif()
-
-# Checkout the specific commit
-execute_process(
- COMMAND ${GIT_EXECUTABLE} checkout -q --detach ${TESTSUITECHECKOUT}
- WORKING_DIRECTORY ${REPO_DIR}
- RESULT_VARIABLE GIT_CHECKOUT_RESULT
-)
-if(NOT GIT_CHECKOUT_RESULT EQUAL 0)
- message(FATAL_ERROR "Failed to checkout ${TESTSUITECHECKOUT} in ${REPO_NAME}")
-endif()
-
-message(STATUS "Test suite ${REPO_NAME} set up successfully")
+++ /dev/null
-# Auto-generated file - do not edit manually
-# Generated by cmake/generate-testsuite-list.sh
-#
-# This file contains lists of tests from the YAML test suite
-# It allows registering individual tests without requiring the test data
-# to be downloaded first.
-
-# Test suite checkout: 6e6c296ae9c9d2d5c4134b4b64d01b29ac19ff6f
-# Generated on: 2025-10-24 08:04:38 UTC
-# Base tests: 350
-
-# List of base test IDs
-set(TESTSUITE_BASE_TESTS
- 229Q
- 236B
- 26DV
- 27NA
- 2AUY
- 2CMS
- 2EBW
- 2G84
- 2JQS
- 2LFX
- 2SXE
- 2XXW
- 33X3
- 35KP
- 36F6
- 3ALJ
- 3GZX
- 3HFZ
- 3MYT
- 3R3P
- 3RLN
- 3UYS
- 4ABK
- 4CQQ
- 4EJS
- 4FJ6
- 4GC6
- 4H7K
- 4HVU
- 4JVG
- 4MUZ
- 4Q9F
- 4QFQ
- 4RWC
- 4UYU
- 4V8U
- 4WA9
- 4ZYM
- 52DL
- 54T7
- 55WF
- 565N
- 57H4
- 58MP
- 5BVJ
- 5C5M
- 5GBF
- 5KJE
- 5LLU
- 5MUD
- 5NYZ
- 5T43
- 5TRB
- 5TYM
- 5U3A
- 5WE3
- 62EZ
- 652Z
- 65WH
- 6BCT
- 6BFJ
- 6CA3
- 6CK3
- 6FWR
- 6H3V
- 6HB6
- 6JQW
- 6JTT
- 6JWB
- 6KGN
- 6LVF
- 6M2F
- 6PBE
- 6S55
- 6SLA
- 6VJK
- 6WLZ
- 6WPF
- 6XDY
- 6ZKB
- 735Y
- 74H7
- 753E
- 7A4E
- 7BMT
- 7BUB
- 7FWL
- 7LBH
- 7MNF
- 7T8X
- 7TMG
- 7W2P
- 7Z25
- 7ZZ5
- 82AN
- 87E4
- 8CWC
- 8G76
- 8KB6
- 8MK2
- 8QBE
- 8UDB
- 8XDJ
- 8XYN
- 93JH
- 93WF
- 96L6
- 96NN
- 98YD
- 9BXH
- 9C9N
- 9CWY
- 9DXL
- 9FMG
- 9HCY
- 9J7A
- 9JBA
- 9KAX
- 9KBC
- 9MAG
- 9MMA
- 9MMW
- 9MQT
- 9SA2
- 9SHH
- 9TFX
- 9U5K
- 9WXW
- 9YRD
- A2M4
- A6F9
- A984
- AB8U
- AVM7
- AZ63
- AZW3
- B3HG
- B63P
- BD7L
- BEC7
- BF9H
- BS4K
- BU8L
- C2DT
- C2SP
- C4HZ
- CC74
- CFD4
- CML9
- CN3R
- CPZ3
- CQ3W
- CT4Q
- CTN5
- CUP7
- CVW2
- CXX2
- D49Q
- D83L
- D88J
- D9TU
- DBG4
- DC7X
- DE56
- DFF7
- DHP8
- DK3J
- DK4H
- DK95
- DMG6
- DWX9
- E76Z
- EB22
- EHF6
- EW3V
- EX5H
- EXG3
- F2C7
- F3CP
- F6MC
- F8F9
- FBC9
- FH7J
- FP8R
- FQ7F
- FRK4
- FTA2
- FUP4
- G4RS
- G5U8
- G7JE
- G992
- G9HC
- GDY7
- GH63
- GT5M
- H2RW
- H3Z8
- H7J7
- H7TQ
- HM87
- HMK4
- HMQ5
- HRE5
- HS5T
- HU3P
- HWV9
- J3BT
- J5UC
- J7PZ
- J7VC
- J9HZ
- JEF9
- JHB9
- JKF3
- JQ4R
- JR7V
- JS2J
- JTV5
- JY7Z
- K3WX
- K4SU
- K527
- K54U
- K858
- KH5V
- KK5P
- KMK3
- KS4U
- KSS4
- L24T
- L383
- L94M
- L9U5
- LE5A
- LHL4
- LP6E
- LQZ7
- LX3P
- M29M
- M2N8
- M5C3
- M5DY
- M6YH
- M7A3
- M7NX
- M9B4
- MJS9
- MUS6
- MXS3
- MYW6
- MZX3
- N4JP
- N782
- NAT4
- NB6Z
- NHX8
- NJ66
- NKF9
- NP9H
- P2AD
- P2EQ
- P76L
- P94K
- PBJ2
- PRH3
- PUW8
- PW8X
- Q4CL
- Q5MG
- Q88A
- Q8AD
- Q9WF
- QB6E
- QF4Y
- QLJ7
- QT73
- R4YG
- R52L
- RHX7
- RLU9
- RR7F
- RTP8
- RXY3
- RZP5
- RZT7
- S3PD
- S4GJ
- S4JQ
- S4T7
- S7BG
- S98Z
- S9E8
- SBG9
- SF5V
- SKE5
- SM9W
- SR86
- SSW6
- SU5Z
- SU74
- SY6V
- SYW4
- T26H
- T4YY
- T5N4
- T833
- TD5N
- TE2A
- TL85
- TS54
- U3C3
- U3XV
- U44R
- U99R
- U9NS
- UDM2
- UDR7
- UGM3
- UKK6
- UT92
- UV7Q
- V55R
- V9D5
- VJP3
- W42U
- W4TN
- W5VH
- W9L4
- WZ62
- X38W
- X4QW
- X8DW
- XLQ9
- XV9V
- XW4D
- Y2GN
- Y79Y
- YD5X
- YJV2
- Z67P
- Z9M4
- ZCZ6
- ZF4X
- ZH7C
- ZK9H
- ZL4Z
- ZVH3
- ZWK4
- ZXT5
-)
-
-# List of all tests (including subtests)
-# Format: BASE or BASE/SUBTEST
-set(TESTSUITE_ALL_TESTS
- "229Q"
- "236B"
- "26DV"
- "27NA"
- "2AUY"
- "2CMS"
- "2EBW"
- "2G84/00"
- "2G84/01"
- "2G84/02"
- "2G84/03"
- "2JQS"
- "2LFX"
- "2SXE"
- "2XXW"
- "33X3"
- "35KP"
- "36F6"
- "3ALJ"
- "3GZX"
- "3HFZ"
- "3MYT"
- "3R3P"
- "3RLN/00"
- "3RLN/01"
- "3RLN/02"
- "3RLN/03"
- "3RLN/04"
- "3RLN/05"
- "3UYS"
- "4ABK"
- "4CQQ"
- "4EJS"
- "4FJ6"
- "4GC6"
- "4H7K"
- "4HVU"
- "4JVG"
- "4MUZ/00"
- "4MUZ/01"
- "4MUZ/02"
- "4Q9F"
- "4QFQ"
- "4RWC"
- "4UYU"
- "4V8U"
- "4WA9"
- "4ZYM"
- "52DL"
- "54T7"
- "55WF"
- "565N"
- "57H4"
- "58MP"
- "5BVJ"
- "5C5M"
- "5GBF"
- "5KJE"
- "5LLU"
- "5MUD"
- "5NYZ"
- "5T43"
- "5TRB"
- "5TYM"
- "5U3A"
- "5WE3"
- "62EZ"
- "652Z"
- "65WH"
- "6BCT"
- "6BFJ"
- "6CA3"
- "6CK3"
- "6FWR"
- "6H3V"
- "6HB6"
- "6JQW"
- "6JTT"
- "6JWB"
- "6KGN"
- "6LVF"
- "6M2F"
- "6PBE"
- "6S55"
- "6SLA"
- "6VJK"
- "6WLZ"
- "6WPF"
- "6XDY"
- "6ZKB"
- "735Y"
- "74H7"
- "753E"
- "7A4E"
- "7BMT"
- "7BUB"
- "7FWL"
- "7LBH"
- "7MNF"
- "7T8X"
- "7TMG"
- "7W2P"
- "7Z25"
- "7ZZ5"
- "82AN"
- "87E4"
- "8CWC"
- "8G76"
- "8KB6"
- "8MK2"
- "8QBE"
- "8UDB"
- "8XDJ"
- "8XYN"
- "93JH"
- "93WF"
- "96L6"
- "96NN/00"
- "96NN/01"
- "98YD"
- "9BXH"
- "9C9N"
- "9CWY"
- "9DXL"
- "9FMG"
- "9HCY"
- "9J7A"
- "9JBA"
- "9KAX"
- "9KBC"
- "9MAG"
- "9MMA"
- "9MMW"
- "9MQT/00"
- "9MQT/01"
- "9SA2"
- "9SHH"
- "9TFX"
- "9U5K"
- "9WXW"
- "9YRD"
- "A2M4"
- "A6F9"
- "A984"
- "AB8U"
- "AVM7"
- "AZ63"
- "AZW3"
- "B3HG"
- "B63P"
- "BD7L"
- "BEC7"
- "BF9H"
- "BS4K"
- "BU8L"
- "C2DT"
- "C2SP"
- "C4HZ"
- "CC74"
- "CFD4"
- "CML9"
- "CN3R"
- "CPZ3"
- "CQ3W"
- "CT4Q"
- "CTN5"
- "CUP7"
- "CVW2"
- "CXX2"
- "D49Q"
- "D83L"
- "D88J"
- "D9TU"
- "DBG4"
- "DC7X"
- "DE56/00"
- "DE56/01"
- "DE56/02"
- "DE56/03"
- "DE56/04"
- "DE56/05"
- "DFF7"
- "DHP8"
- "DK3J"
- "DK4H"
- "DK95/00"
- "DK95/01"
- "DK95/02"
- "DK95/03"
- "DK95/04"
- "DK95/05"
- "DK95/06"
- "DK95/07"
- "DK95/08"
- "DMG6"
- "DWX9"
- "E76Z"
- "EB22"
- "EHF6"
- "EW3V"
- "EX5H"
- "EXG3"
- "F2C7"
- "F3CP"
- "F6MC"
- "F8F9"
- "FBC9"
- "FH7J"
- "FP8R"
- "FQ7F"
- "FRK4"
- "FTA2"
- "FUP4"
- "G4RS"
- "G5U8"
- "G7JE"
- "G992"
- "G9HC"
- "GDY7"
- "GH63"
- "GT5M"
- "H2RW"
- "H3Z8"
- "H7J7"
- "H7TQ"
- "HM87/00"
- "HM87/01"
- "HMK4"
- "HMQ5"
- "HRE5"
- "HS5T"
- "HU3P"
- "HWV9"
- "J3BT"
- "J5UC"
- "J7PZ"
- "J7VC"
- "J9HZ"
- "JEF9/00"
- "JEF9/01"
- "JEF9/02"
- "JHB9"
- "JKF3"
- "JQ4R"
- "JR7V"
- "JS2J"
- "JTV5"
- "JY7Z"
- "K3WX"
- "K4SU"
- "K527"
- "K54U"
- "K858"
- "KH5V/00"
- "KH5V/01"
- "KH5V/02"
- "KK5P"
- "KMK3"
- "KS4U"
- "KSS4"
- "L24T/00"
- "L24T/01"
- "L383"
- "L94M"
- "L9U5"
- "LE5A"
- "LHL4"
- "LP6E"
- "LQZ7"
- "LX3P"
- "M29M"
- "M2N8/00"
- "M2N8/01"
- "M5C3"
- "M5DY"
- "M6YH"
- "M7A3"
- "M7NX"
- "M9B4"
- "MJS9"
- "MUS6/00"
- "MUS6/01"
- "MUS6/02"
- "MUS6/03"
- "MUS6/04"
- "MUS6/05"
- "MUS6/06"
- "MXS3"
- "MYW6"
- "MZX3"
- "N4JP"
- "N782"
- "NAT4"
- "NB6Z"
- "NHX8"
- "NJ66"
- "NKF9"
- "NP9H"
- "P2AD"
- "P2EQ"
- "P76L"
- "P94K"
- "PBJ2"
- "PRH3"
- "PUW8"
- "PW8X"
- "Q4CL"
- "Q5MG"
- "Q88A"
- "Q8AD"
- "Q9WF"
- "QB6E"
- "QF4Y"
- "QLJ7"
- "QT73"
- "R4YG"
- "R52L"
- "RHX7"
- "RLU9"
- "RR7F"
- "RTP8"
- "RXY3"
- "RZP5"
- "RZT7"
- "S3PD"
- "S4GJ"
- "S4JQ"
- "S4T7"
- "S7BG"
- "S98Z"
- "S9E8"
- "SBG9"
- "SF5V"
- "SKE5"
- "SM9W/00"
- "SM9W/01"
- "SR86"
- "SSW6"
- "SU5Z"
- "SU74"
- "SY6V"
- "SYW4"
- "T26H"
- "T4YY"
- "T5N4"
- "T833"
- "TD5N"
- "TE2A"
- "TL85"
- "TS54"
- "U3C3"
- "U3XV"
- "U44R"
- "U99R"
- "U9NS"
- "UDM2"
- "UDR7"
- "UGM3"
- "UKK6/00"
- "UKK6/01"
- "UKK6/02"
- "UT92"
- "UV7Q"
- "V55R"
- "V9D5"
- "VJP3/00"
- "VJP3/01"
- "W42U"
- "W4TN"
- "W5VH"
- "W9L4"
- "WZ62"
- "X38W"
- "X4QW"
- "X8DW"
- "XLQ9"
- "XV9V"
- "XW4D"
- "Y2GN"
- "Y79Y/000"
- "Y79Y/001"
- "Y79Y/002"
- "Y79Y/003"
- "Y79Y/004"
- "Y79Y/005"
- "Y79Y/006"
- "Y79Y/007"
- "Y79Y/008"
- "Y79Y/009"
- "Y79Y/010"
- "YD5X"
- "YJV2"
- "Z67P"
- "Z9M4"
- "ZCZ6"
- "ZF4X"
- "ZH7C"
- "ZK9H"
- "ZL4Z"
- "ZVH3"
- "ZWK4"
- "ZXT5"
-)
@rm -rf Makefile.in
EXTRA_DIST = \
+ canned-man/fy-tool.1 \
conf.py \
+ include \
index.rst \
intro.rst \
libfyaml.rst \
man/fy-tool.rst \
- canned-man/fy-tool.1
+ windows-support.txt
--- /dev/null
+You need to download msvc and the winsdk
+I used git@github.com:mstorsjo/msvc-wine.git
+
+Assume that you've installed at "${MSVC}"
+
+== Build with MSVC using wine
+
+$ mkdir build-msvc
+$ cd build-msvc
+$ export PATH="${MSVC}/bin/x64:/usr/bin:$PATH"
+$ CC=cl CXX=cl cmake -S .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_MAKE_PROGRAM=/usr/bin/make
+
+=== Build with clang-cl without wine
+
+$ sudo apt-get install clang-cl llvm # I used clang-cl-18
+$ mkdir build-clang-cl
+$ cd build-clang-cl
+$ export INCLUDE="${MSVC}/vc/tools/msvc/14.44.35207/include;${MSVC}/kits/10/include/10.0.26100.0/shared;${MSVC}/kits/10/include/10.0.26100.0/ucrt;${MSVC}/kits/10/include/10.0.26100.0/um"
+$ export LIB="${MSVC}/vc/tools/msvc/14.44.35207/lib/x64;${MSVC}/kits/10/lib/10.0.26100.0/ucrt/x64;${MSVC}/kits/10/lib/10.0.26100.0/um/x64"
+$ cmake .. \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_SYSTEM_NAME=Windows \
+ -DCMAKE_C_COMPILER=clang-cl-18 \
+ -DCMAKE_CXX_COMPILER=clang-cl-18 \
+ -DCMAKE_LINKER=lld-link-18 \
+ -DCMAKE_MT=llvm-mt-18 \
+ -DCMAKE_RC_COMPILER=llvm-rc-18
+
+=== Build with native clang cross compiling for windows
+$ export INCLUDE="${MSVC}/vc/tools/msvc/14.44.35207/include;${MSVC}/kits/10/include/10.0.26100.0/shared;${MSVC}/kits/10/include/10.0.26100.0/ucrt;${MSVC}/kits/10/include/10.0.26100.0/um"
+$ export LIB="${MSVC}/vc/tools/msvc/14.44.35207/lib/x64;${MSVC}/kits/10/lib/10.0.26100.0/ucrt/x64;${MSVC}/kits/10/lib/10.0.26100.0/um/x64"
+$ cmake .. \
+ -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_TOOLCHAIN_FILE=../cmake/clang-windows-toolchain.cmake
+
+
+--- new method
+
+=== MSVC using wine
+$ cmake -DMSVC_WINE_DIR="${MSVC}" -DMSVC_WINE_COMPILER=cl ..
+
+=== clang-cl
+$ cmake -DMSVC_WINE_DIR="${MSVC}" -DMSVC_WINE_COMPILER=clang-cl ..
+
+=== clang cross
+$ cmake -DMSVC_WINE_DIR="${MSVC}" -DMSVC_WINE_COMPILER=clang ..
#if defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))
#include <unistd.h>
+#include <sys/uio.h>
+#elif defined(_WIN32)
+/* Windows compatibility definitions */
+#ifndef _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED
+#ifdef _WIN64
+typedef __int64 ssize_t;
+#else
+typedef int ssize_t;
#endif
-
+#endif
+/* Windows doesn't have sys/uio.h, provide iovec definition */
+#ifndef _FY_IOVEC_DEFINED
+#define _FY_IOVEC_DEFINED
+struct iovec {
+ void *iov_base;
+ size_t iov_len;
+};
+#endif
+#else
#include <sys/uio.h>
+#endif
/* opaque types for the user */
struct fy_token;
/* NULL terminated string length specifier */
#define FY_NT ((size_t)-1)
+/* DLL export/import macros
+ * Note: On Windows, a .def file (src/lib/fyaml.def) is used to export
+ * public API symbols. The FY_EXPORT macro is kept for GCC visibility.
+ */
#if defined(__GNUC__) && __GNUC__ >= 4
#define FY_EXPORT __attribute__ ((visibility ("default")))
#define FY_DEPRECATED __attribute__ ((deprecated))
#define FY_FORMAT(_t, _x, _y) __attribute__ ((format(_t, _x, _y)))
+#elif defined(_MSC_VER)
+#define FY_EXPORT /* nothing - exports handled via .def file */
+#define FY_DEPRECATED /* nothing - MSVC __declspec must be prefix */
+#define FY_FORMAT(_t, _x, _y) /* nothing */
#else
#define FY_EXPORT /* nothing */
#define FY_DEPRECATED /* nothing */
* If the _str pointer is NULL, then NULL will be returned
*/
#ifndef FY_ALLOCA_COPY_FREE
+#ifdef _MSC_VER
+/*
+ * MSVC doesn't support GCC statement expressions, so we provide
+ * function-based alternatives using thread-local storage.
+ */
+#define FY_ALLOCA_COPY_FREE_BUFSZ 8192
+static __declspec(thread) char fy_alloca_copy_free_buf[FY_ALLOCA_COPY_FREE_BUFSZ];
+
+static __inline const char *fy_alloca_copy_free_impl(char *str, size_t len)
+{
+ size_t actual_len;
+ if (!str)
+ return NULL;
+ actual_len = (len == FY_NT) ? strlen(str) : len;
+ if (actual_len >= FY_ALLOCA_COPY_FREE_BUFSZ)
+ actual_len = FY_ALLOCA_COPY_FREE_BUFSZ - 1;
+ memcpy(fy_alloca_copy_free_buf, str, actual_len);
+ fy_alloca_copy_free_buf[actual_len] = '\0';
+ free(str);
+ return fy_alloca_copy_free_buf;
+}
+
+#define FY_ALLOCA_COPY_FREE(_str, _len) \
+ fy_alloca_copy_free_impl((_str), (size_t)(_len))
+
+#define FY_ALLOCA_COPY_FREE_NO_NULL(_str, _len) \
+ (fy_alloca_copy_free_impl((_str), (size_t)(_len)) ? fy_alloca_copy_free_buf : "")
+
+#else
+/* GCC/Clang version with statement expressions */
#define FY_ALLOCA_COPY_FREE(_str, _len) \
({ \
char *__str = (_str), *__stra = NULL; \
} \
(const char *)__stra; \
})
-#endif
/* same as above but when _str == NULL return "" */
-#ifndef FY_ALLOCA_COPY_FREE_NO_NULL
#define FY_ALLOCA_COPY_FREE_NO_NULL(_str, _len) \
({ \
const char *__strb; \
__strb; \
})
#endif
+#endif
/**
* DOC: libfyaml public API
fy_token_get_text_length(struct fy_token *fyt)
FY_EXPORT;
-/**
- * fy_token_get_utf8_length() - Get length of the text of a token
- *
- * This method will return the length of the text representation
- * of a token as a utf8 string.
- *
- * @fyt: The token
- *
- * Returns:
- * The size of the utf8 text representation of a token, -1 in case of an error.
- * Note that the NULL token will return a length of zero.
- */
-size_t
-fy_token_get_utf8_length(struct fy_token *fyt)
- FY_EXPORT;
-
/**
* enum fy_comment_placement - Comment placement relative to token
*
/**
* fy_token_get_comment() - Get zero terminated comment of a token
*
+ * Get the comment that is attached at a token having the given
+ * placement.
+ *
* @fyt: The token out of which the comment text will be returned.
- * @buf: The buffer to be filled with the contents of the token
- * @maxsz: The maximum size of the comment buffer
* @which: The comment placement
*
* Returns:
* NULL in case of an error or if the token has no comment.
*/
const char *
-fy_token_get_comment(struct fy_token *fyt, char *buf, size_t maxsz,
- enum fy_comment_placement which)
+fy_token_get_comment(struct fy_token *fyt, enum fy_comment_placement which)
+ FY_EXPORT;
+
+/**
+ * fy_token_get_comments() - Get all comments of a token
+ *
+ * Get all the comments that are attached on a token
+ *
+ * @fyt: The token
+ *
+ * Returns:
+ * A pointer to a zero terminated text representation of all the comments.
+ * The comments of all the placements are concatenated and returned as one.
+ * NULL in case of an error or if the event has no comments.
+ */
+const char *
+fy_token_get_comments(struct fy_token *fyt)
+ FY_EXPORT;
+
+/**
+ * fy_token_set_comment() - Attach a comment to a token
+ *
+ * Attach the given comment on the token at the specified placement.
+ * If another comment is already present it will be overriden.
+ * If text is NULL the comment is removed.
+ *
+ * @fyt: The token out of which the comment text will be attached
+ * @which: The placement
+ * @text: The text of the comment
+ * @len: The length of the comment (FY_NT means the length of text)
+ *
+ * Returns:
+ * 0 on success, -1 on failure.
+ */
+int
+fy_token_set_comment(struct fy_token *fyt, enum fy_comment_placement which,
+ const char *text, size_t len)
+ FY_EXPORT;
+
+/**
+ * fy_event_get_comments() - Get all comments of an event
+ *
+ * @fye: The event
+ *
+ * Returns:
+ * A pointer to a zero terminated text representation of all the comments.
+ * The comments of all the placements are concatenated and returned as one.
+ * NULL in case of an error or if the event has no comments.
+ * The pointer must be free'ed if it's not NULL via a call to free()
+ */
+const char *
+fy_event_get_comments(struct fy_event *fye)
+ FY_EXPORT;
+
+/**
+ * fy_node_get_comment() - Get comment of a node
+ *
+ * @fyn: The node
+ * @placement: The placement of the comment
+ *
+ * Returns:
+ * A pointer to a zero terminated text representation of the comment.
+ * NULL in case of an error or if the event has no such comments.
+ */
+const char *
+fy_node_get_comment(struct fy_node *fyn, enum fy_comment_placement which)
+ FY_EXPORT;
+
+/**
+ * fy_node_get_comments() - Get all comments of a node
+ *
+ * @fyn: The node
+ *
+ * Returns:
+ * A pointer to a zero terminated text representation of all the comments.
+ * The comments of all the placements are concatenated and returned as one.
+ * NULL in case of an error or if the event has no comments.
+ */
+const char *
+fy_node_get_comments(struct fy_node *fyn)
FY_EXPORT;
/**
fy_emit_to_string_collect(struct fy_emitter *emit, size_t *sizep)
FY_EXPORT;
-/**
- * fy_emitter_vlog() - Log using the emitters diagnostics printf style (va_arg)
- *
- * Output a log on the emitter diagnostic output
- *
- * @emit: The emitter
- * @type: The error type
- * @fmt: The printf format string
- * @ap: The argument list
- */
-void
-fy_emitter_vlog(struct fy_emitter *emit, enum fy_error_type type, const char *fmt, va_list ap)
- FY_EXPORT;
-
-/**
- * fy_emitter_log() - Log using the emitters diagnostics printf style
- *
- * Output a report on the emitter's diagnostics
- *
- * @emit: The emitter
- * @type: The error type
- * @fmt: The printf format string
- * @...: The extra arguments
- */
-void
-fy_emitter_log(struct fy_emitter *emit, enum fy_error_type type, const char *fmt, ...)
- FY_FORMAT(printf, 3, 4)
- FY_EXPORT;
-
-#ifndef NDEBUG
-
-#define fy_emitter_debug(_emit, _fmt, ...) \
- fy_emitter_log((_emit), FYET_DEBUG, (_fmt) , ## __VA_ARGS__)
-#else
-
-#define fy_emitter_debug(_emit, _fmt, ...) \
- do { } while(0)
-
-#endif
-
-#define fy_emitter_info(_emit, _fmt, ...) \
- fy_emitter_log((_emit), FYET_INFO, (_fmt) , ## __VA_ARGS__)
-#define fy_emitter_notice(_emit, _fmt, ...) \
- fy_emitter_log((_emit), FYET_NOTICE, (_fmt) , ## __VA_ARGS__)
-#define fy_emitter_warning(_emit, _fmt, ...) \
- fy_emitter_log((_emit), FYET_WARNING, (_fmt) , ## __VA_ARGS__)
-#define fy_emitter_error(_emit, _fmt, ...) \
- fy_emitter_log((_emit), FYET_ERROR, (_fmt) , ## __VA_ARGS__)
-
/**
* fy_node_copy() - Copy a node, associating the new node with the given document
*
fy_node_get_style(struct fy_node *fyn)
FY_EXPORT;
+/**
+ * fy_node_set_style() - Set the node style
+ *
+ * Try to set the node rendering style of a node.
+ * If the style of node is illegal (for example
+ * you can't set an arbitrary scalar that contains
+ * zeroes to plain) then the actual style that was
+ * set will be returned.
+ *
+ * @fyn: The node
+ *
+ * Returns:
+ * The final node style
+ */
+enum fy_node_style
+fy_node_set_style(struct fy_node *fyn, enum fy_node_style style)
+ FY_EXPORT;
+
/**
* fy_node_get_start_token() - Get the node start token
*
fy_diag_set_collect_errors(struct fy_diag *diag, bool collect_errors)
FY_EXPORT;
+/**
+ * fy_diag_get_collect_errors() - Get collect errors state
+ *
+ * Get the collect errors mode.
+ *
+ * @diag: The diagnostic object
+ *
+ * Returns:
+ * true collecting errors, false otherwise
+ */
+bool
+fy_diag_get_collect_errors(struct fy_diag *diag)
+ FY_EXPORT;
+
/**
* fy_diag_cfg_default() - Fill in the configuration structure
* with defaults
FY_FORMAT(printf, 3, 4)
FY_EXPORT;
+#ifdef _MSC_VER
+/* MSVC doesn't support GCC statement expressions, use do-while(0) instead */
+#define fy_diag_diag(_diag, _level, _fmt, ...) \
+ do { \
+ struct fy_diag_ctx _ctx; \
+ memset(&_ctx, 0, sizeof(_ctx)); \
+ _ctx.level = (_level); \
+ _ctx.module = FYEM_UNKNOWN; \
+ _ctx.source_func = __func__; \
+ _ctx.source_file = __FILE__; \
+ _ctx.source_line = __LINE__; \
+ fy_diagf((_diag), &_ctx, (_fmt) , ## __VA_ARGS__); \
+ } while(0)
+#else
#define fy_diag_diag(_diag, _level, _fmt, ...) \
({ \
struct fy_diag_ctx _ctx = { \
}; \
fy_diagf((_diag), &_ctx, (_fmt) , ## __VA_ARGS__); \
})
+#endif
#ifndef NDEBUG
FY_FORMAT(printf, 5, 6)
FY_EXPORT;
-/**
- * fy_diag_event_override_vreport() - Report about a token vprintf style,
- * overriding file, line and column info using
- * the given diagnostic object
- *
- * Output a report about the given event part via the specific
- * error type. This method will use the overrides provided in order
- * to massage the reporting information.
- * If @file is NULL, no file location will be reported.
- * If either @line or @column is negative no location will be reported.
- *
- * @diag: The diag object
- * @fye: The event
- * @fyep: The event part
- * @type: The error type
- * @file: The file override
- * @line: The line override
- * @column: The column override
- * @fmt: The printf format string
- * @ap: The argument list
- */
-void
-fy_diag_event_override_vreport(struct fy_diag *diag, struct fy_event *fye,
- enum fy_event_part fyep, enum fy_error_type type,
- const char *file, int line, int column,
- const char *fmt, va_list ap)
- FY_EXPORT;
-
-/**
- * fy_diag_event_override_report() - Report about a token printf style,
- * overriding file, line and column info using
- * the given diagnostic object
- *
- * Output a report about the given event part via the specific
- * error type. This method will use the overrides provided in order
- * to massage the reporting information.
- * If @file is NULL, no file location will be reported.
- * If either @line or @column is negative no location will be reported.
- *
- * @diag: The diag object
- * @fyt: The event
- * @fyep: The event part
- * @type: The error type
- * @file: The file override
- * @line: The line override
- * @column: The column override
- * @fmt: The printf format string
- * @...: The extra arguments.
- */
-void
-fy_diag_event_override_report(struct fy_diag *diag, struct fy_token *fyt,
- enum fy_event_part fyep, enum fy_error_type type,
- const char *file, int line, int column,
- const char *fmt, ...)
- FY_FORMAT(printf, 8, 9)
- FY_EXPORT;
-
/**
* fy_diag_errors_iterate() - Iterate over the errors of a diagnostic object
*
uninstall-hook:
(cd "$(DESTDIR)$(bindir)" && rm -f fy-dump fy-filter fy-testsuite fy-join fy-ypath fy-compose)
+
+EXTRA_DIST = \
+ getopt/getopt.c \
+ getopt/getopt.h \
+ util/fy-win32.h
+
/* for container_of */
#include "fy-list.h"
#include "fy-utils.h"
+#include "fy-win32.h"
#include "fy-allocator-dedup.h"
// #define DEBUG_GROWS
+#ifdef DEBUG_GROWS
+
#undef BEFORE
#define BEFORE() \
do { \
} while(0)
#undef AFTER
+#ifdef _MSC_VER
+static __inline int64_t fy_dedup_after_calc(const struct timespec *before, const struct timespec *after)
+{
+ return (int64_t)(after->tv_sec - before->tv_sec) * (int64_t)1000000000UL + (int64_t)(after->tv_nsec - before->tv_nsec);
+}
+#define AFTER() \
+ (clock_gettime(CLOCK_MONOTONIC, &after), fy_dedup_after_calc(&before, &after))
+#else
#define AFTER() \
({ \
clock_gettime(CLOCK_MONOTONIC, &after); \
(int64_t)(after.tv_sec - before.tv_sec) * (int64_t)1000000000UL + (int64_t)(after.tv_nsec - before.tv_nsec); \
})
+#endif
+
+#endif
static const unsigned int bit_to_chain_length_map[] = {
[0] = 1, /* 1 */
{
struct fy_dedup_allocator *da = dtd->cfg.da;
- fy_parent_allocator_free(&da->a, dtd->buckets);
- fy_parent_allocator_free(&da->a, dtd->bloom_id);
- fy_parent_allocator_free(&da->a, dtd->buckets_in_use);
+ fy_parent_allocator_free(&da->a, (void *)dtd->buckets);
+ fy_parent_allocator_free(&da->a, (void *)dtd->bloom_id);
+ fy_parent_allocator_free(&da->a, (void *)dtd->buckets_in_use);
}
static int fy_dedup_tag_data_setup(struct fy_dedup_tag_data *dtd,
dtd->chain_length_grow_trigger++;
}
- dtd->bloom_filter_mask = (1U << dtd->bloom_filter_bits) - 1;
- dtd->bucket_count_mask = (1U << dtd->bucket_count_bits) - 1;
+ dtd->bloom_filter_mask = ((unsigned int)1 << dtd->bloom_filter_bits) - 1;
+ dtd->bucket_count_mask = ((unsigned int)1 << dtd->bucket_count_bits) - 1;
- dtd->bloom_id_count = ((1U << dtd->bloom_filter_bits) + FY_ID_BITS_BITS - 1) / FY_ID_BITS_BITS;
+ dtd->bloom_id_count = (((size_t)1 << dtd->bloom_filter_bits) + FY_ID_BITS_BITS - 1) / FY_ID_BITS_BITS;
assert(dtd->bloom_id_count > 0);
tmpsz = dtd->bloom_id_count * sizeof(*dtd->bloom_id);
dtd->bloom_id = fy_parent_allocator_alloc(&da->a, tmpsz, _Alignof(fy_id_bits));
goto err_out;
fy_id_reset(dtd->bloom_id, dtd->bloom_id_count);
- dtd->bucket_count = 1U << dtd->bucket_count_bits;
+ dtd->bucket_count = (size_t)1 << dtd->bucket_count_bits;
assert(dtd->bucket_count);
tmpsz = sizeof(*dtd->buckets) * dtd->bucket_count;
for (i = 0; i < dtd->bucket_count; i++)
atomic_store(&dtd->buckets[i], NULL);
- dtd->bucket_id_count = ((1U << dtd->bucket_count_bits) + FY_ID_BITS_BITS - 1) / FY_ID_BITS_BITS;
+ dtd->bucket_id_count = (((size_t)1 << dtd->bucket_count_bits) + FY_ID_BITS_BITS - 1) / FY_ID_BITS_BITS;
assert(dtd->bucket_id_count > 0);
tmpsz = dtd->bucket_id_count * sizeof(*dtd->buckets_in_use);
dtd->buckets_in_use = fy_parent_allocator_alloc(&da->a, tmpsz, _Alignof(fy_id_bits));
return -1;
}
- bucket_count = 1U << dtd->bucket_count_bits;
+ bucket_count = (size_t)1 << dtd->bucket_count_bits;
bucket_used = fy_id_count_used(dtd->buckets_in_use, dtd->bucket_id_count);
- occupancy_ratio = (double)bucket_used/(double)bucket_count;
+ occupancy_ratio = (float)((double)bucket_used/(double)bucket_count);
/* do not grow until we're over 60% full */
if (occupancy_ratio < da->cfg.minimum_bucket_occupancy) {
fy_dedup_tag_cleanup(da, dt);
}
- fy_parent_allocator_free(&da->a, da->ids);
+ fy_parent_allocator_free(&da->a, (void *)da->ids);
fy_parent_allocator_free(&da->a, da->tags);
}
bucket_count_bits = cfg->bucket_count_bits;
if (!bucket_count_bits && has_estimate) {
bucket_count_bits = 1;
- while ((1LU << bucket_count_bits) < (cfg->estimated_content_size / BUCKET_ESTIMATE_DIV))
+ while (((size_t)1 << bucket_count_bits) < (cfg->estimated_content_size / BUCKET_ESTIMATE_DIV))
bucket_count_bits++;
#ifdef DEBUG_GROWS
fprintf(stderr, "bucket_count_bits %u\n", bucket_count_bits);
bloom_filter_bits = cfg->bloom_filter_bits;
if (!bloom_filter_bits && has_estimate) {
bloom_filter_bits = 1;
- while ((1LU << bloom_filter_bits) < (cfg->estimated_content_size / BLOOM_ESTIMATE_DIV))
+ while (((size_t)1 << bloom_filter_bits) < (cfg->estimated_content_size / BLOOM_ESTIMATE_DIV))
bloom_filter_bits++;
#ifdef DEBUG_GROWS
fprintf(stderr, "bloom_filter_bits %u\n", bloom_filter_bits);
/* verify it's aligned correctly */
assert(((uintptr_t)mem & (align - 1)) == 0);
- de = mem + de_offset;
+ de = (void *)((char *)mem + de_offset);
de->hash = hash;
de->size = total_size;
if (da->ids != ids) {
da->ids = ids;
- fy_parent_allocator_free(&da->a, da->ids);
+ fy_parent_allocator_free(&da->a, (void *)da->ids);
}
da->tag_count = tag_count;
err_out:
fy_parent_allocator_free(&da->a, alloc_tags);
- fy_parent_allocator_free(&da->a, alloc_ids);
+ fy_parent_allocator_free(&da->a, (void *)alloc_ids);
return -1;
}
buf = cfg->buf;
s = buf;
- e = s + cfg->size;
+ e = (char *)s + cfg->size;
s = fy_ptr_align(s, _Alignof(struct fy_linear_allocator));
- if ((size_t)(e - s) < sizeof(*la))
+ if ((size_t)((char *)e - (char *)s) < sizeof(*la))
goto err_out;
la = s;
- s += sizeof(*la);
+ s = (char *)s + sizeof(*la);
memset(&newcfg, 0, sizeof(newcfg));
newcfg.buf = s;
- newcfg.size = (size_t)(e - s);
+ newcfg.size = (size_t)((char *)e - (char *)s);
rc = fy_linear_setup(&la->a, parent, parent_tag, &newcfg);
if (rc)
/* atomically update the pointer */
do {
next = fy_atomic_load(&la->next);
- s = fy_ptr_align(la->start + next, align);
- new_next = (s + size) - la->start;
+ s = fy_ptr_align((char *)la->start + next, align);
+ new_next = (size_t)(((char *)s + size) - (char *)la->start);
/* handle both overflow and underflow */
if (new_next > la->cfg.size)
goto err_out;
if (a->flags & FYAF_KEEP_STATS) {
la = container_of(a, struct fy_linear_allocator, a);
-
fy_atomic_fetch_add(&la->stores, 1);
fy_atomic_fetch_add(&la->stores, size);
}
struct fy_linear_allocator *la;
la = container_of(a, struct fy_linear_allocator, a);
- return ptr >= la->start && ptr < (la->start + la->cfg.size);
+ return (char *)ptr >= (char *)la->start &&
+ (char *)ptr < ((char *)la->start + la->cfg.size);
}
const struct fy_allocator_ops fy_linear_allocator_ops = {
#include <stdalign.h>
#include <time.h>
#include <inttypes.h>
-
#include <stdio.h>
/* for container_of */
#include "fy-list.h"
#include "fy-utils.h"
+#include "fy-align.h"
+#include "fy-win32.h"
#include "fy-allocator-malloc.h"
/* cleanup should happen from a single thread */
while ((me = fy_malloc_entry_list_pop(&mt->entries)) != NULL)
- free(me->mem);
+ fy_align_free(me->mem);
}
static void fy_malloc_cleanup(struct fy_allocator *a)
fy_malloc_tag_cleanup(ma, mt);
}
- fy_parent_allocator_free(&ma->a, ma->ids);
- fy_parent_allocator_free(&ma->a, ma->tags);
+ fy_parent_allocator_free(&ma->a, (void *)ma->ids);
+ fy_parent_allocator_free(&ma->a, (void *)ma->tags);
}
static int fy_malloc_setup(struct fy_allocator *a, struct fy_allocator *parent, int parent_tag, const void *data)
{
struct fy_malloc_entry *me;
size_t me_offset, max_align;
- int r;
void *mem;
me_offset = fy_size_t_align(size, _Alignof(struct fy_malloc_entry));
max_align = align > _Alignof(struct fy_malloc_entry) ? align : _Alignof(struct fy_malloc_entry);
- r = posix_memalign(&mem, max_align, me_offset + sizeof(*me));
- if (r)
+ mem = fy_align_alloc(max_align, me_offset + sizeof(*me));
+ if (!mem)
return NULL;
- me = mem + me_offset;
+ me = (void *)((char *)mem + me_offset);
me->size = size;
fy_malloc_tag_list_lock(mt);
fy_malloc_entry_list_del(&mt->entries, me);
fy_malloc_tag_list_unlock(mt);
- free(me->mem);
+ fy_align_free(me->mem);
}
static void *fy_malloc_alloc(struct fy_allocator *a, int tag, size_t size, size_t align)
}
if (ma->ids != ids) {
ma->ids = ids;
- fy_parent_allocator_free(&ma->a, ma->ids);
+ fy_parent_allocator_free(&ma->a, (void *)ma->ids);
}
ma->tag_count = tag_count;
ma->tag_id_count = tag_id_count;
err_out:
fy_parent_allocator_free(&ma->a, tags);
- fy_parent_allocator_free(&ma->a, ids);
+ fy_parent_allocator_free(&ma->a, (void *)ids);
return -1;
}
/* no lock, reset is single thread only */
while ((me = fy_malloc_entry_list_pop(&mt->entries)) != NULL)
- free(me->mem);
+ fy_align_free(me);
}
static struct fy_allocator_info *
for (me = fy_malloc_entry_list_head(&mt->entries); me;
me = fy_malloc_entry_next(&mt->entries, me)) {
- if (ptr >= (void *)me->mem && ptr < (void *)me->mem + me->size) {
+ if (ptr >= (void *)me->mem &&
+ ptr < (void *)((char *)me->mem + me->size)) {
fy_malloc_tag_list_unlock(mt);
return true;
}
#include <time.h>
#include <inttypes.h>
#include <math.h>
+#include <stdio.h>
+
+#ifndef _WIN32
#include <sys/mman.h>
+#include <unistd.h>
+#endif
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
-
-#include <stdio.h>
-
/* for container_of */
#include "fy-list.h"
#include "fy-utils.h"
+#include "fy-win32.h"
#include "fy-allocator-mremap.h"
// #define DEBUG_ARENA
-#if defined(__NetBSD__)
+#if defined(__NetBSD__) || defined(_WIN32)
#define DISABLE_MREMAP
#endif
if (size < mra->minimum_arena_size)
size = mra->minimum_arena_size;
- size_page_align = fy_mremap_useable_arena_size(mra, size);
+ /* need to be aligned to page boundary */
+ size_page_align = fy_size_t_align(fy_mremap_useable_arena_size(mra, size), mra->pagesz);
switch (mra->arena_type) {
case FYMRAT_MALLOC:
mran = malloc(size_page_align);
/* either it fails, or it moves we handle it */
#else
/* we don't shrink, we just unmap over the limit */
- rc = munmap(mem + size_page_align, balloon_size - size_page_align);
+ rc = munmap((char *)mem + size_page_align, balloon_size - size_page_align);
if (rc) {
#ifdef DEBUG_ARENA
fprintf(stderr, "%s: failed to unmap for shink\n", __func__);
assert(mem == mran);
#else
/* do a mmap right after the one we have, if it succeeds we have grown */
- mem = mmap((void *)mran + mran->size, mran->size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
- if (mem != (void *)mran + mran->size) {
+ mem = mmap((char *)mran + mran->size, mran->size, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
+ if (mem != (char *)mran + mran->size) {
if (mem != MAP_FAILED)
munmap(mem, mran->size);
break;
return -1;
#else
/* we don't shrink, we just unmap over the limit */
- rc = munmap((void *)mran + new_size, mran->size - new_size);
+ rc = munmap((char *)mran + new_size, mran->size - new_size);
if (rc)
return -1;
#endif
#endif
goto again;
}
- ptr = (void *)mran + data_pos;
+ ptr = (void *)((char *)mran + data_pos);
} while (!fy_atomic_compare_exchange_strong(&mran->next, &old_next, new_next));
/* malloc arenas need to zero out */
fy_mremap_tag_cleanup(mra, mrt);
}
- fy_parent_allocator_free(&mra->a, mra->ids);
+ fy_parent_allocator_free(&mra->a, (void *)mra->ids);
fy_parent_allocator_free(&mra->a, mra->tags);
}
}
if (mra->ids != ids) {
mra->ids = ids;
- fy_parent_allocator_free(&mra->a, mra->ids);
+ fy_parent_allocator_free(&mra->a, (void *)mra->ids);
}
mra->tag_count = tag_count;
mra->tag_id_count = tag_id_count;
err_out:
fy_parent_allocator_free(&mra->a, tags);
- fy_parent_allocator_free(&mra->a, ids);
+ fy_parent_allocator_free(&mra->a, (void *)ids);
return -1;
}
arena_info->free = arena_free;
arena_info->used = arena_used;
arena_info->total = arena_total;
- arena_info->data = (void *)mran + FY_MREMAP_ARENA_OVERHEAD;
+ arena_info->data = (char *)mran + FY_MREMAP_ARENA_OVERHEAD;
arena_info->size = arena_info->used;
arena_info++;
tag_info->num_arena_infos++;
for (mra = fy_atomic_load(&mrt->arenas); mra; mra = mra->next_arena) {
if (p >= (const void *)mra->mem &&
- p < (const void *)mra->mem + mra->size)
+ p < (const void *)((const char *)mra->mem + mra->size))
return true;
}
#include <stdio.h>
+#ifndef _WIN32
#include <sys/mman.h>
-
-#ifndef FY_NON_LOCKING_REGISTRY
#include <pthread.h>
#endif
/* for container_of */
#include "fy-list.h"
#include "fy-utils.h"
+#include "fy-align.h"
+#include "fy-win32.h"
#include "fy-allocator.h"
#include "fy-allocator-linear.h"
static bool allocator_registry_locked = false;
#ifndef FY_NON_LOCKING_REGISTRY
+
+#if !defined(_WIN32)
+
static pthread_mutex_t allocator_registry_mutex = PTHREAD_MUTEX_INITIALIZER;
static inline void allocator_registry_lock(void)
{
- int rc FY_UNUSED;
+ int rc FY_DEBUG_UNUSED;
rc = pthread_mutex_lock(&allocator_registry_mutex);
assert(!rc);
static inline void allocator_registry_unlock(void)
{
- int rc FY_UNUSED;
+ int rc FY_DEBUG_UNUSED;
assert(allocator_registry_locked);
allocator_registry_locked = false;
rc = pthread_mutex_unlock(&allocator_registry_mutex);
assert(!rc);
}
-#else
+
+#else // _WIN32
+
+static CRITICAL_SECTION allocator_registry_mutex;
+static LONG allocator_registry_mutex_initialized = 0;
+static inline void allocator_registry_lock(void)
+{
+ /* Initialize on first use using interlocked operation */
+ if (InterlockedCompareExchange(&allocator_registry_mutex_initialized, 1, 0) == 0)
+ InitializeCriticalSection(&allocator_registry_mutex);
+ EnterCriticalSection(&allocator_registry_mutex);
+ assert(!allocator_registry_locked);
+ allocator_registry_locked = true;
+}
+
+static inline void allocator_registry_unlock(void)
+{
+ assert(allocator_registry_locked);
+ allocator_registry_locked = false;
+ LeaveCriticalSection(&allocator_registry_mutex);
+}
+
+#endif
+
+#else // FY_NON_LOCKING_REGISTRY
+
static inline void allocator_registry_lock(void)
{
/* nothing */
}
static inline void allocator_registry_unlock(void)
{
+
/* nothing */
}
#endif
{
if (!a || !ptr)
return;
- return fy_allocator_free_nocheck(a, tag, ptr);
+ fy_allocator_free_nocheck(a, tag, ptr);
}
const void *fy_allocator_storev_hash(struct fy_allocator *a, int tag, const struct iovec *iov, int iovcnt, size_t align, uint64_t hash)
/* respects the parent allocator (or uses posix_memalign if NULL) */
void *fy_early_parent_allocator_alloc(struct fy_allocator *parent, int parent_tag, size_t size, size_t align)
{
- void *ptr;
- int r;
-
/* yeah, not gonna work */
if (parent == FY_PARENT_ALLOCATOR_INPLACE)
return NULL;
if (parent)
return fy_allocator_alloc(parent, parent_tag, size, align);
- r = posix_memalign(&ptr, align, size);
- if (r)
- return NULL;
-
- return ptr;
+ return fy_align_alloc(align, size);
}
void fy_early_parent_allocator_free(struct fy_allocator *parent, int parent_tag, void *ptr)
if (parent)
fy_allocator_free(parent, parent_tag, ptr);
else
- free(ptr);
+ fy_align_free(ptr);
}
/* respects the parent allocator (or uses posix_memalign if NULL) */
if (!a || !ptr)
return;
- return fy_early_parent_allocator_free(a->parent, a->parent_tag, ptr);
+ fy_early_parent_allocator_free(a->parent, a->parent_tag, ptr);
}
#include <stdbool.h>
#include <assert.h>
+#ifndef _WIN32
#include <sys/uio.h>
+#endif
#include "fy-typelist.h"
#include "fy-utils.h"
+#include "fy-win32.h"
#include <libfyaml.h>
void (*trim_tag)(struct fy_allocator *a, int tag);
void (*reset_tag)(struct fy_allocator *a, int tag);
struct fy_allocator_info *(*get_info)(struct fy_allocator *a, int tag);
- unsigned int (*get_caps)(struct fy_allocator *a); /* Get capability flags (FYACF_*) */
+ enum fy_allocator_cap_flags (*get_caps)(struct fy_allocator *a); /* Get capability flags (FYACF_*) */
bool (*contains)(struct fy_allocator *a, int tag, const void *ptr);
};
#include <alloca.h>
#endif
+#ifndef _WIN32
#include <pthread.h>
-#include <stdlib.h>
+#endif
#include "blake3.h"
#include "blake3_impl.h"
#include "blake3_internal.h"
+#include "fy-win32.h"
#include "fy-thread.h"
// GCC gets confused sometimes
#include <stddef.h>
#include <stdint.h>
-#include <pthread.h>
#include <stdalign.h>
#define BLAKE3_VERSION_STRING "1.4.1"
#include <string.h>
#include <stdio.h>
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-
#include <stdlib.h>
-#include <unistd.h>
#include "fy-bit64.h"
#endif
#include <stdlib.h>
-#include <unistd.h>
#include "blake3.h"
#include "blake3_impl.h"
#include "blake3_internal.h"
#include "fy-thread.h"
+#include "fy-win32.h"
struct cpusimd_data {
unsigned int num_cpus;
if (num_cpus <= 1)
return 0;
- num_simd_cpus = round_down_to_power_of_2(num_cpus);
+ num_simd_cpus = (unsigned int)round_down_to_power_of_2(num_cpus);
if (!mult_fact)
mult_fact = 1;
#include <stdbool.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
+#ifndef _WIN32
#include <pthread.h>
-#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
-#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
+#endif
#include "fy-bit64.h"
#include "blake3_internal.h"
#include "fy-thread.h"
+#include "fy-win32.h"
/* 256K threshold for using alloca */
#define BLAKE3_ALLOCA_BUFFER_SIZE (256U << 10)
while (left > 0) {
chunk = left > max_chunk ? max_chunk : left;
blake3_hasher_update(hasher, p, chunk);
- p += chunk;
+ p = (char *)p + chunk;
left -= chunk;
}
} else {
#include <string.h>
#include <stdatomic.h>
#include <stdalign.h>
-
-#ifndef _WIN32
#include <stdlib.h>
-#if defined(__linux__)
-#include <malloc.h>
-#endif
-#endif
#if defined(__linux__)
+#include <malloc.h>
#include <sys/sysmacros.h>
#endif
#if defined(IS_X86)
#if defined(_MSC_VER)
+#if defined(__clang__)
+/* clang-cl: intrin.h pulls in mmintrin.h which has vector type bugs
+ * when cross-compiling. Declare only the intrinsics we actually need. */
+unsigned long long _xgetbv(unsigned int);
+void __cpuid(int[4], int);
+#else
#include <intrin.h>
#endif
#endif
+#endif
/* Find index of the highest set bit */
/* x is assumed to be nonzero. */
#include <stddef.h>
#include <stdint.h>
-#include <pthread.h>
-#include <stdatomic.h>
#include "blake3.h"
#include <stdbool.h>
#include <stdint.h>
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
-#endif
-
#include <stdlib.h>
#include <errno.h>
--- /dev/null
+Copyright (c) 2012-2023, Kim Grasman <kim.grasman@gmail.com>
+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.
+ * Neither the name of Kim Grasman nor the
+ names of contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 KIM GRASMAN 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.
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2012-2023, Kim Grasman <kim.grasman@gmail.com>
+ * 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.
+ * * Neither the name of Kim Grasman nor the
+ * names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 KIM GRASMAN 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 <stddef.h>
+#include <string.h>
+
+#include "getopt.h"
+
+char* optarg;
+int optopt;
+/* The variable optind [...] shall be initialized to 1 by the system. */
+int optind = 1;
+int opterr;
+
+static char* optcursor = NULL;
+
+/* Implemented based on [1] and [2] for optional arguments.
+ optopt is handled FreeBSD-style, per [3].
+ Other GNU and FreeBSD extensions are purely accidental.
+
+[1] http://pubs.opengroup.org/onlinepubs/000095399/functions/getopt.html
+[2] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
+[3] http://www.freebsd.org/cgi/man.cgi?query=getopt&sektion=3&manpath=FreeBSD+9.0-RELEASE
+*/
+int getopt(int argc, char* const argv[], const char* optstring) {
+ int optchar = -1;
+ const char* optdecl = NULL;
+
+ optarg = NULL;
+ opterr = 0;
+ optopt = 0;
+
+ /* Unspecified, but we need it to avoid overrunning the argv bounds. */
+ if (optind >= argc)
+ goto no_more_optchars;
+
+ /* If, when getopt() is called argv[optind] is a null pointer, getopt()
+ shall return -1 without changing optind. */
+ if (argv[optind] == NULL)
+ goto no_more_optchars;
+
+ /* If, when getopt() is called *argv[optind] is not the character '-',
+ getopt() shall return -1 without changing optind. */
+ if (*argv[optind] != '-')
+ goto no_more_optchars;
+
+ /* If, when getopt() is called argv[optind] points to the string "-",
+ getopt() shall return -1 without changing optind. */
+ if (strcmp(argv[optind], "-") == 0)
+ goto no_more_optchars;
+
+ /* If, when getopt() is called argv[optind] points to the string "--",
+ getopt() shall return -1 after incrementing optind. */
+ if (strcmp(argv[optind], "--") == 0) {
+ ++optind;
+ goto no_more_optchars;
+ }
+
+ if (optcursor == NULL || *optcursor == '\0')
+ optcursor = argv[optind] + 1;
+
+ optchar = *optcursor;
+
+ /* FreeBSD: The variable optopt saves the last known option character
+ returned by getopt(). */
+ optopt = optchar;
+
+ /* The getopt() function shall return the next option character (if one is
+ found) from argv that matches a character in optstring, if there is
+ one that matches. */
+ optdecl = strchr(optstring, optchar);
+ if (optdecl) {
+ /* [I]f a character is followed by a colon, the option takes an
+ argument. */
+ if (optdecl[1] == ':') {
+ optarg = ++optcursor;
+ if (*optarg == '\0') {
+ /* GNU extension: Two colons mean an option takes an
+ optional arg; if there is text in the current argv-element
+ (i.e., in the same word as the option name itself, for example,
+ "-oarg"), then it is returned in optarg, otherwise optarg is set
+ to zero. */
+ if (optdecl[2] != ':') {
+ /* If the option was the last character in the string pointed to by
+ an element of argv, then optarg shall contain the next element
+ of argv, and optind shall be incremented by 2. If the resulting
+ value of optind is greater than argc, this indicates a missing
+ option-argument, and getopt() shall return an error indication.
+
+ Otherwise, optarg shall point to the string following the
+ option character in that element of argv, and optind shall be
+ incremented by 1.
+ */
+ if (++optind < argc) {
+ optarg = argv[optind];
+ } else {
+ /* If it detects a missing option-argument, it shall return the
+ colon character ( ':' ) if the first character of optstring
+ was a colon, or a question-mark character ( '?' ) otherwise.
+ */
+ optarg = NULL;
+ optchar = (optstring[0] == ':') ? ':' : '?';
+ }
+ } else {
+ optarg = NULL;
+ }
+ }
+
+ optcursor = NULL;
+ }
+ } else {
+ /* If getopt() encounters an option character that is not contained in
+ optstring, it shall return the question-mark ( '?' ) character. */
+ optchar = '?';
+ }
+
+ if (optcursor == NULL || *++optcursor == '\0')
+ ++optind;
+
+ return optchar;
+
+no_more_optchars:
+ optcursor = NULL;
+ return -1;
+}
+
+/* Implementation based on [1].
+
+[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
+*/
+int getopt_long(int argc, char* const argv[], const char* optstring,
+ const struct option* longopts, int* longindex) {
+ const struct option* o = longopts;
+ const struct option* match = NULL;
+ int num_matches = 0;
+ size_t argument_name_length = 0;
+ size_t option_length = 0;
+ const char* current_argument = NULL;
+ int retval = -1;
+
+ optarg = NULL;
+ optopt = 0;
+
+ if (optind >= argc)
+ return -1;
+
+ if (strlen(argv[optind]) < 3 || strncmp(argv[optind], "--", 2) != 0)
+ return getopt(argc, argv, optstring);
+
+ /* It's an option; starts with -- and is longer than two chars. */
+ current_argument = argv[optind] + 2;
+ argument_name_length = strcspn(current_argument, "=");
+ for (; o->name; ++o) {
+ /* Check for exact match first. */
+ option_length = strlen(o->name);
+ if (option_length == argument_name_length &&
+ strncmp(o->name, current_argument, option_length) == 0) {
+ match = o;
+ num_matches = 1;
+ break;
+ }
+
+ /* If not exact, count the number of abbreviated matches. */
+ if (strncmp(o->name, current_argument, argument_name_length) == 0) {
+ match = o;
+ ++num_matches;
+ }
+ }
+
+ if (num_matches == 1) {
+ /* If longindex is not NULL, it points to a variable which is set to the
+ index of the long option relative to longopts. */
+ if (longindex)
+ *longindex = (int)(match - longopts);
+
+ /* If flag is NULL, then getopt_long() shall return val.
+ Otherwise, getopt_long() returns 0, and flag shall point to a variable
+ which shall be set to val if the option is found, but left unchanged if
+ the option is not found. */
+ if (match->flag)
+ *(match->flag) = match->val;
+
+ retval = match->flag ? 0 : match->val;
+
+ if (match->has_arg != no_argument) {
+ optarg = strchr(argv[optind], '=');
+ if (optarg != NULL)
+ ++optarg;
+
+ if (match->has_arg == required_argument) {
+ /* Only scan the next argv for required arguments. Behavior is not
+ specified, but has been observed with Ubuntu and Mac OSX. */
+ if (optarg == NULL && ++optind < argc) {
+ optarg = argv[optind];
+ }
+
+ if (optarg == NULL)
+ retval = ':';
+ }
+ } else if (strchr(argv[optind], '=')) {
+ /* An argument was provided to a non-argument option.
+ I haven't seen this specified explicitly, but both GNU and BSD-based
+ implementations show this behavior.
+ */
+ retval = '?';
+ }
+ } else {
+ /* Unknown option or ambiguous match. */
+ retval = '?';
+ }
+
+ ++optind;
+ return retval;
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2012-2023, Kim Grasman <kim.grasman@gmail.com>
+ * 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.
+ * * Neither the name of Kim Grasman nor the
+ * names of contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 KIM GRASMAN 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.
+ *
+ ******************************************************************************/
+
+#ifndef INCLUDED_GETOPT_PORT_H
+#define INCLUDED_GETOPT_PORT_H
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define no_argument 1
+#define required_argument 2
+#define optional_argument 3
+
+extern char* optarg;
+extern int optind, opterr, optopt;
+
+struct option {
+ const char* name;
+ int has_arg;
+ int* flag;
+ int val;
+};
+
+int getopt(int argc, char* const argv[], const char* optstring);
+
+int getopt_long(int argc, char* const argv[],
+ const char* optstring, const struct option* longopts, int* longindex);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // INCLUDED_GETOPT_PORT_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <assert.h>
+#include <time.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdalign.h>
+
+#ifndef _WIN32
#include <unistd.h>
#include <fcntl.h>
-#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
-
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
+#else
+#include "fy-win32.h"
#endif
-#include <stdbool.h>
#include <getopt.h>
-#include <ctype.h>
-#include <assert.h>
-#include <time.h>
-#include <stdint.h>
-#include <inttypes.h>
-#include <stdalign.h>
#include <libfyaml.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <assert.h>
+
+#ifdef HAVE_ALLOCA_H
+#include <alloca.h>
+#endif
+
+#ifndef _WIN32
#include <unistd.h>
#include <fcntl.h>
-#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
-
-#ifdef HAVE_ALLOCA_H
-#include <alloca.h>
+#else
+#include "fy-win32.h"
#endif
-#include <stdbool.h>
#include <getopt.h>
-#include <ctype.h>
-#include <assert.h>
-#include <stdatomic.h>
#include <blake3.h>
#define OPT_NO_MMAP 128
while (isxdigit((unsigned char)*s))
s++;
- length = s - linebuf;
+ length = (unsigned int)(s - linebuf);
if (length == 0 || length > (BLAKE3_OUT_LEN * 2) || (length % 1) || !isspace((unsigned char)*s)) {
fprintf(stderr, "Bad line found at file \"%s\" line #%d\n", check_filename, line);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
#include <stdbool.h>
-#include <getopt.h>
#include <ctype.h>
#include <assert.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
-#include <stdatomic.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#else
+#include "fy-win32.h"
+#endif
+
+#include <getopt.h>
#include <libfyaml.h>
#include "fy-atomics.h"
#include "fy-thread.h"
+/* Helper to get number of online processors */
+static inline unsigned int get_num_processors(void)
+{
+ long scval = sysconf(_SC_NPROCESSORS_ONLN);
+ return scval > 0 ? (unsigned int)scval : 1;
+}
+
static void test_worker_thread_fn(void *arg)
{
FY_ATOMIC(int) *p = arg;
struct fy_thread_pool *tp;
struct fy_thread **threads, *t;
struct fy_thread_work *works;
- long scval;
unsigned int i, count, num_cpus;
int rc, test_count;
(void)rc;
- if (num_threads == 0) {
- scval = sysconf(_SC_NPROCESSORS_ONLN);
- assert(scval > 0);
- num_cpus = (unsigned int)scval;
- } else
- num_cpus = num_threads;
+ num_cpus = (num_threads == 0) ? get_num_processors() : num_threads;
memset(&tp_cfg, 0, sizeof(tp_cfg));
tp_cfg.flags = 0;
struct fy_thread_pool_cfg tp_cfg;
struct fy_thread_pool *tp;
void **args;
- long scval;
unsigned int count, num_cpus;
int rc, test_count;
(void)rc;
- if (num_threads == 0) {
- scval = sysconf(_SC_NPROCESSORS_ONLN);
- assert(scval > 0);
- num_cpus = (unsigned int)scval;
- } else
- num_cpus = num_threads;
+ num_cpus = (num_threads == 0) ? get_num_processors() : num_threads;
memset(&tp_cfg, 0, sizeof(tp_cfg));
tp_cfg.flags = 0;
struct fy_thread_pool *tp;
struct fy_thread **threads, *t;
struct fy_thread_work *works;
- long scval;
unsigned int i, count, num_cpus;
int rc;
struct thread_latency_state *states, *s;
(void)rc;
- if (num_threads == 0) {
- scval = sysconf(_SC_NPROCESSORS_ONLN);
- assert(scval > 0);
- num_cpus = (unsigned int)scval;
- } else
- num_cpus = num_threads;
+ num_cpus = (num_threads == 0) ? get_num_processors() : num_threads;
memset(&tp_cfg, 0, sizeof(tp_cfg));
tp_cfg.flags = 0;
struct fy_thread_pool_cfg tp_cfg;
struct fy_thread_pool *tp;
void **args;
- long scval;
unsigned int count, num_cpus;
int rc, test_count;
(void)rc;
- if (num_threads == 0) {
- scval = sysconf(_SC_NPROCESSORS_ONLN);
- assert(scval > 0);
- num_cpus = (unsigned int)scval;
- } else
- num_cpus = num_threads;
-
+ num_cpus = (num_threads == 0) ? get_num_processors() : num_threads;
tp_cfg.flags = FYTPCF_STEAL_MODE;
tp_cfg.num_threads = num_cpus;
uint64_t sum;
unsigned int pos;
- pos = s->values - s->values_start;
+ pos = (unsigned int)(s->values - s->values_start);
assert(pos <= s->count_start);
assert(pos + s->count <= s->count_start);
struct fy_thread_pool *tp;
struct timespec before, after;
unsigned int i, num_cpus;
- long scval;
uint8_t *values;
int rc;
uint64_t sum_single, sum_multi;
struct sum_args args[2];
- long long table_multi[times];
+ long long *table_multi;
long long ns;
+ table_multi = (long long *)malloc(times * sizeof(long long));
+ assert(table_multi);
+
(void)rc;
fprintf(stderr, "**********************************************************************\n");
ns = delta_ns(before, after);
fprintf(stderr, "%s: calculated sum=%"PRIu64" (single threaded) done in %lldus\n", __func__, sum_single, ns / 1000);
- if (num_threads == 0) {
- scval = sysconf(_SC_NPROCESSORS_ONLN);
- assert(scval > 0);
- num_cpus = (unsigned int)scval;
- } else
- num_cpus = num_threads;
+ num_cpus = (num_threads == 0) ? get_num_processors() : num_threads;
memset(&tp_cfg, 0, sizeof(tp_cfg));
tp_cfg.flags = steal_mode ? FYTPCF_STEAL_MODE : 0;
fy_thread_pool_destroy(tp);
+ free(table_multi);
free(values);
}
#include <time.h>
#include <inttypes.h>
-#include <libfyaml.h>
+#include <getopt.h>
+
+#ifndef _WIN32
+#include "fy-win32.h"
+#endif
#if defined(HAVE_LIBYAML) && HAVE_LIBYAML
#include <yaml.h>
#endif
+#include <libfyaml.h>
+
#include "fy-parse.h"
#include "fy-walk.h"
#include "fy-blob.h"
struct fy_atom *handle;
enum fy_comment_placement placement;
static const char *placement_txt[] = { "top", "right", "bottom" };
- char buf[1024];
+ const char *comment;
fydi = fy_document_iterator_create();
assert(fydi);
if (!handle || !fy_atom_is_set(handle))
continue;
- if (!fy_token_get_comment(fyt, buf, sizeof(buf), placement))
+ comment = fy_token_get_comment(fyt, placement);
+ if (!comment)
continue;
- fprintf(stderr, "%s: %s\n", placement_txt[placement], buf);
+ fprintf(stderr, "%s: %s\n", placement_txt[placement], comment);
}
free(path);
key = fy_kv_store_key_by_index(&kvs, idx);
assert(key);
- printf("removing #%d - %s\n", idx, key);
+ printf("removing #%d - %s\n", idx, key ? key : "<NULL>");
rc = fy_kv_store_remove(&kvs, key);
assert(!rc);
FILE *fp;
char *mbuf = NULL;
size_t msize;
+ struct fy_memstream *fyms = NULL;
- fp = open_memstream(&mbuf, &msize);
+ fyms = fy_memstream_open(&fp);
+ assert(fyms);
assert(fp);
fy_diag_cfg_default(&dcfg);
fy_diag_destroy(diag);
- fclose(fp);
-
+ mbuf = fy_memstream_close(fyms, &msize);
assert(mbuf);
printf("checking diagnostic\n");
FILE *fp;
char *mbuf = NULL;
size_t msize;
+ struct fy_memstream *fyms = NULL;
- fp = open_memstream(&mbuf, &msize);
- assert(fp);
+ fyms = fy_memstream_open(&fp);
+ assert(fyms);
fy_diag_cfg_default(&dcfg);
dcfg.fp = NULL;
fy_diag_destroy(diag);
- fclose(fp);
-
+ mbuf = fy_memstream_close(fyms, &msize);
assert(mbuf);
printf("checking diagnostic\n");
assert(fwr);
fwr->type = fwrt_node_ref;
fwr->fyn = fyn;
- result = fy_path_expr_execute(fypx, 0, expr, fwr, fpet_none);
+ result = fy_path_expr_execute(fypx, 0, expr, fwr, fpet_none, NULL);
printf("\n");
if (!result) {
int fy_accel_grow(struct fy_accel *xl)
{
+ unsigned int idx;
+
if (!xl)
return -1;
/* should not grow indefinetely */
- if (xl->next_exp2 >= sizeof(prime_lt_pow2)/sizeof(prime_lt_pow2[0]))
+ idx = xl->next_exp2 + 1;
+ if (idx >= ARRAY_SIZE(prime_lt_pow2))
return -1;
- return fy_accel_resize(xl, prime_lt_pow2[xl->next_exp2 + 1]);
+ return fy_accel_resize(xl, prime_lt_pow2[idx]);
}
int fy_accel_shrink(struct fy_accel *xl)
if (!atom)
return NULL;
- return fy_input_start(atom->fyi) + atom->start_mark.input_pos;
+ return (const char *)fy_input_start(atom->fyi) + atom->start_mark.input_pos;
}
int fy_reader_advance_mark(struct fy_reader *fyr, int advance, struct fy_mark *m)
{
- int i, c, tabsize;
+ int c, tabsize, w;
bool is_line_break;
tabsize = fy_reader_tabsize(fyr);
- i = 0;
while (advance-- > 0) {
- c = fy_reader_peek_at(fyr, i++);
+ c = fy_reader_peek_at_offset_width(fyr, m->input_pos, &w);
if (c == -1)
return -1;
m->input_pos += fy_utf8_width(c);
/* first check for CR/LF */
- if (c == '\r' && fy_reader_peek_at(fyr, i) == '\n') {
+ if (c == '\r' &&
+ fy_reader_peek_at_offset(fyr, m->input_pos + (size_t)w) == '\n') {
m->input_pos++;
- i++;
is_line_break = true;
} else if (fy_reader_is_lb(fyr, c))
is_line_break = true;
return 0;
}
-/* keep it around without a warning even though it's unused */
-static int
-_fy_atom_iter_add_utf8(struct fy_atom_iter *iter, int c)
- __attribute__((__unused__));
-
-static int
-_fy_atom_iter_add_utf8(struct fy_atom_iter *iter, int c)
-{
- char buf[FY_UTF8_FORMAT_BUFMIN];
- char *e;
-
- /* only fails if invalid utf8 */
- e = fy_utf8_put(buf, sizeof(buf), c);
- if (!e)
- return -1;
-
- return _fy_atom_iter_add_chunk_copy(iter, buf, e - buf);
-}
-
/* optimized linebreaks */
static int
_fy_atom_iter_add_lb(struct fy_atom_iter *iter, int c)
#ifndef DEBUG_CHUNK
#define fy_atom_iter_add_chunk _fy_atom_iter_add_chunk
#define fy_atom_iter_add_chunk_copy _fy_atom_iter_add_chunk_copy
-#define fy_atom_iter_add_utf8 _fy_atom_iter_add_utf8
#define fy_atom_iter_add_lb _fy_atom_iter_add_lb
#else
#define fy_atom_iter_add_chunk(_iter, _str, _len) \
} \
__ret; \
})
-#define fy_atom_iter_add_utf8(_iter, _c) \
- ({ \
- int __c = (_c); \
- fprintf(stderr, "%s:%d utf8 %d\n", __func__, __LINE__, __c); \
- _fy_atom_iter_add_utf8((_iter), (_c)); \
- })
#define fy_atom_iter_add_lb(_iter, _c) \
({ \
int __c = (_c); \
{
const struct fy_atom *atom = iter->atom;
const char *s, *e, *ss;
- int col, c, w, ts, cws, advws;
+ int col, c, cn, w, wn, ts, cws, advws;
bool last_was_ws, is_block;
int lastc;
last_was_ws = false;
- ts = atom->tabsize ? : 8; /* pick it up from the atom (if there is) */
+ ts = atom->tabsize ? atom->tabsize : 8; /* pick it up from the atom (if there is) */
/* consecutive whitespace */
cws = 0;
last_was_ws = true;
}
+#if defined(DEBUG_CHUNK)
+ /* special CR/LF handling */
+ if (c == '\r') {
+ cn = ss < e ? fy_utf8_get(ss + w, (e - ss - w), &wn) : FYUG_EOF;
+ if (cn == '\n') {
+ ss += w;
+ w = wn;
+ }
+ }
+#endif
+
} else if (fy_is_space(c)) {
col++;
li->trailing_breaks_ws = true;
if (fy_is_lb_m(c, atom->lb_mode)) {
+ /* special CRLF handling */
+ if (c == '\r') {
+ cn = ss < e ? fy_utf8_get(ss + w, (e - ss - w), &wn) : FYUG_EOF;
+ if (cn == '\n') {
+#if defined(DEBUG_CHUNK)
+ fprintf(stderr, "%s:%d trailing CRLF\n", __FILE__, __LINE__);
+#endif
+ ss += w;
+ w = wn;
+ }
+ }
li->trailing_breaks++;
col = 0;
} else {
iter->chomp = atom->increment;
/* default tab size is 8 */
- iter->tabsize = atom->tabsize ? : 8;
+ iter->tabsize = atom->tabsize ? atom->tabsize : 8;
memset(iter->li, 0, sizeof(iter->li));
li = &iter->li[1];
const struct fy_atom *atom = iter->atom;
const struct fy_atom_iter_line_info *li;
const char *s, *e, *t;
- int value, code_length, rlen, ret;
+ int value, code_length, ret;
uint8_t code[4], *tt;
int j, pending_nl;
int *pending_lb = NULL, *pending_lb_new = NULL;
int pending_lb_size = 0;
enum fy_utf8_escape esc_mode;
- size_t i;
+ size_t rlen, i;
/* done? */
li = fy_atom_iter_line(iter);
return ic;
}
-int fy_atom_format_text_length(struct fy_atom *atom)
+ssize_t fy_atom_format_text_length(struct fy_atom *atom)
{
struct fy_atom_iter iter;
const struct fy_iter_chunk *ic;
return -1;
if (atom->storage_hint_valid)
- return atom->storage_hint;
+ return (ssize_t)atom->storage_hint;
len = 0;
fy_atom_iter_start(atom, &iter);
fy_atom_iter_finish(&iter);
/* something funky going on here */
- if ((int)len < 0)
+ if ((ssize_t)len < 0)
return -1;
if (ret != 0)
atom->storage_hint = (size_t)len;
atom->storage_hint_valid = true;
- return (int)len;
+ return (ssize_t)len;
}
const char *fy_atom_format_text(struct fy_atom *atom, char *buf, size_t maxsz)
struct fy_atom_iter iter;
const struct fy_iter_chunk *ic;
const char *s, *e;
- size_t len;
- int ret, rem, run, w;
+ size_t len, run, rem;
+ int ret, w;
if (!atom)
return -1;
e = s + ic->len;
/* add the remainder */
- run = (e - s) > rem ? rem : (e - s);
+ run = (size_t)(e - s) > rem ? rem : (size_t)(e - s);
s += run;
/* count utf8 characters */
if (l->lineno > 0 && iter->rs >= iter->ae)
return NULL;
+ /* this may happen on illegal utf8 */
+ if (!iter->is)
+ return NULL;
+
+ c = -1;
while (s > iter->is) {
c = fy_utf8_get_right(iter->is, (size_t)(s - iter->is), &w);
if (c <= 0 || fy_is_lb_m(c, iter->atom->lb_mode))
l->line_count = count;
if (fy_is_lb_m(c, iter->atom->lb_mode)) {
+
s += w;
/* special case for MSDOS */
if (c == '\r' && (s < iter->ie && s[1] == '\n'))
{
/* nothing */
}
+
+/* returns the line of the atom, marking exactly where the atom is */
+const char *fy_atom_lines_containing(struct fy_atom *atom, size_t *lenp)
+{
+ const struct fy_raw_line *l, *ln;
+ struct fy_atom_raw_line_iter iter;
+ bool first_line, last_line;
+ const char *start, *end;
+
+ if (!atom || !lenp) {
+ if (lenp)
+ *lenp = 0;
+ return NULL;
+ }
+
+ start = end = NULL;
+
+ fy_atom_raw_line_iter_start(atom, &iter);
+ l = fy_atom_raw_line_iter_next(&iter);
+ for (; l != NULL; l = ln) {
+ /* get the next too */
+ ln = fy_atom_raw_line_iter_next(&iter);
+
+ first_line = l->lineno <= 1;
+ last_line = ln == NULL;
+
+ if (first_line)
+ start = l->line_start;
+ if (last_line)
+ end = l->line_start + l->line_count;
+ }
+ fy_atom_raw_line_iter_finish(&iter);
+
+ *lenp = end - start;
+ return start;
+}
return fy_is_flow_ws_m(c, fy_atom_flow_ws_mode(handle));
}
-int fy_atom_format_text_length(struct fy_atom *atom);
+ssize_t fy_atom_format_text_length(struct fy_atom *atom);
const char *fy_atom_format_text(struct fy_atom *atom, char *buf, size_t maxsz);
int fy_atom_format_utf8_length(struct fy_atom *atom);
const struct fy_raw_line *
fy_atom_raw_line_iter_next(struct fy_atom_raw_line_iter *iter);
+const char *
+fy_atom_lines_containing(struct fy_atom *atom, size_t *lenp);
+
#endif
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
return -1;
/* perform the enable tests early to avoid the overhead */
- if (((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < fyc->cfg.diag->cfg.level)
+ if ((int)((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < (int)fyc->cfg.diag->cfg.level)
return 0;
/* fill in fy_diag_ctx */
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
#include "fy-parse.h"
#include "fy-input.h"
-
static const char *error_type_txt[] = {
[FYET_DEBUG] = "debug",
[FYET_INFO] = "info",
while ((errp = fy_diag_errorp_list_pop(&diag->errors)) != NULL)
fy_diag_errorp_free(errp);
- return fy_diag_unref(diag);
+ fy_diag_unref(diag);
}
bool fy_diag_got_error(struct fy_diag *diag)
}
}
+bool fy_diag_get_collect_errors(struct fy_diag *diag)
+{
+ if (!diag || diag->destroyed)
+ return false;
+
+ return diag->collect_errors;
+}
+
struct fy_diag_error *fy_diag_errors_iterate(struct fy_diag *diag, void **prevp)
{
struct fy_diag_errorp *errp;
}
rc = fy_diag_printf(diag, "%s" "%*s" "%*s" "%*s" "%*s" "%s" "%s\n",
- color_start ? : "",
- source ? diag->cfg.source_width : 0, source ? : "",
- position ? diag->cfg.position_width : 0, position ? : "",
- typestr ? diag->cfg.type_width : 0, typestr ? : "",
- modulestr ? diag->cfg.module_width : 0, modulestr ? : "",
+ color_start ? color_start : "",
+ source ? diag->cfg.source_width : 0, source ? source : "",
+ position ? diag->cfg.position_width : 0, position ? position : "",
+ typestr ? diag->cfg.type_width : 0, typestr ? typestr : "",
+ modulestr ? diag->cfg.module_width : 0, modulestr ? modulestr : "",
msg,
- color_end ? : "");
+ color_end ? color_end : "");
if (rc > 0)
rc++;
}
}
display = rowbuf;
- display_len = rbs - rowbuf;
+ display_len = (int)(rbs - rowbuf);
tilde_start = content_start_col - line_shift;
tilde_width = content_width;
if (tilde_start + tilde_width > cols)
tilde_width = cols - tilde_start;
if ((size_t)tilde_width >= rowbufsz)
- tilde_width = rowbufsz - 1; /* guard */
+ tilde_width = (int)(rowbufsz - 1); /* guard */
tilde_width_m1 = tilde_width > 0 ? (tilde_width - 1) : 0;
/* output the line */
if (!diag->collect_errors) {
fy_diag_printf(diag, "%s" "%s%s: %s" "%s\n",
- name_str ? : "",
+ name_str ? name_str : "",
color_start, fy_error_type_to_string(fydrc->type), color_end,
msg_str);
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
return -1;
/* perform the enable tests early to avoid the overhead */
- if (((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < fyd->diag->cfg.level)
+ if ((int)((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < (int)fyd->diag->cfg.level)
return 0;
/* fill in fy_diag_ctx */
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
#include <limits.h>
#include <libfyaml.h>
fyam->multiple = true;
fya->multiple = true;
- fyd_notice(fyd, "register anchor %.*s is multiple", (int)len, text);
+ fyd_debug(fyd, "register anchor %.*s is multiple", (int)len, text);
}
xle = fy_accel_entry_insert(fyd->axl, fya->anchor, fya);
if (!fyt_start || !fyt_end)
return NULL;
- s = fy_input_start(fyi) + fyt_start->handle.start_mark.input_pos;
- e = fy_input_start(fyi) + fyt_end->handle.end_mark.input_pos;
+ s = (const char *)fy_input_start(fyi) + fyt_start->handle.start_mark.input_pos;
+ e = (const char *)fy_input_start(fyi) + fyt_end->handle.end_mark.input_pos;
size = (size_t)(e - s);
if (size > 0)
{
struct fy_anchor *fya, *fyam;
struct fy_accel_entry *xle;
- const char *text;
- size_t text_len;
+ const char *text FY_DEBUG_UNUSED;
+ size_t text_len FY_DEBUG_UNUSED;
int rc;
fya = fy_anchor_create(fyd, fyn, anchor);
fya->multiple = true;
text = fy_anchor_get_text(fya, &text_len);
- fyd_notice(fyd, "register anchor %.*s is multiple", (int)text_len, text);
+ assert(text);
+ assert(text_len > 0);
+ fyd_debug(fyd, "register anchor %.*s is multiple", (int)text_len, text);
}
xle = fy_accel_entry_insert(fyd->axl, fya->anchor, fya);
}
struct fy_node *fy_node_copy_internal(struct fy_document *fyd, struct fy_node *fyn_from,
- struct fy_node *fyn_parent)
+ struct fy_node *fyn_parent, int depth)
{
struct fy_document *fyd_from;
- struct fy_node *fyn, *fyni, *fynit;
- struct fy_node_pair *fynp, *fynpt;
+ struct fy_node *fyn = NULL, *fyni = NULL, *fynit = NULL;
+ struct fy_node_pair *fynp = NULL, *fynpt = NULL;
struct fy_anchor *fya, *fya_from;
const char *anchor;
size_t anchor_len;
if (!fyd || !fyn_from || !fyn_from->fyd)
return NULL;
+ FYD_NODE_ERROR_CHECK(fyd, fyn_from, FYEM_DOC,
+ depth < FY_NODE_PATH_WALK_DEPTH_DEFAULT, err_out,
+ "maximum node copy depth exceeded %d (max %d)",
+ depth, FY_NODE_PATH_WALK_DEPTH_DEFAULT);
+
fyd_from = fyn_from->fyd;
fyn = fy_node_alloc(fyd, fyn_from->type);
for (fyni = fy_node_list_head(&fyn_from->sequence); fyni;
fyni = fy_node_next(&fyn_from->sequence, fyni)) {
- fynit = fy_node_copy_internal(fyd, fyni, fyn);
+ fynit = fy_node_copy_internal(fyd, fyni, fyn, depth + 1);
fyd_error_check(fyd, fynit, err_out,
"fy_node_copy_internal() failed");
fy_node_list_add_tail(&fyn->sequence, fynit);
fynit->attached = true;
+ fynit = NULL;
}
break;
fyd_error_check(fyd, fynpt, err_out,
"fy_node_pair_alloc() failed");
- fynpt->key = fy_node_copy_internal(fyd, fynp->key, fyn);
- fynpt->value = fy_node_copy_internal(fyd, fynp->value, fyn);
+ if (fynp->key) {
+ fynpt->key = fy_node_copy_internal(fyd, fynp->key, fyn, depth + 1);
+ fyd_error_check(fyd, fynpt->key, err_out,
+ "fy_node_copy_internal() key failed");
+ }
+ if (fynp->value) {
+ fynpt->value = fy_node_copy_internal(fyd, fynp->value, fyn, depth + 1);
+ fyd_error_check(fyd, fynpt->value, err_out,
+ "fy_node_copy_internal() key failed");
+ }
fynp->parent = fyn;
- fy_node_pair_list_add_tail(&fyn->mapping, fynpt);
- if (fyn->xl) {
- rc = fy_accel_insert(fyn->xl, fynpt->key, fynpt);
- fyd_error_check(fyd, !rc, err_out,
- "fy_accel_insert() failed");
- }
if (fynpt->key) {
fynpt->key->attached = true;
fynpt->key->key_root = true;
}
if (fynpt->value)
fynpt->value->attached = true;
+
+ fy_node_pair_list_add_tail(&fyn->mapping, fynpt);
+ if (fyn->xl) {
+ rc = fy_accel_insert(fyn->xl, fynpt->key, fynpt);
+ fyd_error_check(fyd, !rc, err_out,
+ "fy_accel_insert() failed");
+ }
+ fynpt = NULL;
}
break;
}
return fyn;
err_out:
+ fy_node_free(fynit);
+ fy_node_pair_free(fynpt);
+ fy_node_free(fyn);
return NULL;
}
if (!fyd)
return NULL;
- fyn = fy_node_copy_internal(fyd, fyn_from, NULL);
+ fyn = fy_node_copy_internal(fyd, fyn_from, NULL, 0);
if (!fyn) {
fyd->diag->on_error = false;
return NULL;
}
}
- /* verify no funkiness on root */
- assert(fyn_parent || fyn_to == fyd->root);
-
/* deleting target */
if (!fyn_from) {
fyn_to->parent = NULL;
if (!fyn_parent) {
- fyd_doc_debug(fyd, "Deleting root node");
+ fyd_doc_debug(fyd, "Deleting %s node", fyd->root == fyn_to ? "root" : "unattached");
fy_node_detach_and_free(fyn_to);
- fyd->root = NULL;
+
+ /* if destination was the root, remove it */
+ if (fyn_to == fyd->root)
+ fyd->root = NULL;
} else if (fyn_parent->type == FYNT_SEQUENCE) {
fyd_doc_debug(fyd, "Deleting sequence node");
fy_node_list_del(&fyn_parent->sequence, fyn_to);
int fy_node_delete(struct fy_node *fyn)
{
+ if (!fyn)
+ return 0;
return fy_node_insert(fyn, NULL);
}
/* for resolution to work, no reference loops should exist */
ret = fy_check_ref_loop(fyd, fyd->root,
- FYNWF_MAXDEPTH_DEFAULT | FYNWF_FOLLOW, NULL);
+ FYNWF_MAXDEPTH_DEFAULT | FYNWF_FOLLOW, NULL, 0);
fy_node_clear_system_marks(fyd->root);
fyp->stream_error = false;
/* if we collect diagnostics, we can continue */
- fyp_error_check(fyp, fyd || (fyp->cfg.flags & FYPCF_COLLECT_DIAG), err_out,
- "fy_parse_load_document() failed");
+ if (!fyd && !(fyp->cfg.flags & FYPCF_COLLECT_DIAG))
+ goto err_out;
/* no document, but we're collecting diagnostics */
if (!fyd) {
- fyp_error(fyp, "fy_parse_load_document() failed");
+ if (fyp->cfg.flags & FYPCF_COLLECT_DIAG)
+ fyp_error(fyp, "fy_parse_load_document() failed");
fyp->stream_error = false;
fyd = fy_parse_document_create(fyp, NULL);
return fyn ? fyn->style : FYNS_PLAIN;
}
+enum fy_node_style fy_node_set_style(struct fy_node *fyn, enum fy_node_style style)
+{
+ const struct fy_token_analysis *ta;
+
+ /* a NULL node is always plain */
+ if (!fyn)
+ return FYNS_PLAIN;
+
+ /* same style */
+ if (style == fyn->style)
+ return style;
+
+ /* can't change an alias style */
+ if (fyn->style == FYNS_ALIAS)
+ return fyn->style;
+
+ /* any is easy... */
+ if (style == FYNS_ANY) {
+ fyn->style = style;
+ return style;
+ }
+
+ /* for a collection the choices are limited */
+ if (fyn->type == FYNT_MAPPING ||
+ fyn->type == FYNT_SEQUENCE) {
+
+ /* only flow/block style is allowed */
+ if (style == FYNS_FLOW || style == FYNS_BLOCK)
+ fyn->style = style;
+
+ return fyn->style;
+ }
+
+ /* a scalar, analyze it */
+ ta = fy_token_text_analyze(fyn->scalar);
+ switch (style) {
+ case FYNS_PLAIN:
+ if (ta->flags & FYTTAF_CAN_BE_PLAIN)
+ fyn->style = style;
+ break;
+ case FYNS_SINGLE_QUOTED:
+ if (ta->flags & FYTTAF_CAN_BE_SINGLE_QUOTED)
+ fyn->style = style;
+ break;
+
+ case FYNS_DOUBLE_QUOTED:
+ if (ta->flags & FYTTAF_CAN_BE_DOUBLE_QUOTED)
+ fyn->style = style;
+ break;
+
+ case FYNS_LITERAL:
+ if (ta->flags & FYTTAF_CAN_BE_LITERAL)
+ fyn->style = style;
+ break;
+
+ case FYNS_FOLDED:
+ /* we never support changing style to folded
+ * it is never emitted and frankly not worth the effort.
+ */
+ break;
+
+ default:
+ /* anything else, doesn't take */
+ break;
+
+ }
+
+ /* NOTE even if the style has 'taken' the emitter is free to change it
+ * since the style might not be possible at a given state. For example
+ * setting a literal style when the emitter is in flow mode obviously
+ * will not work.
+ */
+ return fyn->style;
+}
+
struct fy_token *fy_node_get_start_token(struct fy_node *fyn)
{
if (!fyn)
bool fy_node_is_attached(struct fy_node *fyn)
{
- return fyn ? fyn->attached : false;
+ if (!fyn)
+ return false;
+
+ if (fyn->attached)
+ return true;
+
+ /* finally root is attached (although the property is not set) */
+ return fyn->fyd && fyn->fyd->root == fyn;
}
struct fy_node *fy_node_get_parent(struct fy_node *fyn)
return true;
}
+#ifdef _MSC_VER
+/* MSVC version - use _alloca with helper function */
+static __inline struct fy_node_walk_ctx *
+fy_node_walk_ctx_init_impl(struct fy_node_walk_ctx *ctx, unsigned int max_depth, unsigned int mark)
+{
+ ctx->max_depth = max_depth;
+ ctx->next_slot = 0;
+ ctx->mark = mark;
+ return ctx;
+}
+#define fy_node_walk_ctx_create_a(_max_depth, _mark) \
+ fy_node_walk_ctx_init_impl( \
+ (struct fy_node_walk_ctx *)_alloca(sizeof(struct fy_node_walk_ctx) + sizeof(struct fy_node *) * (_max_depth)), \
+ (_max_depth), \
+ (_mark))
+#else
#define fy_node_walk_ctx_create_a(_max_depth, _mark) \
({ \
unsigned int __max_depth = (_max_depth); \
_ctx->mark = (_mark); \
_ctx; \
})
+#endif
static inline void fy_node_walk_mark_start(struct fy_node_walk_ctx *ctx)
{
const char *s, *e, *ss, *ee;
char *end_idx, *json_key, *t, *p, *uri_path;
char c;
- int idx, rlen;
- size_t len, json_key_len, uri_path_len;
+ int idx;
+ size_t len, rlen, json_key_len, uri_path_len;
bool has_json_key_esc;
uint8_t code[4];
int code_length;
while (ss < ee) {
/* copy run until '%' or end */
p = memchr(ss, '%', ee - ss);
- rlen = (p ? p : ee) - ss;
+ rlen = (size_t)((p ? p : ee) - ss);
memcpy(t, ss, rlen);
ss += rlen;
t += rlen;
return fyn_ref;
}
-bool fy_check_ref_loop(struct fy_document *fyd, struct fy_node *fyn,
- enum fy_node_walk_flags flags,
- struct fy_node_walk_ctx *ctx)
+bool
+fy_check_ref_loop(struct fy_document *fyd, struct fy_node *fyn,
+ enum fy_node_walk_flags flags,
+ struct fy_node_walk_ctx *ctx,
+ unsigned int depth)
{
struct fy_node *fyni;
struct fy_node_pair *fynp, *fynpi;
if (!fyn)
return false;
+ /* over depth? */
+ if (depth > fy_node_walk_max_depth_from_flags(flags))
+ return true;
+
/* visited? no need to check */
if (fyn->marks & FY_BIT(FYNWF_VISIT_MARKER))
return false;
fyni = fy_node_follow_alias(fyn, flags);
- ret = fy_check_ref_loop(fyd, fyni, flags, ctxn);
+ ret = fy_check_ref_loop(fyd, fyni, flags, ctxn, depth + 1);
if (!ctx)
fy_node_walk_mark_end(ctxn);
for (fyni = fy_node_list_head(&fyn->sequence); fyni;
fyni = fy_node_next(&fyn->sequence, fyni)) {
- ret = fy_check_ref_loop(fyd, fyni, flags, ctx);
+ ret = fy_check_ref_loop(fyd, fyni, flags, ctx, depth + 1);
if (ret)
break;
}
fynpi = fy_node_pair_next(&fyn->mapping, fynp);
- ret = fy_check_ref_loop(fyd, fynp->key, flags, ctx);
+ ret = fy_check_ref_loop(fyd, fynp->key, flags, ctx, depth + 1);
if (ret)
break;
- ret = fy_check_ref_loop(fyd, fynp->value, flags, ctx);
+ ret = fy_check_ref_loop(fyd, fynp->value, flags, ctx, depth + 1);
if (ret)
break;
}
fy_node_detach_and_free(fyd->root);
fyd->root = NULL;
- fyn->parent = NULL;
fyd->root = fyn;
- if (fyn)
+ if (fyn) {
+ fyn->parent = NULL;
fyn->attached = true;
+ }
return 0;
}
def_arg.cmp_fn = NULL;
def_arg.arg = NULL;
}
- ctx.key_cmp = key_cmp ? : fy_node_mapping_sort_cmp_default;
+ ctx.key_cmp = key_cmp ? key_cmp : fy_node_mapping_sort_cmp_default;
ctx.arg = key_cmp ? arg : &def_arg;
ctx.fynpp = fynpp;
ctx.count = count;
fydi->generator_state |= FYDIGF_GENERATED_NULL;
return NULL;
}
+
+const char *
+fy_node_get_comment(struct fy_node *fyn, enum fy_comment_placement placement)
+{
+ struct fy_token *fyt;
+
+ if (!fyn)
+ return NULL;
+
+ switch (fyn->type) {
+ case FYNT_SCALAR:
+ fyt = fyn->scalar;
+ break;
+ case FYNT_SEQUENCE:
+ fyt = fyn->sequence_start;
+ break;
+ case FYNT_MAPPING:
+ fyt = fyn->mapping_start;
+ break;
+ default:
+ fyt = NULL;
+ break;
+ }
+
+ if (!fyt)
+ return NULL;
+
+ return fy_token_get_comment(fyt, placement);
+}
+
+const char *
+fy_node_get_comments(struct fy_node *fyn)
+{
+ struct fy_token *fyt;
+
+ if (!fyn)
+ return NULL;
+
+ switch (fyn->type) {
+ case FYNT_SCALAR:
+ fyt = fyn->scalar;
+ break;
+ case FYNT_SEQUENCE:
+ fyt = fyn->sequence_start;
+ break;
+ case FYNT_MAPPING:
+ fyt = fyn->mapping_start;
+ break;
+ default:
+ fyt = NULL;
+ break;
+ }
+
+ if (!fyt)
+ return NULL;
+
+ return fy_token_get_comments(fyt);
+}
bool fy_check_ref_loop(struct fy_document *fyd, struct fy_node *fyn,
enum fy_node_walk_flags flags,
- struct fy_node_walk_ctx *ctx);
+ struct fy_node_walk_ctx *ctx,
+ unsigned int depth);
#define FYNWF_VISIT_MARKER (FYNWF_MAX_USER_MARKER + 1)
#define FYNWF_REF_MARKER (FYNWF_MAX_USER_MARKER + 2)
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
return -1;
/* perform the enable tests early to avoid the overhead */
- if (((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < fydb->cfg.diag->cfg.level)
+ if ((int)((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < (int)fydb->cfg.diag->cfg.level)
return 0;
/* fill in fy_diag_ctx */
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
#include <libfyaml.h>
return NULL;
memset(fyds, 0, sizeof(*fyds));
+ fyds->fyt_ds = NULL;
fyds->fyt_vd = NULL;
fy_token_list_init(&fyds->fyt_td);
assert(fyds->refs == 1);
+ fy_token_unref(fyds->fyt_ds);
fy_token_unref(fyds->fyt_vd);
fy_token_list_unref_all(&fyds->fyt_td);
memset(&fyds->start_mark, 0, sizeof(fyds->start_mark));
memset(&fyds->end_mark, 0, sizeof(fyds->end_mark));
+ fyds->fyt_ds = NULL;
fyds->fyt_vd = NULL;
fy_token_list_init(&fyds->fyt_td);
fyds_new->start_mark = fyds->start_mark;
fyds_new->end_mark = fyds->end_mark;
+ if (fyds->fyt_ds) {
+ fyt = fy_token_alloc();
+ if (!fyt)
+ goto err_out;
+
+ fyt->type = FYTT_DOCUMENT_START;
+ fyt->handle = fyds->fyt_ds->handle;
+
+ /* take reference */
+ fy_input_ref(fyt->handle.fyi);
+
+ fyds_new->fyt_ds = fyt;
+ }
+
if (fyds->fyt_vd) {
fyt = fy_token_alloc();
if (!fyt)
bool json_mode : 1;
struct fy_mark start_mark;
struct fy_mark end_mark;
+ struct fy_token *fyt_ds; /* the document start token (if any) */
struct fy_token *fyt_vd; /* version directive */
struct fy_token_list fyt_td; /* tag directives */
};
#include <stdio.h>
#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
return ea->next == 0;
}
-static inline int
+static inline size_t
fy_emit_accum_size(struct fy_emit_accum *ea)
{
return ea->next;
#include <assert.h>
#include <stdlib.h>
#include <limits.h>
-#include <unistd.h>
#include <ctype.h>
#include <errno.h>
}
/* fwd decl */
-void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len);
+void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, size_t len);
void fy_emit_printf(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
static inline bool fy_emit_output_comments(struct fy_emitter *emit)
{
- return !!(emit->xcfg.cfg.flags & FYECF_OUTPUT_COMMENTS);
+ return !!(emit->xcfg.cfg.flags & FYECF_OUTPUT_COMMENTS) &&
+ !fy_emit_is_oneline_or_compact(emit) &&
+ !fy_emit_is_json_mode(emit);
}
static int fy_emit_node_check_json(struct fy_emitter *emit, struct fy_node *fyn)
void fy_emit_sequence(struct fy_emitter *emit, struct fy_node *fyn, int flags, int indent);
void fy_emit_mapping(struct fy_emitter *emit, struct fy_node *fyn, int flags, int indent);
-void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len);
+void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, size_t len);
void fy_emit_puts(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str);
void fy_emit_putc(struct fy_emitter *emit, enum fy_emitter_write_type type, int c);
/* simple write, just ascii, advance column */
-void fy_emit_write_simple(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len)
+void fy_emit_write_simple(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, size_t len)
{
int outlen;
if (!len)
return;
- outlen = emit->xcfg.cfg.output(emit, type, str, len, emit->xcfg.cfg.userdata);
- if (outlen != len)
+ outlen = emit->xcfg.cfg.output(emit, type, str, (int)len, emit->xcfg.cfg.userdata);
+ if (outlen != (int)len)
emit->output_error = true;
- emit->column += len;
+ emit->column += (int)len;
}
/* simple puts as above */
}
}
-void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len)
+void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, size_t len)
{
int c, w;
const char *m, *e;
int outlen;
- if (!len)
+ if (!len || len > INT_MAX)
return;
- outlen = emit->xcfg.cfg.output(emit, type, str, len, emit->xcfg.cfg.userdata);
- if (outlen != len)
+ outlen = emit->xcfg.cfg.output(emit, type, str, (int)len, emit->xcfg.cfg.userdata);
+ if (outlen != (int)len)
emit->output_error = true;
e = str + len;
bool fy_emit_token_has_comment(struct fy_emitter *emit, struct fy_token *fyt, enum fy_comment_placement placement)
{
+ if (!fy_emit_output_comments(emit))
+ return false;
return fy_emit_token_comment_handle(emit, fyt, placement) ? true : false;
}
struct fy_atom *handle;
char *text;
const char *t;
- int len;
+ size_t len;
handle = fy_emit_token_comment_handle(emit, fyt, placement);
if (!handle)
}
}
-void fy_emit_node_comment(struct fy_emitter *emit, struct fy_node *fyn, int flags, int indent,
- enum fy_comment_placement placement)
-{
- struct fy_token *fyt;
-
- if (!fy_emit_output_comments(emit) || (unsigned int)placement >= fycp_max)
- return;
-
- fyt = fy_node_value_token(fyn);
- if (!fyt)
- return;
-
- fy_emit_token_comment(emit, fyt, flags, indent, placement);
-}
-
void fy_emit_common_node_preamble(struct fy_emitter *emit,
struct fy_token *fyt_value,
struct fy_token *fyt_anchor,
bool json_mode = false;
struct fy_emit_save_ctx *sc = &emit->s_sc;
+ (void)sc;
+
json_mode = fy_emit_is_json_mode(emit);
if (!json_mode) {
-
- if (fy_emit_token_has_comment(emit, fyt_value, fycp_top))
- fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_top);
-
if (!(emit->xcfg.cfg.flags & FYECF_STRIP_LABELS)) {
if (fyt_anchor)
anchor = fy_token_get_text(fyt_anchor, &anchor_len);
case '\v':
fy_emit_accum_utf8_put(&emit->ea, 'v');
break;
- case '\e':
+ case '\x1b': // \e
fy_emit_accum_utf8_put(&emit->ea, 'e');
break;
case 0x85:
}
/* anything not empty is double quoted here */
- style = !(ta->flags & FYTTAF_EMPTY) ? FYNS_PLAIN : FYNS_DOUBLE_QUOTED;
+ style = (ta->flags & FYTTAF_EMPTY) ? FYNS_PLAIN : FYNS_DOUBLE_QUOTED;
}
/* try to pretify */
void fy_emit_token_scalar(struct fy_emitter *emit, struct fy_token *fyt, int flags, int indent,
enum fy_node_style style, struct fy_token *fyt_tag)
{
+ struct fy_emit_save_ctx *sc = &emit->s_sc;
+
assert(style != FYNS_FLOW && style != FYNS_BLOCK);
+ if (sc->flags & DDNF_HANGING_INDENT)
+ fy_emit_write_indent(emit, sc->indent);
+
+ /* root scalar with a comment needs special handling */
+ if ((flags & DDNF_ROOT) && fy_emit_token_has_comment(emit, fyt, fycp_top))
+ fy_emit_token_comment(emit, fyt, flags, indent, fycp_top);
+
indent = fy_emit_increase_indent(emit, flags, indent);
if (!fy_emit_whitespace(emit))
default:
break;
}
+
+ /* root scalar with a comment needs special handling */
+ if ((flags & DDNF_ROOT) && fy_emit_token_has_comment(emit, fyt, fycp_right)) {
+ fy_emit_token_comment(emit, fyt, flags, indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
}
void fy_emit_scalar(struct fy_emitter *emit, struct fy_node *fyn, int flags, int indent, bool is_key)
style, fyn->tag);
}
-static void fy_emit_sequence_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc)
+static void fy_emit_sequence_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
+ struct fy_token *fyt)
{
bool json = fy_emit_is_json_mode(emit);
bool was_flow = sc->flow;
+ if (fy_emit_token_has_comment(emit, fyt, fycp_top)) {
+ fy_emit_token_comment(emit, fyt, sc->flags, sc->indent, fycp_top);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
+
sc->old_indent = sc->indent;
if (!json) {
if (fy_emit_is_manual(emit))
static void fy_emit_sequence_item_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
struct fy_token *fyt_value)
{
- int tmp_indent;
+ bool has_comment;
sc->flags |= DDNF_SEQ;
- if (fy_emit_token_has_comment(emit, fyt_value, fycp_top) ||
- !fy_emit_is_oneline_or_compact(emit) ||
+ has_comment = fy_emit_token_has_comment(emit, fyt_value, fycp_top);
+
+ if (!fy_emit_is_oneline_or_compact(emit) ||
((fy_emit_is_compact(emit) || sc->flow) && emit->column >= fy_emit_width(emit)))
fy_emit_write_indent(emit, sc->indent);
+ if (has_comment) {
+ fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_top);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
+
if (!sc->flow && !fy_emit_is_json_mode(emit))
fy_emit_write_indicator(emit, di_dash, sc->flags, sc->indent, fyewt_indicator);
-
- tmp_indent = sc->indent;
- if (fy_emit_token_has_comment(emit, fyt_value, fycp_top)) {
- if (!sc->flow && !fy_emit_is_json_mode(emit))
- tmp_indent = fy_emit_increase_indent(emit, sc->flags, sc->indent);
- fy_emit_token_comment(emit, fyt_value, sc->flags, tmp_indent, fycp_top);
- }
}
static void fy_emit_sequence_item_epilog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
if ((sc->flow || fy_emit_is_json_mode(emit)) && !last)
fy_emit_write_indicator(emit, di_comma, sc->flags, sc->indent, fyewt_indicator);
- fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_right);
+ if (fy_emit_token_has_comment(emit, fyt_value, fycp_right)) {
+ fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
needs_hanging_indent = sc->flow && !fy_emit_is_oneline_or_compact(emit) && !sc->empty;
sc->xstyle = fyn->style;
sc->old_indent = sc->indent;
- fy_emit_sequence_prolog(emit, sc);
+ fy_emit_sequence_prolog(emit, sc, fyn->sequence_start);
for (fyni = fy_node_list_head(&fyn->sequence); fyni; fyni = fynin) {
fy_emit_sequence_epilog(emit, sc);
}
-static void fy_emit_mapping_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc)
+static void fy_emit_mapping_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
+ struct fy_token *fyt)
{
bool json = fy_emit_is_json_mode(emit);
bool was_flow = sc->flow;
+ if (fy_emit_token_has_comment(emit, fyt, fycp_top)) {
+ fy_emit_token_comment(emit, fyt, sc->flags, sc->indent, fycp_top);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
+
sc->old_indent = sc->indent;
if (!json) {
if (fy_emit_is_manual(emit))
struct fy_token *fyt_key, bool simple_key)
{
const struct fy_token_analysis *ta;
- bool do_indent, key_over;
+ bool do_indent, key_over, has_comment;
sc->flags = DDNF_MAP | (sc->flags & DDNF_FLOW);
((fy_emit_is_compact(emit) || sc->flow) && emit->column >= fy_emit_width(emit)))
fy_emit_write_indent(emit, sc->indent);
- if (simple_key) {
+ /* if we have a right comment then it's by a definition not a simple key */
+ has_comment = fy_emit_token_has_comment(emit, fyt_key, fycp_right);
+ if (simple_key /* && !has_comment */ ) {
sc->flags |= DDNF_SIMPLE;
if (fyt_key && fyt_key->type == FYTT_SCALAR)
sc->flags |= DDNF_SIMPLE_SCALAR_KEY;
}
do_indent = false;
- if (!fy_emit_is_oneline_or_compact(emit)) {
+ if (!has_comment && !fy_emit_is_oneline_or_compact(emit)) {
if (fyt_key && fyt_key->type != FYTT_SCALAR)
/* always indent on non scalar keys */
key_over = true;
fy_emit_write_indent(emit, sc->indent);
/* complex? */
- if (!(sc->flags & DDNF_SIMPLE))
+ if (!(sc->flags & DDNF_SIMPLE)) {
fy_emit_write_indicator(emit, di_question_mark, sc->flags, sc->indent, fyewt_indicator);
+ }
}
static void fy_emit_mapping_key_epilog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
struct fy_token *fyt_key)
{
- int tmp_indent;
-
/* if the key is an alias, always output an extra whitespace */
if (fyt_key && fyt_key->type == FYTT_ALIAS)
fy_emit_write_ws(emit);
sc->flags &= ~DDNF_MAP;
if (!(sc->flags & DDNF_SIMPLE)) {
+
+ if (fy_emit_token_has_comment(emit, fyt_key, fycp_right)) {
+ fy_emit_token_comment(emit, fyt_key, sc->flags, sc->indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
+
if (!emit->flow_level && !fy_emit_is_oneline_or_compact(emit))
fy_emit_write_indent(emit, sc->indent);
if (!fy_emit_whitespace(emit))
fy_emit_write_ws(emit);
+ } else {
}
- fy_emit_write_indicator(emit, di_colon, sc->flags, sc->indent, fyewt_indicator);
-
- tmp_indent = sc->indent;
- if (fy_emit_token_has_comment(emit, fyt_key, fycp_right)) {
- if (!sc->flow && !fy_emit_is_json_mode(emit))
- tmp_indent = fy_emit_increase_indent(emit, sc->flags, sc->indent);
+ fy_emit_write_indicator(emit, di_colon, sc->flags, sc->indent, fyewt_indicator);
- fy_emit_token_comment(emit, fyt_key, sc->flags, tmp_indent, fycp_right);
- fy_emit_write_indent(emit, tmp_indent);
+ sc->flags &= ~DDNF_HANGING_INDENT;
+ if ((sc->flags & DDNF_SIMPLE) && fy_emit_token_has_comment(emit, fyt_key, fycp_right)) {
+ fy_emit_token_comment(emit, fyt_key, sc->flags, sc->indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
}
- sc->flags = DDNF_MAP | (sc->flags & DDNF_FLOW);
+ sc->flags = DDNF_MAP | (sc->flags & (DDNF_FLOW | DDNF_HANGING_INDENT));
}
static void fy_emit_mapping_value_prolog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc,
const struct fy_token_analysis *ta;
bool value_over;
+ if (sc->flags & DDNF_HANGING_INDENT)
+ fy_emit_write_indent(emit, sc->indent);
+
/* don't do anything for those cases */
if (!sc->flow || fy_emit_is_oneline_or_compact(emit) || !fyt_value || fyt_value->type != FYTT_SCALAR)
return;
if ((sc->flow || fy_emit_is_json_mode(emit)) && !last)
fy_emit_write_indicator(emit, di_comma, sc->flags, sc->indent, fyewt_indicator);
- fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_right);
+ if (fy_emit_token_has_comment(emit, fyt_value, fycp_right)) {
+ fy_emit_token_comment(emit, fyt_value, sc->flags, sc->indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
needs_hanging_indent = sc->flow && !fy_emit_is_oneline_or_compact(emit) && !sc->empty;
sc->xstyle = fyn->style;
sc->old_indent = sc->indent;
- fy_emit_mapping_prolog(emit, sc);
+ fy_emit_mapping_prolog(emit, sc, fyn->mapping_start);
if (!(emit->xcfg.cfg.flags & (FYECF_SORT_KEYS | FYECF_STRIP_EMPTY_KV))) {
fynp = fy_node_pair_list_head(&fyn->mapping);
struct fy_document_state *fyds,
bool root_tag_or_anchor)
{
+ struct fy_emit_save_ctx *sc = &emit->s_sc;
struct fy_token *fyt_chk;
const char *td_handle, *td_prefix;
size_t td_handle_size, td_prefix_size;
/* if either a version or directive tags exist, and no previous
* explicit document end existed, output one now
*/
- if (!fy_emit_is_json_mode(emit) && (vd || td) && !(emit->flags & FYEF_HAD_DOCUMENT_END)) {
+ if (!fy_emit_is_json_mode(emit) && (vd || td) &&
+ (emit->flags & (FYEF_HAD_DOCUMENT_END | FYEF_HAD_DOCUMENT_OUTPUT)) ==
+ (FYEF_HAD_DOCUMENT_END | FYEF_HAD_DOCUMENT_OUTPUT)) {
if (emit->column)
fy_emit_putc_simple(emit, fyewt_linebreak, '\n');
if (!strip_doc) {
}
}
+ /* top comment */
+ if (fy_emit_token_has_comment(emit, fyds->fyt_ds, fycp_top)) {
+ if (emit->column)
+ fy_emit_putc_simple(emit, fyewt_linebreak, '\n');
+ fy_emit_token_comment(emit, fyds->fyt_ds, sc->flags, sc->indent, fycp_top);
+ }
+ /* right comment */
+ if (fy_emit_token_has_comment(emit, fyds->fyt_ds, fycp_right)) {
+ if (emit->column)
+ fy_emit_putc_simple(emit, fyewt_linebreak, '\n');
+ fy_emit_token_comment(emit, fyds->fyt_ds, sc->flags, sc->indent, fycp_right);
+ sc->flags |= DDNF_HANGING_INDENT;
+ }
+
if (!fy_emit_is_json_mode(emit) && vd) {
if (emit->column)
fy_emit_putc_simple(emit, fyewt_linebreak, '\n');
if (!emit || !fyd || !fyd->fyds)
return -1;
- root = fyn_root ? : fy_document_root(fyd);
+ root = fyn_root ? fyn_root : fy_document_root(fyd);
root_tag_or_anchor = root && (root->tag || fy_document_lookup_anchor_by_node(fyd, root));
if (!emit || !fyn)
return -1;
- /* top comment first */
- fy_emit_node_comment(emit, fyn, DDNF_ROOT, -1, fycp_top);
-
fy_emit_node_internal(emit, fyn, DDNF_ROOT, -1, false);
- /* right comment next */
- fy_emit_node_comment(emit, fyn, DDNF_ROOT, -1, fycp_right);
-
- /* bottom comment last */
- fy_emit_node_comment(emit, fyn, DDNF_ROOT, -1, fycp_bottom);
-
return 0;
}
rc = fy_emit_document_end(emit);
+ fy_emit_reset(emit, false);
+
return rc;
}
size_t left, pagesize, size, len;
char *bufnew;
+ if (leni < 0)
+ return -1;
+
/* convert to unsigned and use that */
len = (size_t)leni;
/* no funky business */
- if (len < 0)
+ if ((ssize_t)len < 0)
return -1;
state->need += len;
memcpy(state->buf + state->pos, str, len);
state->pos += len;
- return len;
+ return (int)len;
}
static void
struct fy_emitter_cfg emit_cfg;
struct fy_emit_buffer_state *state;
+ if (flags & FYECF_EXTENDED_CFG)
+ return NULL;
+
state = malloc(sizeof(*state));
if (!state)
return NULL;
rc = fy_emit_str_internal(fyd, flags, NULL, &buf, &size, false);
if (rc != 0)
return -1;
- return size;
+ if ((int)size < 0)
+ return -1;
+ return (int)size;
}
char *fy_emit_document_to_string(struct fy_document *fyd, enum fy_emitter_cfg_flags flags)
static int do_file_output(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int leni, void *userdata)
{
FILE *fp = userdata;
- size_t len;
-
- len = (size_t)leni;
+ size_t len, wrn;
/* no funky stuff */
- if (len < 0)
+ if (leni < 0)
return -1;
- return fwrite(str, 1, len, fp);
+ len = (size_t)leni;
+ wrn = fwrite(str, 1, len, fp);
+ return (int)wrn;
}
int fy_emit_document_to_fp(struct fy_document *fyd, enum fy_emitter_cfg_flags flags,
struct fy_emitter_cfg emit_cfg;
int rc;
- if (!fp)
+ /* we don't allow an extended configuration */
+ if (!fp || (flags & FYECF_EXTENDED_CFG))
return -1;
memset(&emit_cfg, 0, sizeof(emit_cfg));
len -= wrn;
str += wrn;
- total += wrn;
+ total += (int)wrn;
}
return total;
struct fy_emitter_cfg emit_cfg;
int rc;
- if (fd < 0)
+ if (fd < 0 || (flags & FYECF_EXTENDED_CFG))
return -1;
memset(&emit_cfg, 0, sizeof(emit_cfg));
rc = fy_emit_str_internal(NULL, flags, fyn, &buf, &size, false);
if (rc != 0)
return -1;
- return size;
+ return (int)size;
}
char *fy_emit_node_to_string(struct fy_node *fyn, enum fy_emitter_cfg_flags flags)
enum fy_node_style style, xstyle;
int ret, s_flags, s_indent;
- if (fye->type != FYET_ALIAS && fye->type != FYET_SCALAR &&
+ /* force collections after --- to start at a new line */
+ if (!fy_emit_is_oneline(emit) &&
+ fye->type != FYET_ALIAS && fye->type != FYET_SCALAR &&
(emit->s_flags & DDNF_ROOT) && emit->column != 0) {
fy_emit_putc_simple(emit, fyewt_linebreak, '\n');
emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION;
sc->s_flags = s_flags;
sc->s_indent = s_indent;
- fy_emit_sequence_prolog(emit, sc);
+ fy_emit_sequence_prolog(emit, sc, fye->sequence_start.sequence_start);
sc->flags &= ~DDNF_MAP;
sc->flags |= DDNF_SEQ;
sc->s_flags = s_flags;
sc->s_indent = s_indent;
- fy_emit_mapping_prolog(emit, sc);
+ fy_emit_mapping_prolog(emit, sc, fye->mapping_start.mapping_start);
sc->flags &= ~DDNF_SEQ;
sc->flags |= DDNF_MAP;
struct fy_token *fyt_item = NULL;
int ret;
- fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
- sc->fyt_last_value = NULL;
-
switch (fye->type) {
case FYET_SEQUENCE_END:
fy_emit_sequence_item_epilog(emit, sc, true, sc->fyt_last_value);
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
+ sc->fyt_last_value = NULL;
+
/* emit epilog */
fy_emit_sequence_epilog(emit, sc);
return -1;
}
+ if (!first)
+ fy_emit_sequence_item_epilog(emit, sc, false, sc->fyt_last_value);
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
+ sc->fyt_last_value = NULL;
+
ret = fy_emit_push_state(emit, FYES_SEQUENCE_ITEM);
if (ret)
return ret;
emit->s_indent = sc->indent;
emit->s_flags = sc->flags;
- if (!first)
- fy_emit_sequence_item_epilog(emit, sc, false, sc->fyt_last_value);
-
sc->fyt_last_value = fyt_item;
fy_emit_sequence_item_prolog(emit, sc, fyt_item);
int ret;
bool simple_key;
- fy_emit_token_unref(emit, fyp, sc->fyt_last_key);
- sc->fyt_last_key = NULL;
- fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
- sc->fyt_last_value = NULL;
-
simple_key = false;
switch (fye->type) {
/* emit epilog */
fy_emit_mapping_epilog(emit, sc);
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_key);
+ sc->fyt_last_key = NULL;
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
+ sc->fyt_last_value = NULL;
+
/* restore indent and flags */
emit->s_indent = sc->s_indent;
emit->s_flags = sc->s_flags;
if (!first)
fy_emit_mapping_value_epilog(emit, sc, false, sc->fyt_last_value);
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_key);
+ sc->fyt_last_key = NULL;
+ fy_emit_token_unref(emit, fyp, sc->fyt_last_value);
+ sc->fyt_last_value = NULL;
+
sc->fyt_last_key = fyt_key;
fy_emit_mapping_key_prolog(emit, sc, fyt_key, simple_key);
if (color)
raw_default_output(fp, fd, color, strlen(color));
- ret = raw_default_output(fp, fd, str, len);
+ ret = (int)raw_default_output(fp, fd, str, len);
if (color)
raw_default_output(fp, fd, A_RESET, strlen(A_RESET));
int fy_emit_setup(struct fy_emitter *emit, const struct fy_emitter_cfg *cfg);
void fy_emit_cleanup(struct fy_emitter *emit);
-void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len);
+void fy_emit_write(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, size_t len);
static inline bool fy_emit_whitespace(struct fy_emitter *emit)
{
if (!fyp || !fye)
return;
- if (fy_reader_generates_events(fyp->reader))
- return fy_reader_event_free(fyp->reader, fye);
+ if (fy_reader_generates_events(fyp->reader)) {
+ fy_reader_event_free(fyp->reader, fye);
+ return;
+ }
fyep = container_of(fye, struct fy_eventp, e);
case FYET_ALIAS:
if (type == FYET_SCALAR) {
+ fye->scalar.value = fye->scalar.anchor = fye->scalar.tag = NULL;
sstyle = va_arg(ap, enum fy_scalar_style);
value = va_arg(ap, const char *);
len = va_arg(ap, size_t);
if (len == FY_NT)
len = strlen(value);
} else {
+ fye->alias.anchor = NULL;
sstyle = FYSS_PLAIN;
value = va_arg(ap, const char *);
if (!value) {
return fy_document_state_version(fye->document_start.document_state);
}
+char *fy_event_to_string(struct fy_event *fye)
+{
+ struct fy_memstream *fyms = NULL;
+ FILE *fp = NULL;
+ char *mbuf = NULL;
+ const char *anchor = NULL;
+ const char *tag = NULL;
+ const char *text = NULL;
+ const char *alias = NULL;
+ size_t msize, anchor_len = 0, tag_len = 0, text_len = 0, alias_len = 0;
+ enum fy_scalar_style style;
+ const uint8_t *p;
+ int i, c, w;
+
+ if (!fye)
+ return NULL;
+
+ fyms = fy_memstream_open(&fp);
+ if (!fyms)
+ return NULL;
+
+ /* event type */
+ switch (fye->type) {
+ case FYET_NONE:
+ fprintf(fp, "???");
+ break;
+ case FYET_STREAM_START:
+ fprintf(fp, "+STR");
+ break;
+ case FYET_STREAM_END:
+ fprintf(fp, "-STR");
+ break;
+ case FYET_DOCUMENT_START:
+ fprintf(fp, "+DOC");
+ break;
+ case FYET_DOCUMENT_END:
+ fprintf(fp, "-DOC");
+ break;
+ case FYET_MAPPING_START:
+ fprintf(fp, "+MAP");
+ if (fye->mapping_start.anchor)
+ anchor = fy_token_get_text(fye->mapping_start.anchor, &anchor_len);
+ if (fye->mapping_start.tag)
+ tag = fy_token_get_text(fye->mapping_start.tag, &tag_len);
+ if (fy_event_get_node_style(fye) == FYNS_FLOW)
+ fprintf(fp, " {}");
+ break;
+ case FYET_MAPPING_END:
+ fprintf(fp, "-MAP");
+ break;
+ case FYET_SEQUENCE_START:
+ fprintf(fp, "+SEQ");
+ if (fye->sequence_start.anchor)
+ anchor = fy_token_get_text(fye->sequence_start.anchor, &anchor_len);
+ if (fye->sequence_start.tag)
+ tag = fy_token_get_text(fye->sequence_start.tag, &tag_len);
+ if (fy_event_get_node_style(fye) == FYNS_FLOW)
+ fprintf(fp, " []");
+ break;
+ case FYET_SEQUENCE_END:
+ fprintf(fp, "-SEQ");
+ break;
+ case FYET_SCALAR:
+ fprintf(fp, "=VAL");
+ if (fye->scalar.anchor)
+ anchor = fy_token_get_text(fye->scalar.anchor, &anchor_len);
+ if (fye->scalar.tag)
+ tag = fy_token_get_text(fye->scalar.tag, &tag_len);
+ break;
+ case FYET_ALIAS:
+ fprintf(fp, "=ALI");
+ break;
+ default:
+ break;
+ }
+
+ /* (position) anchor and tag */
+ if (anchor)
+ fprintf(fp, " &%.*s", (int)anchor_len, anchor);
+ if (tag)
+ fprintf(fp, " <%.*s>", (int)tag_len, tag);
+
+ /* style hint */
+ switch (fye->type) {
+ default:
+ break;
+ case FYET_DOCUMENT_START:
+ if (!fy_document_event_is_implicit(fye))
+ fprintf(fp, " ---");
+ break;
+ case FYET_DOCUMENT_END:
+ if (!fy_document_event_is_implicit(fye))
+ fprintf(fp, " ...");
+ break;
+ case FYET_MAPPING_START:
+ break;
+ case FYET_SEQUENCE_START:
+ break;
+ case FYET_SCALAR:
+ style = fy_token_scalar_style(fye->scalar.value);
+ switch (style) {
+ case FYSS_ANY:
+ fprintf(fp, " !");
+ break;
+ case FYSS_PLAIN:
+ fprintf(fp, " :");
+ break;
+ case FYSS_SINGLE_QUOTED:
+ fprintf(fp, " '");
+ break;
+ case FYSS_DOUBLE_QUOTED:
+ fprintf(fp, " \"");
+ break;
+ case FYSS_LITERAL:
+ fprintf(fp, " |");
+ break;
+ case FYSS_FOLDED:
+ fprintf(fp, " >");
+ break;
+ default:
+ break;
+ }
+ break;
+ case FYET_ALIAS:
+ break;
+ }
+
+ /* content */
+ switch (fye->type) {
+ default:
+ break;
+ case FYET_SCALAR:
+ text = fy_token_get_text(fye->scalar.value, &text_len);
+ for (p = (const uint8_t *)text; text_len > 0; p += w, text_len -= (size_t)w) {
+
+ /* get width from the first octet */
+ w = (p[0] & 0x80) == 0x00 ? 1 :
+ (p[0] & 0xe0) == 0xc0 ? 2 :
+ (p[0] & 0xf0) == 0xe0 ? 3 :
+ (p[0] & 0xf8) == 0xf0 ? 4 : 0;
+
+ /* error, clip it */
+ if ((size_t)w > text_len)
+ break;
+
+ /* initial value */
+ c = p[0] & (0xff >> w);
+ for (i = 1; i < w; i++) {
+ if ((p[i] & 0xc0) != 0x80)
+ break;
+ c = (c << 6) | (p[i] & 0x3f);
+ }
+
+ /* check for validity */
+ if ((w == 4 && c < 0x10000) ||
+ (w == 3 && c < 0x800) ||
+ (w == 2 && c < 0x80) ||
+ (c >= 0xd800 && c <= 0xdfff) || c >= 0x110000)
+ break;
+
+ switch (c) {
+ case '\\':
+ fprintf(fp, "\\\\");
+ break;
+ case '\0':
+ fprintf(fp, "\\0");
+ break;
+ case '\b':
+ fprintf(fp, "\\b");
+ break;
+ case '\f':
+ fprintf(fp, "\\f");
+ break;
+ case '\n':
+ fprintf(fp, "\\n");
+ break;
+ case '\r':
+ fprintf(fp, "\\r");
+ break;
+ case '\t':
+ fprintf(fp, "\\t");
+ break;
+ case '\a':
+ fprintf(fp, "\\a");
+ break;
+ case '\v':
+ fprintf(fp, "\\v");
+ break;
+ case '\x1b':
+ fprintf(fp, "\\e");
+ break;
+ case 0x85:
+ fprintf(fp, "\\N");
+ break;
+ case 0xa0:
+ fprintf(fp, "\\_");
+ break;
+ case 0x2028:
+ fprintf(fp, "\\L");
+ break;
+ case 0x2029:
+ fprintf(fp, "\\P");
+ break;
+ default:
+ if ((c >= 0x01 && c <= 0x1f) || c == 0x7f || /* C0 */
+ (c >= 0x80 && c <= 0x9f)) /* C1 */
+ fprintf(fp, "\\x%02x", c);
+ else
+ fprintf(fp, "%.*s", w, p);
+ break;
+ }
+ }
+ break;
+ case FYET_ALIAS:
+ alias = fy_token_get_text(fye->alias.anchor, &alias_len);
+ fprintf(fp, " %s%.*s", "*", (int)alias_len, alias);
+ break;
+ }
+
+ mbuf = fy_memstream_close(fyms, &msize);
+ return mbuf;
+}
+
struct fy_eventp *
fy_document_iterator_eventp_alloc(struct fy_document_iterator *fydi)
{
fy_document_iterator_eventp_recycle(fydi, fyep);
}
+
+const char *
+fy_event_get_comments(struct fy_event *fye)
+{
+ struct fy_token *fyt;
+
+ if (!fye)
+ return NULL;
+
+ fyt = fy_event_get_token(fye);
+ if (!fyt)
+ return NULL;
+
+ return fy_token_get_comments(fyt);
+}
struct fy_token *fy_event_get_and_clear_anchor_token(struct fy_event *fye);
const char *fy_event_get_anchor(struct fy_event *fye, size_t *anchor_lenp);
+struct fy_eventp *
+fy_eventp_vcreate_internal(struct fy_eventp_list *recycled_list, struct fy_diag *diag,
+ struct fy_document_state *fyds, enum fy_event_type type, va_list ap);
+
+struct fy_token_list;
+
+void fy_eventp_clean_rl(struct fy_token_list *fytl, struct fy_eventp *fyep);
+
+/* convert to event dump string, string is malloc'ed */
+char *fy_event_to_string(struct fy_event *fye);
+
struct fy_document_iterator;
struct fy_eventp *fy_document_iterator_eventp_alloc(struct fy_document_iterator *fydi);
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
#include <assert.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/mman.h>
#include <sys/ioctl.h>
-#include <limits.h>
-#include <errno.h>
+#endif
#include <libfyaml.h>
+#include "fy-win32.h"
#include "fy-parse.h"
#include "fy-ctype.h"
int fy_reader_file_open(struct fy_reader *fyr, const char *filename)
{
+ int flags = O_RDONLY;
+
if (!fyr || !filename)
return -1;
if (fyr->ops && fyr->ops->file_open)
return fyr->ops->file_open(fyr, filename);
- return open(filename, O_RDONLY);
+ return open(filename, flags);
}
void fy_reader_reset(struct fy_reader *fyr)
break;
/* if we're not ignoring stdio, open a FILE* using the fd */
- if (!fyi->cfg.ignore_stdio) {
- fyi->fp = fdopen(fyi->fd, "r");
+ if (sb.st_size > 0 && !fyi->cfg.ignore_stdio) {
+ fyi->fp = fdopen(fyi->fd, "rb");
fyr_error_check(fyr, rc != -1, err_out, "failed to fdopen %s", fyi->name);
} else
fyi->fp = NULL;
case fyit_stream:
case fyit_callback:
/* chop extra buffer */
- buf = realloc(fyi->buffer, current_input_pos);
- fyr_error_check(fyr, buf || !current_input_pos, err_out,
- "realloc() failed");
+ if (current_input_pos > 0) {
+ buf = realloc(fyi->buffer, current_input_pos);
+ fyr_error_check(fyr, buf || !current_input_pos, err_out,
+ "realloc() failed");
+ } else {
+ /* for empty stream, just free everything */
+ free(fyi->buffer);
+ buf = NULL;
+ }
/* increate input generation; required for direct input to work */
if (fyi->buffer != buf) {
assert(fyi->read >= current_input_pos);
fyi_new->read = fyi->read - current_input_pos;
if (fyi_new->read > 0)
- memcpy(fyi_new->buffer, fyi->buffer + current_input_pos, fyi_new->read);
+ memcpy(fyi_new->buffer, (const char *)fyi->buffer + current_input_pos, fyi_new->read);
fyr->this_input_start += current_input_pos;
fyr->current_input = fyi_new;
fyr->current_ptr = fyi_new->buffer;
fyr->current_ptr_start = fyi_new->buffer;
- fyr->current_ptr_end = fyr->current_ptr_start + fyi_new->read;
+ fyr->current_ptr_end = (const char *)fyr->current_ptr_start + fyi_new->read;
fyr_debug(fyr, "chop at this_input_start=%zu chop=%zu\n", fyr->this_input_start, fyi->chop);
left = size - current_input_pos;
assert(left <= size);
- p = start + current_input_pos;
+ p = (const char *)start + current_input_pos;
if (leftp)
*leftp = left;
if (!fyr->current_ptr_start) {
fyr->current_ptr_start = start;
- fyr->current_ptr_end = start + size;
+ fyr->current_ptr_end = (const char *)start + size;
}
fyr->current_ptr = p;
fyr_debug(fyr, "file input exhausted");
break;
}
- p = fyi->addr + pos;
+ p = (char *)fyi->addr + pos;
break;
}
assert(fyi->read >= pos);
left = fyi->read - pos;
- p = fyi->buffer + pos;
+ p = (char *)fyi->buffer + pos;
/* enough to satisfy directly */
if (left >= pull)
fyi->allocated = size;
space = fyi->allocated - pos;
- p = fyi->buffer + pos;
+ p = (char *)fyi->buffer + pos;
}
/* always try to read up to the allocated space */
fyr_debug(fyr, "performing callback request of %zu", nreadreq);
- nread = fyi->cfg.callback.input(fyi->cfg.userdata, fyi->buffer + fyi->read, nreadreq);
+ nread = fyi->cfg.callback.input(fyi->cfg.userdata, (char *)fyi->buffer + fyi->read, nreadreq);
fyr_debug(fyr, "callback returned %zu", nread);
fyr_debug(fyr, "performing fread request of %zu", nreadreq);
- nread = fread(fyi->buffer + fyi->read, 1, nreadreq, fyi->fp);
+ nread = fread((char *)fyi->buffer + fyi->read, 1, nreadreq, fyi->fp);
fyr_debug(fyr, "fread returned %zu", nread);
fyr_debug(fyr, "performing read request of %zu", nreadreq);
do {
- snread = read(fyi->fd, fyi->buffer + fyi->read, nreadreq);
+ snread = read(fyi->fd, (char *)fyi->buffer + fyi->read, nreadreq);
} while (snread == -1 && errno == EAGAIN);
-
fyr_debug(fyr, "read returned %zd", snread);
if (snread == -1) {
fyr_debug(fyr, "memory input exhausted");
break;
}
- p = fyi->cfg.memory.data + pos;
+ p = (const char *)fyi->cfg.memory.data + pos;
break;
case fyit_alloc:
fyr_debug(fyr, "alloc input exhausted");
break;
}
- p = fyi->cfg.alloc.data + pos;
+ p = (const char *)fyi->cfg.alloc.data + pos;
break;
case fyit_dociter:
break;
case fyit_memory:
ret = asprintf(&fyi->name, "<memory-@%p-%p>",
- fyic->memory.data, fyic->memory.data + fyic->memory.size - 1);
+ fyic->memory.data, (const char *)fyic->memory.data + fyic->memory.size - 1);
if (ret == -1)
fyi->name = NULL;
break;
case fyit_alloc:
ret = asprintf(&fyi->name, "<alloc-@%p-%p>",
- fyic->memory.data, fyic->memory.data + fyic->memory.size - 1);
+ fyic->memory.data, (const char *)fyic->memory.data + fyic->memory.size - 1);
if (ret == -1)
fyi->name = NULL;
break;
fyr->current_ptr_start = new_start;
}
- fyr->current_ptr_end = fyr->current_ptr_start + new_size;
+ fyr->current_ptr_end = (const char *)fyr->current_ptr_start + new_size;
}
fyr->current_ptr = p;
break;
}
+ /* if we've parsed need to clamp */
+ if (fyi->state == FYIS_PARSED) {
+ switch (fyi->cfg.type) {
+ case fyit_file:
+ case fyit_fd:
+ case fyit_stream:
+ case fyit_callback:
+ if (fyi->allocated < size)
+ size = fyi->allocated;
+ break;
+ default:
+ break;
+ }
+ }
+
*sizep = size;
return start;
}
static FY_ALWAYS_INLINE inline size_t
fy_reader_current_input_pos(const struct fy_reader *fyr)
{
- return (size_t)(fyr->current_ptr - fyr->current_ptr_start);
+ return (size_t)((const char *)fyr->current_ptr - (const char *)fyr->current_ptr_start);
}
static FY_ALWAYS_INLINE inline size_t
fy_reader_current_left(const struct fy_reader *fyr)
{
- return (size_t)(fyr->current_ptr_end - fyr->current_ptr);
+ return (size_t)((const char *)fyr->current_ptr_end - (const char *)fyr->current_ptr);
}
static inline bool
assert(fyr);
if ((ssize_t)(fy_reader_current_left(fyr) - offset) >= 4)
- return fy_utf8_get(fyr->current_ptr + offset, 4, wp);
+ return fy_utf8_get((const char *)fyr->current_ptr + offset, 4, wp);
return fy_reader_peek_at_offset_width_slow_path(fyr, offset, wp);
}
assert(fyr);
if ((ssize_t)(fy_reader_current_left(fyr) - offset) >= 4)
- return fy_utf8_get_64(fyr->current_ptr + offset, 4);
+ return fy_utf8_get_64((const char *)fyr->current_ptr + offset, 4);
return fy_reader_peek_at_offset_width_slow_path_64(fyr, offset);
}
static FY_ALWAYS_INLINE inline void
fy_reader_advance_octets(struct fy_reader *fyr, size_t advance)
{
- fyr->current_ptr += advance;
+ fyr->current_ptr = (const char *)fyr->current_ptr + advance;
}
void fy_reader_advance_slow_path(struct fy_reader *fyr, int c);
{
assert(fy_utf8_is_valid(c));
fy_reader_advance_octets(fyr, fy_utf8_width(c));
- fy_reader_update_state_lb_mode(fyr, c, lb_mode);
+ /* Handle CRLF as single line break */
+ if (c == '\r' && fy_reader_peek(fyr) == '\n') {
+ fy_reader_advance_octets(fyr, 1);
+ fyr->column = 0;
+ fyr->line++;
+ } else {
+ fy_reader_update_state_lb_mode(fyr, c, lb_mode);
+ }
}
static FY_ALWAYS_INLINE inline void
#define FYR_NODE_WARNING(_fyr, _fyn, _type, _module, _fmt, ...) \
FYR_NODE_DIAG(_fyr, _fyn, FYET_WARNING, _module, _fmt, ## __VA_ARGS__)
+struct fy_input *fy_input_from_data(const char *data, size_t size,
+ struct fy_atom *handle, bool simple);
+struct fy_input *fy_input_from_malloc_data(char *data, size_t size,
+ struct fy_atom *handle, bool simple);
+
#endif
#include <stdio.h>
#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <unistd.h>
#include <ctype.h>
#include <libfyaml.h>
#include <stdio.h>
#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
#include <limits.h>
+#include <fcntl.h>
#include <libfyaml.h>
+#include "fy-win32.h"
#include "fy-parse.h"
#include "fy-utils.h"
#define ATOM_SIZE_CHECK
#endif
+#ifdef ATOM_SIZE_CHECK
+#define FORCE_ATOM_SIZE_CHECK_DEFAULT true
+#else
+#define FORCE_ATOM_SIZE_CHECK_DEFAULT false
+#endif
+
const char *fy_library_version(void)
{
#ifndef VERSION
versp++;
- idx = versp - fy_map_option_to_version;
+ idx = (unsigned int)(versp - fy_map_option_to_version);
if (idx >= sizeof(fy_map_option_to_version)/sizeof(fy_map_option_to_version[0]))
return NULL;
fy_eventp_list_init(&fyp->mks.args);
fy_atom_reset(&fyp->last_comment);
+ fy_atom_reset(&fyp->override_comment);
fyp->suppress_recycling = !!(fyp->cfg.flags & FYPCF_DISABLE_RECYCLING) ||
(getenv("FY_VALGRIND") &&
fy_input_unref(fyp->last_comment.fyi);
fy_atom_reset(&fyp->last_comment);
+ fy_input_unref(fyp->override_comment.fyi);
+ fy_atom_reset(&fyp->override_comment);
+
fy_input_unref(fyp->last_event_handle.fyi);
fy_atom_reset(&fyp->last_event_handle);
bool ws_or_lb;
if (!a || !b)
- return NULL;
+ return false;
/* must be on same input */
if (a->fyi != b->fyi)
- return NULL;
+ return false;
/* must be comments */
if (a->style != FYAS_COMMENT || b->style != FYAS_COMMENT)
- return NULL;
+ return false;
/* a must be before */
if (a->end_mark.input_pos > b->start_mark.input_pos) {
return true;
}
+static inline bool
+fy_reset_override_comment(struct fy_parser *fyp)
+{
+ if (!(fyp->cfg.flags & FYPCF_PARSE_COMMENTS))
+ return false;
+
+ if (!fy_atom_is_set(&fyp->override_comment))
+ return false;
+
+ fy_atom_reset(&fyp->override_comment);
+ return true;
+}
+
+/* -1 error, 0, no comment attached, 1 comment attached */
int fy_attach_comments_if_any(struct fy_parser *fyp, struct fy_token *fyt)
{
struct fy_atom *handle;
struct fy_mark fym;
- int c, rc;
+ int c, rc, count;
if (!fyp || !fyt)
return -1;
if (!(fyp->cfg.flags & FYPCF_PARSE_COMMENTS))
return 0;
+ count = 0;
+
+ /* special handling for document start */
+ if (fyt->type == FYTT_DOCUMENT_START && fy_atom_is_set(&fyp->override_comment)) {
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() top failed\n");
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ *handle = fyp->override_comment;
+ count++;
+
+ fy_reset_override_comment(fyp);
+ }
+
/* if a last comment exists and is valid */
- if (fy_atom_is_set(&fyp->last_comment) &&
- (handle = fy_token_comment_handle(fyt, fycp_top, true)) != NULL) {
+ if (fy_atom_is_set(&fyp->last_comment)) {
+
+ handle = fy_token_comment_handle(fyt, count == 0 ? fycp_top : fycp_right, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() top failed\n");
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
*handle = fyp->last_comment;
+ count++;
fy_reset_last_comment(fyp);
}
while (fy_is_ws(c = fy_parse_peek(fyp)))
fy_advance(fyp, c);
- if (c == '#') {
- fy_get_mark(fyp, &fym);
+ if (c != '#')
+ return 0;
- /* it's a right comment only if it's on the same line */
- if (fym.line == fyt->handle.end_mark.line)
- handle = fy_token_comment_handle(fyt, fycp_right, true);
- else
- handle = &fyp->last_comment; /* otherwise, last comment */
+ fy_get_mark(fyp, &fym);
+
+ /* only the one that in the same line */
+ if (fym.line != fyt->handle.end_mark.line)
+ return 0;
+
+ /* it's a right comment only if it's on the same line */
+ handle = fy_token_comment_handle(fyt, fycp_right, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() right failed\n");
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ rc = fy_scan_comment(fyp, handle, false);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_scan_comment() failed");
+
+ if (fy_atom_is_set(handle))
+ count++;
+ return count;
+
+err_out_rc:
+ return rc;
+err_out:
+ rc = -1;
+ goto err_out;
+}
+
+int fy_fetch_flow_collection_entry(struct fy_parser *fyp, int c);
+
+int fy_parse_handle_comma(struct fy_parser *fyp, int c)
+{
+ struct fy_mark m;
+ int rc;
+
+ fyp->indent_line = fyp_line(fyp);
+
+ fyp_error_check(fyp, c == ',', err_out,
+ "illegal comma");
+
+ fy_get_mark(fyp, &m);
+
+ fyp_scan_debug(fyp, "fy_fetch_flow_collection_entry(%c)", c);
+ rc = fy_fetch_flow_collection_entry(fyp, c);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_fetch_flow_collection_entry() failed");
+
+ fyp->last_was_comma = true;
+ fyp->last_comma_mark = m;
- rc = fy_scan_comment(fyp, handle, false);
- fyp_error_check(fyp, !rc, err_out_rc,
- "fy_scan_comment() failed");
- }
return 0;
err_out_rc:
return rc;
+err_out:
+ rc = -1;
+ goto err_out_rc;
+}
+
+int fy_parse_handle_right_comment_after_comma(struct fy_parser *fyp, struct fy_token *fyt)
+{
+ int c, rc, start_line;
+
+ /* not collecting comment or now in flow mode */
+ if (!(fyp->cfg.flags & FYPCF_PARSE_COMMENTS) || !fyp->flow_level)
+ return 0;
+
+ /* we can only attach right to these tokens */
+ if (fyt->type != FYTT_SCALAR &&
+ fyt->type != FYTT_FLOW_SEQUENCE_END &&
+ fyt->type != FYTT_FLOW_MAPPING_END)
+ return 0;
+
+ /* skip white space while we're on the same line */
+ start_line = fyp_line(fyp);
+ while (fy_is_ws(c = fy_parse_peek(fyp)))
+ fy_advance(fyp, c);
+
+ /* is it a comma at the same line? */
+ if (c != ',' || start_line != fyp_line(fyp))
+ return 0;
+
+ /* immediately parse the comma because grab the scalar to attach the comment */
+ rc = fy_parse_handle_comma(fyp, ',');
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_parse_handle_comma() failed");
+
+ return 0;
+err_out_rc:
+ return rc;
+}
+
+int fy_parse_handle_comments_after_token(struct fy_parser *fyp, struct fy_token *fyt)
+{
+ int rc;
+
+ if (!(fyp->cfg.flags & FYPCF_PARSE_COMMENTS))
+ return 0;
+
+ rc = fy_attach_comments_if_any(fyp, fyt);
+ fyp_error_check(fyp, rc >= 0, err_out_rc,
+ "fy_attach_right_hand_comment() failed");
+
+ rc = fy_parse_handle_right_comment_after_comma(fyp, fyt);
+ fyp_error_check(fyp, rc >= 0, err_out_rc,
+ "fy_parse_handle_right_comment_after_comma() failed");
+
+ return 0;
+
+err_out_rc:
+ return rc;
+err_out:
+ rc = -1;
+ goto err_out;
}
int fy_scan_to_next_token(struct fy_parser *fyp)
rc = fy_scan_comment(fyp, NULL, false);
fyp_error_check(fyp, !rc, err_out_rc,
"fy_scan_comment() failed");
-
-
} else {
memset(&this_comment, 0, sizeof(this_comment));
if (fy_atom_is_set(&fyp->last_comment)) {
- /* merge consecutive comments */
- if (fy_comment_atoms_seperated_by_ws(fyp, &fyp->last_comment, &this_comment)) {
- fyp->last_comment.end_mark = this_comment.end_mark;
- fy_input_unref(this_comment.fyi);
- fy_atom_reset(&this_comment);
+ /* merge consecutive override comments */
+ if (fy_atom_is_set(&fyp->override_comment) &&
+ fy_comment_atoms_seperated_by_ws(fyp, &fyp->override_comment, &fyp->last_comment)) {
+ fyp->override_comment.end_mark = fyp->last_comment.end_mark;
} else {
- fy_input_unref(fyp->last_comment.fyi);
- fy_atom_reset(&fyp->last_comment);
- fyp->last_comment = this_comment;
+ /* override comment keeps the last comment */
+ fy_input_unref(fyp->override_comment.fyi);
+ fy_atom_reset(&fyp->override_comment);
+ fyp->override_comment.fyi = fy_input_ref(fyp->last_comment.fyi);
+ fyp->override_comment = fyp->last_comment;
}
+ fy_input_unref(fyp->last_comment.fyi);
+ fy_atom_reset(&fyp->last_comment);
+ fyp->last_comment = this_comment;
+
} else
fyp->last_comment = this_comment;
}
while (fy_is_ws(c = fy_parse_peek(fyp)))
fy_advance(fyp, c);
+ rc = fy_attach_comments_if_any(fyp, fyt);
+ fyp_error_check(fyp, rc >= 0, err_out_rc,
+ "fy_attach_right_hand_comment() failed");
+
return 0;
err_out:
"fy_save_simple_key_mark() failed");
}
+ /* if a last comment exists and is valid */
+ if ((fyp->cfg.flags & FYPCF_PARSE_COMMENTS) &&
+ (fy_atom_is_set(&fyp->override_comment) || fy_atom_is_set(&fyp->last_comment))) {
+
+ struct fy_atom *handle;
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ if (fy_atom_is_set(&fyp->override_comment)) {
+ *handle = fyp->override_comment;
+ fy_atom_reset(&fyp->override_comment);
+ } else if (fy_atom_is_set(&fyp->last_comment)) {
+ *handle = fyp->last_comment;
+ fy_atom_reset(&fyp->last_comment);
+ }
+ }
+
/* increase flow level */
fyp->flow_level++;
fyp_error_check(fyp, fyp->flow_level, err_out,
}
}
+ rc = fy_parse_handle_comments_after_token(fyp, fyt);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_parse_handle_comments_after_token() failed");
+
+
return 0;
err_out:
fyp->tab_used_for_ws = false;
fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
- fyt_last = fy_token_list_tail(&fyp->queued_tokens);
+ if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS)
+ fyt_last = fy_token_list_tail(&fyp->queued_tokens);
+ else
+ fyt_last = NULL;
fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, type, 1);
fyp_error_check(fyp, fyt, err_out,
"invalid comment after comma");
/* skip white space */
- while (fy_is_ws(c = fy_parse_peek(fyp)))
- fy_advance(fyp, c);
-
- if (c == '#') {
- if (fyt_last)
- fyt = fyt_last;
+ if (fyt_last) {
+ while (fy_is_ws(c = fy_parse_peek(fyp)))
+ fy_advance(fyp, c);
- handle = NULL;
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS)
- handle = fy_token_comment_handle(fyt, fycp_right, true);
+ if (c == '#') {
+ handle = fy_token_comment_handle(fyt_last, fycp_right, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
- rc = fy_scan_comment(fyp, handle, true);
- fyp_error_check(fyp, !rc, err_out_rc,
- "fy_scan_comment() failed");
+ rc = fy_scan_comment(fyp, handle, true);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_scan_comment() failed");
+ }
}
return 0;
struct fy_mark mark;
struct fy_simple_key *fysk;
struct fy_token *fyt;
+ struct fy_atom *handle;
fyp_error_check(fyp, c == '-', err_out,
"illegal block entry");
fyt = fy_token_queue_simple_internal(fyp, &fyp->queued_tokens, FYTT_BLOCK_SEQUENCE_START, 0);
fyp_error_check(fyp, fyt, err_out,
"fy_token_queue_simple_internal() failed");
+
+ /* if a last comment exists and is valid */
+ if ((fyp->cfg.flags & FYPCF_PARSE_COMMENTS) &&
+ (fy_atom_is_set(&fyp->override_comment) || fy_atom_is_set(&fyp->last_comment))) {
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ if (fy_atom_is_set(&fyp->override_comment)) {
+ *handle = fyp->override_comment;
+ fy_atom_reset(&fyp->override_comment);
+ } else if (fy_atom_is_set(&fyp->last_comment)) {
+ *handle = fyp->last_comment;
+ fy_atom_reset(&fyp->last_comment);
+ }
+ }
}
+ /* always reset the override comment */
+ fy_reset_override_comment(fyp);
+
if (c == '-' && fyp->flow_level) {
/* this is an error, but we let the parser catch it */
;
fyt = fy_token_queue_simple_internal(fyp, &fyp->queued_tokens, FYTT_BLOCK_MAPPING_START, 0);
fyp_error_check(fyp, fyt, err_out,
"fy_token_queue_simple_internal() failed");
+
+ /* if a last comment exists and is valid */
+ if ((fyp->cfg.flags & FYPCF_PARSE_COMMENTS) &&
+ (fy_atom_is_set(&fyp->override_comment) || fy_atom_is_set(&fyp->last_comment))) {
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ if (fy_atom_is_set(&fyp->override_comment)) {
+ *handle = fyp->override_comment;
+ fy_atom_reset(&fyp->override_comment);
+ } else if (fy_atom_is_set(&fyp->last_comment)) {
+ *handle = fyp->last_comment;
+ fy_atom_reset(&fyp->last_comment);
+ }
+ }
}
rc = fy_remove_simple_key(fyp, FYTT_KEY);
} else
fyp->tab_used_for_ws = false; // XXX
- /* comment? */
- if (c == '#') {
+ /* comment which we care about? */
+ if ((fyp->cfg.flags & FYPCF_PARSE_COMMENTS) && c == '#') {
+
+ handle = fy_token_comment_handle(fyt, fycp_right, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
- handle = NULL;
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS)
- handle = fy_token_comment_handle(fyt, fycp_right, true);
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
rc = fy_scan_comment(fyp, handle, false);
fyp_error_check(fyp, !rc, err_out_rc,
fyp_error_check(fyp, fyt, err_out,
"fy_token_queue_simple_internal() failed");
+ /* if a last comment exists and is valid */
+ if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS) {
+
+ struct fy_atom *key_handle, *handle;
+
+ if (fysk && fysk->token) {
+ key_handle = fy_token_comment_handle(fysk->token, fycp_top, true);
+ fyp_error_check(fyp, key_handle, err_out,
+ "fy_token_comment_handle() failed");
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+
+ /* move the comment to the block mapping start */
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+ *handle = *key_handle;
+ fy_atom_reset(key_handle);
+ }
+
+ handle = fy_token_comment_handle(fyt, fycp_top, true);
+ fyp_error_check(fyp, handle, err_out,
+ "fy_token_comment_handle() failed");
+
+ if (fy_atom_is_set(&fyp->override_comment)) {
+ *handle = fyp->override_comment;
+ fy_atom_reset(&fyp->override_comment);
+ } else if (fy_atom_is_set(&fyp->last_comment)) {
+ *handle = fyp->last_comment;
+ fy_atom_reset(&fyp->last_comment);
+ }
+ }
+
/* update with this mark */
fyt->handle.start_mark = fyt->handle.end_mark = mark_insert;
}
fyp->pending_complex_key_column);
}
- if (fyt_insert) {
+ if ((fyp->cfg.flags & FYPCF_PARSE_COMMENTS) && fyt_insert) {
/* eat whitespace */
while (fy_is_blank(c = fy_parse_peek(fyp)))
fy_advance(fyp, c);
/* comment? */
if (c == '#') {
- chandle = NULL;
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS)
- chandle = fy_token_comment_handle(fyt_insert, fycp_right, true);
+ chandle = fy_token_comment_handle(fyt_insert, fycp_right, true);
+ fyp_error_check(fyp, chandle, err_out,
+ "fy_token_comment_handle() failed");
+
+ fy_input_unref(chandle->fyi);
+ fy_atom_reset(chandle);
rc = fy_scan_comment(fyp, chandle, false);
fyp_error_check(fyp, !rc, err_out_rc,
"fy_scan_comment() failed");
}
-
}
return 0;
fy_advance(fyp, c);
- break_length = fy_utf8_width(c);
+ break_length = (int)fy_utf8_width(c);
(*breaks)++;
(*breaks_length) += 1;
int lastc, rc, increment = 0, current_indent, new_indent, indent = 0;
int breaks, breaks_length, presentation_breaks_length, first_break_length;
bool doc_start_end_detected, empty, empty_line, prev_empty_line, indented, prev_indented, first;
- bool has_ws, has_lb, starts_with_ws, starts_with_lb, ends_with_ws, ends_with_lb, trailing_lb;
+ bool has_ws, has_lb, has_cr, starts_with_ws, starts_with_lb, ends_with_ws, ends_with_lb, trailing_lb;
bool pending_nl, ends_with_eof, starts_with_eof, content_is_eof;
struct fy_token *fyt;
size_t length, line_length, trailing_ws, trailing_breaks_length;
int actual_lb_length, pending_lb_length;
struct fy_mark indicator_mark;
bool generated_indent, final_lb;
-#ifdef ATOM_SIZE_CHECK
size_t tlength;
-#endif
fyp_error_check(fyp, c == '|' || c == '>', err_out,
"bad start of block scalar ('%s')",
empty = true;
has_ws = false;
has_lb = false;
+ has_cr = false;
starts_with_ws = false;
starts_with_lb = false;
ends_with_ws = false;
if (!fy_is_z(c)) {
/* eat line break */
- actual_lb_length = fy_utf8_width(c);
+ actual_lb_length = (int)fy_utf8_width(c);
fy_advance(fyp, c);
has_lb = true;
"fy_scan_block_scalar_indent() failed");
if (fy_is_lb_LS_PS(c))
presentation_breaks_length += actual_lb_length;
+
+ /* very simple heuristic, if we hit a '\r' then force size check */
+ has_cr |= c == '\r';
} else {
has_lb = false;
new_indent = indent;
handle.ends_with_eof = ends_with_eof;
handle.is_merge_key = false;
-#ifdef ATOM_SIZE_CHECK
- tlength = fy_atom_format_text_length(&handle);
- if (tlength != length) {
- fyp_warning(fyp, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
- tlength, length,
- fy_utf8_format_text_a(fy_atom_data(&handle), fy_atom_size(&handle), fyue_doublequote));
- length = tlength;
+ /* force calculation of length if we had a CR */
+ if (has_cr || FORCE_ATOM_SIZE_CHECK_DEFAULT) {
+ tlength = fy_atom_format_text_length(&handle);
+ if (!has_cr && tlength != length) {
+ fyp_warning(fyp, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
+ tlength, length,
+ fy_utf8_format_text_a(fy_atom_data(&handle), fy_atom_size(&handle), fyue_doublequote));
+ length = tlength;
+ }
}
-#endif
handle.storage_hint = length;
handle.storage_hint_valid = true;
fyp_error_check(fyp, fyt, err_out_rc,
"fy_token_queue() failed");
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS) {
- rc = fy_attach_comments_if_any(fyp, fyt);
- fyp_error_check(fyp, !rc, err_out_rc,
- "fy_attach_right_hand_comment() failed");
- }
+ rc = fy_attach_comments_if_any(fyp, fyt);
+ fyp_error_check(fyp, rc >= 0, err_out_rc,
+ "fy_attach_right_hand_comment() failed");
if (generated_indent) {
rc = fy_pop_indent(fyp);
int breaks_found, blanks_found, break_run, total_code_length;
int breaks_found_length, first_break_length, value;
uint32_t hi_surrogate, lo_surrogate;
- bool is_single, is_multiline, esc_lb, ws_lb_only, has_ws, has_lb, has_esc;
+ bool is_single, is_multiline, esc_lb, ws_lb_only, has_ws, has_lb, has_cr, has_esc;
bool first, starts_with_ws, starts_with_lb, ends_with_ws, ends_with_lb, trailing_lb = false;
bool unicode_esc, is_json_unesc, has_json_esc;
int last_esc_lb, break_length, presentation_breaks_length;
size_t escbuf_len;
enum fy_utf8_escape esc_mode;
const char *ep;
-#ifdef ATOM_SIZE_CHECK
size_t tlength;
-#endif
(void)last_esc_lb;
ws_lb_only = true;
has_ws = false;
has_lb = false;
+ has_cr = false;
starts_with_ws = false;
starts_with_lb = false;
ends_with_ws = false;
size_t len, consumed;
const char *p, *s, *e;
int8_t cc;
- int run;
+ size_t run;
run = 0;
while ((p = fy_reader_ensure_lookahead(fyr, 1, &len)) != NULL) {
consumed = s - p;
if (consumed) {
fy_reader_advance_octets(fyr, consumed);
- fyr->column += consumed;
+ fyr->column += (int)consumed;
lastc = (int)cc;
}
run += consumed;
if (!fy_is_lb_LS_PS(c)) {
break_length = 1;
} else {
- break_length = fy_utf8_width(c);
+ break_length = (int)fy_utf8_width(c);
presentation_breaks_length += break_length;
}
breaks_found_length += break_length;
blanks_found = 0;
esc_lb = false;
+
+ has_cr |= c == '\r';
} else {
has_ws = true;
if (!esc_lb)
/* skip over block scalar end */
fy_reader_advance_by(fyr, 1);
-#ifdef ATOM_SIZE_CHECK
- tlength = fy_atom_format_text_length(handle);
- if (tlength != length) {
- fyr_warning(fyr, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
- tlength, length,
- fy_utf8_format_text_a(fy_atom_data(handle), fy_atom_size(handle), fyue_doublequote));
- length = tlength;
+ if (has_cr || FORCE_ATOM_SIZE_CHECK_DEFAULT) {
+ tlength = fy_atom_format_text_length(handle);
+ if (!has_cr && tlength != length) {
+ fyr_warning(fyr, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
+ tlength, length,
+ fy_utf8_format_text_a(fy_atom_data(handle), fy_atom_size(handle), fyue_doublequote));
+ length = tlength;
+ }
}
-#endif
handle->storage_hint = length;
handle->storage_hint_valid = true;
bool has_high_ascii;
bool simple_key_allowed;
bool last_was_lb;
+ bool has_cr;
};
static FY_ALWAYS_INLINE inline int
struct {
bool run_has_lb : 1;
bool run_has_ws : 1;
+ bool run_has_cr : 1;
bool has_json_esc : 1;
bool has_high_ascii : 1;
bool has_lb : 1;
bool has_ws : 1;
+ bool has_cr : 1;
bool had_run : 1;
bool flow_level_gt_0 : 1;
bool flow_level_le_0_indent_ge_0 : 1;
while (run < len && fy_utf8_is_simple_scalar_no_check((int8_t)s[run]))
run++;
- fyr->column += run;
+ fyr->column += (int)run;
nextc = -1;
} else {
- width = fy_utf8_width(c);
+ width = (int)fy_utf8_width(c);
if (c == ':') {
u.has_lb |= u.run_has_lb;
u.has_ws |= u.run_has_ws;
+ u.has_cr |= u.run_has_cr;
fy_reader_get_mark(fyr, &state->last_mark);
}
breaks_found_length = 0;
first_break_length = 0;
blanks_found_length = 0;
- u.run_has_ws = u.run_has_lb = false;
+ u.run_has_ws = u.run_has_lb = u.run_has_cr = false;
- width = fy_utf8_width(c);
+ width = (int)fy_utf8_width(c);
do {
fy_reader_advance_lb_mode(fyr, c, lb_mode);
first_break_length = width;
breaks_found_length += width;
u.run_has_lb = true;
+ u.run_has_cr |= c == '\r';
}
c = fy_reader_peek_width(fyr, &width);
state->has_json_esc = u.has_json_esc;
state->has_high_ascii = u.has_high_ascii;
state->last_was_lb = u.last_was_lb;
+ state->has_cr = u.has_cr;
return 0;
const enum fy_lb_mode lb_mode = fy_reader_lb_mode(fyr);
bool is_merge_key, ends_with_eof, is_multiline;
int nextc, rc;
+ size_t tlength;
nextc = fy_reader_peek_at(fyr, 1);
handle->simple_key_allowed = state->simple_key_allowed;
handle->high_ascii = state->has_high_ascii;
-#ifdef ATOM_SIZE_CHECK
- size_t tlength;
- tlength = fy_atom_format_text_length(handle);
- if (tlength != state->length) {
- fyr_warning(fyr, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
- tlength, state->length,
- fy_utf8_format_text_a(fy_atom_data(handle), fy_atom_size(handle), fyue_doublequote));
- state->length = tlength;
+ if (state->has_cr || FORCE_ATOM_SIZE_CHECK_DEFAULT) {
+ tlength = fy_atom_format_text_length(handle);
+ if (!state->has_cr && tlength != state->length) {
+ fyr_warning(fyr, "%s: storage hint calculation failed real %zu != hint %zu - \"%s\"", __func__,
+ tlength, state->length,
+ fy_utf8_format_text_a(fy_atom_data(handle), fy_atom_size(handle), fyue_doublequote));
+ state->length = tlength;
+ }
}
-#endif
handle->storage_hint = state->length;
handle->storage_hint_valid = true;
"invalid comment without whitespace after %s scalar",
is_single ? "single-quoted" : "double-quoted");
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS) {
- rc = fy_attach_comments_if_any(fyp, fyt);
- fyp_error_check(fyp, !rc, err_out_rc,
- "fy_attach_right_hand_comment() failed");
- }
+ rc = fy_parse_handle_comments_after_token(fyp, fyt);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_parse_handle_comments_after_token() failed");
return 0;
consumed = s - p;
if (consumed) {
fy_reader_advance_octets(fyr, consumed);
- fyr->column += consumed;
+ fyr->column += (int)consumed;
}
if (s < e)
fyp->simple_key_allowed = handle.simple_key_allowed;
fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
- if (fyp->cfg.flags & FYPCF_PARSE_COMMENTS) {
- rc = fy_attach_comments_if_any(fyp, fyt);
- fyp_error_check(fyp, !rc, err_out_rc,
- "fy_attach_right_hand_comment() failed");
- }
+ rc = fy_parse_handle_comments_after_token(fyp, fyt);
+ fyp_error_check(fyp, !rc, err_out_rc,
+ "fy_parse_handle_comments_after_token() failed");
return 0;
int fy_fetch_tokens(struct fy_parser *fyp)
{
- struct fy_mark m;
bool was_double_colon;
int c, rc;
if (c == ',') {
- fyp->indent_line = fyp_line(fyp);
-
- fy_get_mark(fyp, &m);
-
- fyp_scan_debug(fyp, "fy_fetch_flow_collection_entry(%c)", c);
- rc = fy_fetch_flow_collection_entry(fyp, c);
+ rc = fy_parse_handle_comma(fyp, ',');
fyp_error_check(fyp, !rc, err_out_rc,
- "fy_fetch_flow_collection_entry() failed");
-
- fyp->last_was_comma = true;
- fyp->last_comma_mark = m;
+ "fy_parse_handle_comma() failed");
goto out;
}
struct fy_token *fyt_td;
struct fy_token *fytn;
struct fy_atom *ev_handle = NULL;
+ int rc;
fyds = fyp->current_document_state;
assert(fyds);
fye->sequence_start.sequence_start = fytn;
+ rc = fy_attach_comments_if_any(fyp, fye->sequence_start.sequence_start);
+ fyp_error_check(fyp, rc >= 0, err_out,
+ "fy_attach_comments_if_any() failed");
+
fy_parse_state_set(fyp, FYPS_INDENTLESS_SEQUENCE_ENTRY);
ev_handle = &fye->sequence_start.sequence_start->handle;
char tbuf[16] __FY_DEBUG_UNUSED__;
int rc;
+ (void)tbuf;
version_directive = NULL;
fy_token_list_init(&tag_directives);
fye->document_start.document_state = fy_document_state_ref(fyds);
fye->document_start.implicit = fyds->start_implicit;
+ /* update the handle of the document start token */
+ fytn = fyds->fyt_ds;
+ fyds->fyt_ds = fy_token_ref(fye->document_start.document_start);
+ fy_token_unref(fytn);
+
ev_handle = &fye->document_start.document_start->handle;
break;
static void fy_parse_dump_eventp(struct fy_parser *fyp, struct fy_eventp *fyep, const char *pfx)
{
- struct fy_event *fye = NULL;
- FILE *fp;
char *mbuf = NULL;
- const char *anchor = NULL;
- const char *tag = NULL;
- const char *text = NULL;
- const char *alias = NULL;
- size_t msize, anchor_len = 0, tag_len = 0, text_len = 0, alias_len = 0;
- enum fy_scalar_style style;
- const uint8_t *p;
- int i, c, w;
+
+ if (!fyep)
+ return;
/* perform the enable tests early to avoid the overhead */
if ((FYET_DEBUG >> FYDF_LEVEL_SHIFT) < fyp->diag->cfg.level)
return;
- fp = open_memstream(&mbuf, &msize);
- if (!fp)
+ mbuf = fy_event_to_string(&fyep->e);
+ if (!mbuf)
return;
- if (!fyep) {
- fprintf(fp, "<NULL>");
- goto out;
- }
- fye = &fyep->e;
-
- /* event type */
- switch (fye->type) {
- case FYET_NONE:
- fprintf(fp, "???");
- break;
- case FYET_STREAM_START:
- fprintf(fp, "+STR");
- break;
- case FYET_STREAM_END:
- fprintf(fp, "-STR");
- break;
- case FYET_DOCUMENT_START:
- fprintf(fp, "+DOC");
- break;
- case FYET_DOCUMENT_END:
- fprintf(fp, "-DOC");
- break;
- case FYET_MAPPING_START:
- fprintf(fp, "+MAP");
- if (fye->mapping_start.anchor)
- anchor = fy_token_get_text(fye->mapping_start.anchor, &anchor_len);
- if (fye->mapping_start.tag)
- tag = fy_token_get_text(fye->mapping_start.tag, &tag_len);
- if (fy_event_get_node_style(fye) == FYNS_FLOW)
- fprintf(fp, " {}");
- break;
- case FYET_MAPPING_END:
- fprintf(fp, "-MAP");
- break;
- case FYET_SEQUENCE_START:
- fprintf(fp, "+SEQ");
- if (fye->sequence_start.anchor)
- anchor = fy_token_get_text(fye->sequence_start.anchor, &anchor_len);
- if (fye->sequence_start.tag)
- tag = fy_token_get_text(fye->sequence_start.tag, &tag_len);
- if (fy_event_get_node_style(fye) == FYNS_FLOW)
- fprintf(fp, " []");
- break;
- case FYET_SEQUENCE_END:
- fprintf(fp, "-SEQ");
- break;
- case FYET_SCALAR:
- fprintf(fp, "=VAL");
- if (fye->scalar.anchor)
- anchor = fy_token_get_text(fye->scalar.anchor, &anchor_len);
- if (fye->scalar.tag)
- tag = fy_token_get_text(fye->scalar.tag, &tag_len);
- break;
- case FYET_ALIAS:
- fprintf(fp, "=ALI");
- break;
- default:
- break;
- }
-
- /* (position) anchor and tag */
- if (anchor)
- fprintf(fp, " &%.*s", (int)anchor_len, anchor);
- if (tag)
- fprintf(fp, " <%.*s>", (int)tag_len, tag);
-
- /* style hint */
- switch (fye->type) {
- default:
- break;
- case FYET_DOCUMENT_START:
- if (!fy_document_event_is_implicit(fye))
- fprintf(fp, " ---");
- break;
- case FYET_DOCUMENT_END:
- if (!fy_document_event_is_implicit(fye))
- fprintf(fp, " ...");
- break;
- case FYET_MAPPING_START:
- break;
- case FYET_SEQUENCE_START:
- break;
- case FYET_SCALAR:
- style = fy_token_scalar_style(fye->scalar.value);
- switch (style) {
- case FYSS_PLAIN:
- fprintf(fp, " :");
- break;
- case FYSS_SINGLE_QUOTED:
- fprintf(fp, " '");
- break;
- case FYSS_DOUBLE_QUOTED:
- fprintf(fp, "\"");
- break;
- case FYSS_LITERAL:
- fprintf(fp, " |");
- break;
- case FYSS_FOLDED:
- fprintf(fp, " >");
- break;
- default:
- break;
- }
- break;
- case FYET_ALIAS:
- break;
- }
-
- /* content */
- switch (fye->type) {
- default:
- break;
- case FYET_SCALAR:
- text = fy_token_get_text(fye->scalar.value, &text_len);
- for (p = (const uint8_t *)text; text_len > 0; p += w, text_len -= (size_t)w) {
-
- /* get width from the first octet */
- w = (p[0] & 0x80) == 0x00 ? 1 :
- (p[0] & 0xe0) == 0xc0 ? 2 :
- (p[0] & 0xf0) == 0xe0 ? 3 :
- (p[0] & 0xf8) == 0xf0 ? 4 : 0;
-
- /* error, clip it */
- if ((size_t)w > text_len)
- break;
-
- /* initial value */
- c = p[0] & (0xff >> w);
- for (i = 1; i < w; i++) {
- if ((p[i] & 0xc0) != 0x80)
- break;
- c = (c << 6) | (p[i] & 0x3f);
- }
-
- /* check for validity */
- if ((w == 4 && c < 0x10000) ||
- (w == 3 && c < 0x800) ||
- (w == 2 && c < 0x80) ||
- (c >= 0xd800 && c <= 0xdfff) || c >= 0x110000)
- break;
-
- switch (c) {
- case '\\':
- fprintf(fp, "\\\\");
- break;
- case '\0':
- fprintf(fp, "\\0");
- break;
- case '\b':
- fprintf(fp, "\\b");
- break;
- case '\f':
- fprintf(fp, "\\f");
- break;
- case '\n':
- fprintf(fp, "\\n");
- break;
- case '\r':
- fprintf(fp, "\\r");
- break;
- case '\t':
- fprintf(fp, "\\t");
- break;
- case '\a':
- fprintf(fp, "\\a");
- break;
- case '\v':
- fprintf(fp, "\\v");
- break;
- case '\e':
- fprintf(fp, "\\e");
- break;
- case 0x85:
- fprintf(fp, "\\N");
- break;
- case 0xa0:
- fprintf(fp, "\\_");
- break;
- case 0x2028:
- fprintf(fp, "\\L");
- break;
- case 0x2029:
- fprintf(fp, "\\P");
- break;
- default:
- if ((c >= 0x01 && c <= 0x1f) || c == 0x7f || /* C0 */
- (c >= 0x80 && c <= 0x9f)) /* C1 */
- fprintf(fp, "\\x%02x", c);
- else
- fprintf(fp, "%.*s", w, p);
- break;
- }
- }
- break;
- case FYET_ALIAS:
- alias = fy_token_get_text(fye->alias.anchor, &alias_len);
- fprintf(fp, " %s%.*s", "*", (int)alias_len, alias);
- break;
- }
-
-out:
- fclose(fp);
fyp_parse_debug(fyp, "%s%s", pfx, mbuf);
free(mbuf);
}
memset(&fyic, 0, sizeof(fyic));
fyic.type = fyit_stream;
- fyic.stream.name = name ? : "<stream>";
+ fyic.stream.name = name ? name : "<stream>";
fyic.stream.fp = fp;
fyic.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
fypc->stream_end_token = fy_token_ref(fyp->stream_end_token);
fypc->last_comment.fyi = fy_input_ref(fyp->last_comment.fyi);
+ fypc->override_comment.fyi = fy_input_ref(fyp->override_comment.fyi);
fypc->current_document_state = fy_document_state_ref(fyp->current_document_state);
fypc->default_document_state = fy_document_state_ref(fyp->default_document_state);
fypc->next_single_document = fyp->next_single_document;
fyp->last_comment = fypc->last_comment;
fyp->last_comment.fyi = fy_input_ref(fypc->last_comment.fyi);
+ fy_input_unref(fyp->override_comment.fyi);
+ fyp->override_comment = fypc->override_comment;
+ fyp->override_comment.fyi = fy_input_ref(fypc->override_comment.fyi);
+
/* indents */
while ((fyit = fy_indent_list_pop(&fyp->indent_stack)) != NULL)
fy_parse_indent_recycle(fyp, fyit);
/* last comment */
struct fy_atom last_comment;
+ /* next comment */
+ struct fy_atom override_comment;
/* indent stack */
struct fy_indent_list indent_stack;
fy_get_mark(struct fy_parser *fyp, struct fy_mark *fym)
{
assert(fyp);
- return fy_reader_get_mark(fyp->reader, fym);
+ fy_reader_get_mark(fyp->reader, fym);
}
static inline const void *
fy_advance_octets(struct fy_parser *fyp, size_t advance)
{
assert(fyp);
- return fy_reader_advance_octets(fyp->reader, advance);
+ fy_reader_advance_octets(fyp->reader, advance);
}
/* compare string at the current point (n max) */
{
if (!fyp)
return;
- fyp->reader = fyr ? : &fyp->builtin_reader;
+ fyp->reader = fyr ? fyr : &fyp->builtin_reader;
}
static inline void
void fy_token_clean_rl(struct fy_token_list *fytl, struct fy_token *fyt)
{
- int i;
+ struct fy_token_comment *tk;
if (!fyt)
return;
fy_input_unref(fyt->handle.fyi);
fyt->handle.fyi = NULL;
- /* release comment references */
- if (fyt->comment) {
- for (i = 0; i < fycp_max; i++)
- fy_input_unref(fyt->comment[i].fyi);
- free(fyt->comment);
- fyt->comment = NULL;
+ /* release the token comments */
+ while ((tk = fyt->token_comment) != NULL) {
+ fyt->token_comment = tk->next;
+ fy_input_unref(tk->handle.fyi);
+ fy_atom_reset(&tk->handle);
+ if (tk->comment)
+ free(tk->comment);
+ free(tk);
+ }
+
+ if (fyt->comments) {
+ free(fyt->comments);
+ fyt->comments = NULL;
}
switch (fyt->type) {
return fya->fyi_generation != fya->fyi->generation;
}
-static int fy_tag_token_format_internal(const struct fy_token *fyt, void *out, size_t *outszp)
+#define O_CPY(_src, _len) \
+ do { \
+ size_t _l = (_len); \
+ if (o && _l) { \
+ size_t _cl = _l; \
+ if (_cl > (size_t)(oe - o)) \
+ _cl = (size_t)(oe - o); \
+ memcpy(o, (_src), _cl); \
+ o += _cl; \
+ } \
+ len += _l; \
+ } while(0)
+
+static size_t fy_tag_token_format_internal(const struct fy_token *fyt, void *out, size_t *outszp)
{
char *o = NULL, *oe = NULL;
size_t outsz;
const char *handle, *suffix;
- size_t handle_size, suffix_size;
- int len, code_length, rlen;
+ size_t len, rlen, handle_size, suffix_size;
+ int code_length;
uint8_t code[4];
const char *t, *s, *e;
if (out) {
outsz = *outszp;
o = out;
- oe = out + outsz;
+ oe = (char *)out + outsz;
}
if (!fyt->tag.fyt_td)
- return -1;
+ return 0;
handle = fy_tag_directive_token_prefix(fyt->tag.fyt_td, &handle_size);
if (!handle)
- return -1;
+ return 0;
suffix = fy_atom_data(&fyt->handle) + fyt->tag.skip + fyt->tag.handle_length;
suffix_size = fyt->tag.suffix_length;
-#define O_CPY(_src, _len) \
- do { \
- int _l = (_len); \
- if (o && _l) { \
- int _cl = _l; \
- if (_cl > (oe - o)) \
- _cl = oe - o; \
- memcpy(o, (_src), _cl); \
- o += _cl; \
- } \
- len += _l; \
- } while(0)
-
len = 0;
O_CPY(handle, handle_size);
while (s < e) {
/* find next escape */
t = memchr(s, '%', e - s);
- rlen = (t ? t : e) - s;
+ rlen = (size_t)((t ? t : e) - s);
O_CPY(s, rlen);
/* end of string */
s = t;
}
-#undef O_CPY
return len;
-
}
-int fy_tag_token_format_text_length(const struct fy_token *fyt)
+size_t fy_tag_token_format_text_length(const struct fy_token *fyt)
{
return fy_tag_token_format_internal(fyt, NULL, NULL);
}
const char *fy_tag_token_format_text(const struct fy_token *fyt, char *buf, size_t maxsz)
{
+ if (maxsz > 0)
+ buf[0] = '\0';
fy_tag_token_format_internal(fyt, buf, &maxsz);
return buf;
}
-static int fy_tag_directive_token_format_internal(const struct fy_token *fyt,
+static size_t fy_tag_directive_token_format_internal(const struct fy_token *fyt,
void *out, size_t *outszp)
{
char *o = NULL, *oe = NULL;
size_t outsz;
- int len;
+ size_t len;
const char *handle, *prefix;
size_t handle_size, prefix_size;
if (out) {
outsz = *outszp;
o = out;
- oe = out + outsz;
+ oe = (char *)out + outsz;
}
-#define O_CPY(_src, _len) \
- do { \
- int _l = (_len); \
- if (o && _l) { \
- int _cl = _l; \
- if (_cl > (oe - o)) \
- _cl = oe - o; \
- memcpy(o, (_src), _cl); \
- o += _cl; \
- } \
- len += _l; \
- } while(0)
-
len = 0;
handle = fy_atom_data(&fyt->handle);
if (!handle_size)
O_CPY(">", 1);
-#undef O_CPY
return len;
-
}
+#undef O_CPY
-int fy_tag_directive_token_format_text_length(const struct fy_token *fyt)
+size_t fy_tag_directive_token_format_text_length(const struct fy_token *fyt)
{
return fy_tag_directive_token_format_internal(fyt, NULL, NULL);
}
if (!fyt)
goto err_out;
fyt->type = type;
+ fyt->handle.fyi = NULL;
handle = va_arg(ap, struct fy_atom *);
if (handle)
fyt->tag_directive.handle0 = NULL;
break;
case FYTT_SCALAR:
- fyt->scalar.style = va_arg(ap, enum fy_scalar_style);
- if (fyt->scalar.style != FYSS_ANY && (unsigned int)fyt->scalar.style >= FYSS_MAX)
- goto err_out;
fyt->scalar.path_key = NULL;
fyt->scalar.path_key_len = 0;
fyt->scalar.path_key_storage = NULL;
fyt->scalar.is_null = false; /* by default the scalar is not NULL */
+ fyt->scalar.style = va_arg(ap, enum fy_scalar_style);
+ if (fyt->scalar.style != FYSS_ANY && (unsigned int)fyt->scalar.style >= FYSS_MAX)
+ goto err_out;
break;
case FYTT_TAG:
fyt->tag.skip = va_arg(ap, unsigned int);
return fyt;
}
-int fy_token_format_text_length(struct fy_token *fyt)
+size_t fy_token_format_text_length(struct fy_token *fyt)
{
- int length;
+ size_t length;
if (!fyt)
return 0;
}
length = fy_atom_format_text_length(&fyt->handle);
-
return length;
}
return str;
}
-int fy_token_format_utf8_length(struct fy_token *fyt)
+size_t fy_token_format_utf8_length(struct fy_token *fyt)
{
const char *str;
size_t len;
return fy_atom_format_utf8_length(&fyt->handle);
}
-
struct fy_atom *fy_token_atom(struct fy_token *fyt)
{
return fyt ? &fyt->handle : NULL;
flags |= FYTTAF_DIRECT_OUTPUT;
- maxcol = fyt->handle.storage_hint;
+ maxcol = (int)fyt->handle.storage_hint;
maxspan = maxcol - 1;
flags |=
FYTTAF_DIRECT_OUTPUT |
text0[handle_len + suffix_len] = '\0';
fyt->tag.short0 = text0;
- fyt->tag.short_length = handle_len + suffix_len;
+ fyt->tag.short_length = (unsigned int)(handle_len + suffix_len);
*lenp = fyt->tag.short_length;
static void fy_token_prepare_text(struct fy_token *fyt)
{
- int ret;
+ size_t ret;
assert(fyt);
ret = fy_token_format_text_length(fyt);
/* no text on this token? */
- if (ret == -1) {
+ if (ret == 0) {
fyt->text_len = 0;
fyt->text = fyt->text0 = strdup("");
return;
cos_lastnlhashspc,
};
-const char *fy_token_get_comment(struct fy_token *fyt, char *buf, size_t maxsz,
- enum fy_comment_placement which)
+const char *
+fy_token_get_comment(struct fy_token *fyt, enum fy_comment_placement which)
{
+ struct fy_token_comment *tk;
struct fy_atom *handle;
struct fy_atom_iter iter;
const struct fy_iter_chunk *ic;
char *s, *e;
const char *ss, *ee;
- int c, w, ret;
+ int c, w, ret, pass;
+ size_t size;
enum comment_out_state state;
bool output;
- if (!buf || maxsz == 0 || (unsigned int)which >= fycp_max)
+ if (!fyt || (unsigned int)which >= fycp_max)
return NULL;
- /* return empty? */
- handle = fy_token_comment_handle(fyt, which, false);
- if (!handle || !fy_atom_is_set(handle))
+ for (tk = fyt->token_comment; tk; tk = tk->next) {
+ if (tk->placement == which && fy_atom_is_set(&tk->handle))
+ break;
+ }
+
+ /* not found, we're done */
+ if (!tk)
return NULL;
- /* start expecting # */
- state = cos_lastnl;
+ /* found and already generated */
+ if (tk->comment)
+ return tk->comment;
- s = buf;
- e = s + maxsz;
- fy_atom_iter_start(handle, &iter);
- ic = NULL;
- while ((ic = fy_atom_iter_chunk_next(&iter, ic, &ret)) != NULL) {
- ss = ic->str;
- ee = ss + ic->len;
+ handle = &tk->handle;
- while ((c = fy_utf8_get(ss, ee - ss, &w)) > 0) {
+ s = e = NULL;
+ size = 0;
+ for (pass = 0; pass < 2; pass++) {
- output = true;
- switch (state) {
- case cos_normal:
- if (fy_is_lb_m(c, handle->lb_mode))
- state = cos_lastnl;
- break;
+ if (pass) {
+ tk->comment = malloc(size + 1);
+ if (!tk->comment)
+ return NULL;
+ s = tk->comment;
+ e = s + size + 1;
+ }
- case cos_lastnl:
- if (c == '#') {
- state = cos_lastnlhash;
- output = false;
+ /* start expecting # */
+ state = cos_lastnl;
+ fy_atom_iter_start(handle, &iter);
+ ic = NULL;
+ while ((ic = fy_atom_iter_chunk_next(&iter, ic, &ret)) != NULL) {
+ ss = ic->str;
+ ee = ss + ic->len;
+
+ while ((c = fy_utf8_get(ss, ee - ss, &w)) > 0) {
+
+ output = true;
+ switch (state) {
+ case cos_normal:
+ if (fy_is_lb_m(c, handle->lb_mode))
+ state = cos_lastnl;
+ break;
+
+ case cos_lastnl:
+ if (c == '#') {
+ state = cos_lastnlhash;
+ output = false;
+ break;
+ }
+ state = cos_normal;
+ break;
+
+ case cos_lastnlhash:
+ if (c == ' ') {
+ state = cos_lastnlhashspc;
+ output = false;
+ break;
+ }
+ if (fy_is_lb_m(c, handle->lb_mode)) {
+ state = cos_lastnl;
+ output = true;
+ break;
+ }
+ state = cos_normal;
break;
- }
- state = cos_normal;
- break;
- case cos_lastnlhash:
- if (c == ' ') {
- state = cos_lastnlhashspc;
- output = false;
+ case cos_lastnlhashspc:
+ state = cos_normal;
break;
}
- state = cos_normal;
- break;
- case cos_lastnlhashspc:
- state = cos_normal;
- break;
- }
+ if (output) {
+ if (s) {
+ s = fy_utf8_put(s, (size_t)(e - s), c);
+ if (!s)
+ return NULL;
+ }
+ size += w;
+ }
- if (output) {
- s = fy_utf8_put(s, (size_t)(e - s), c);
- if (!s)
- return NULL;
+ ss += w;
}
-
- ss += w;
}
+ fy_atom_iter_finish(&iter);
}
- fy_atom_iter_finish(&iter);
- if (ret != 0 || s >= e)
- return NULL;
+ assert(s);
+ assert(s < e);
*s = '\0';
- return buf;
+ return tk->comment;
+}
+
+const char *
+fy_token_get_comments(struct fy_token *fyt)
+{
+ enum fy_comment_placement placement;
+ const char *str;
+ char *accum, *new_accum;
+ size_t size, accum_size, new_accum_size;
+ bool has_nl;
+
+ if (!fyt)
+ return NULL;
+
+ /* quick exit if no comments */
+ if (!fyt->token_comment)
+ return NULL;
+
+ /* already have it generated? */
+ if (fyt->comments)
+ return fyt->comments;
+
+ str = NULL;
+ accum = NULL;
+ accum_size = 0;
+ for (placement = fycp_top; placement < fycp_max; placement++) {
+
+ str = fy_token_get_comment(fyt, placement);
+ if (!str)
+ continue;
+
+ size = strlen(str);
+ has_nl = size > 0 && str[size-1] == '\n';
+ new_accum_size = accum_size + size + !has_nl + 1;
+ new_accum = realloc(accum, new_accum_size);
+ if (!new_accum)
+ goto err_out;
+ accum = new_accum;
+ memcpy(accum + accum_size, str, size);
+ accum_size += size;
+ if (!has_nl)
+ accum[accum_size++] = '\n';
+ accum[accum_size] = '\0';
+ }
+ return fyt->comments = accum;
+
+err_out:
+ if (accum)
+ free(accum);
+ return NULL;
+}
+
+int
+fy_token_set_comment(struct fy_token *fyt, enum fy_comment_placement which,
+ const char *text, size_t len)
+{
+ struct fy_token_comment *tk, *tk_prev;
+ struct fy_input *fyi = NULL;
+ char *data = NULL;
+ const char *s, *e;
+ char utf8buf[FY_UTF8_MAX_WIDTH];
+ int c, lastc, w;
+ size_t sz;
+ struct fy_atom *handle;
+ struct fy_memstream *fyms = NULL;
+ FILE *fp;
+
+ if (!fyt || (unsigned int)which >= fycp_max)
+ return -1;
+
+ tk_prev = NULL;
+ for (tk = fyt->token_comment; tk; tk = tk->next) {
+ if (tk->placement == which)
+ break;
+ tk_prev = tk;
+ }
+
+ /* removal of comment */
+ if (!text && tk) {
+ if (!tk_prev)
+ fyt->token_comment = tk->next;
+ else
+ tk_prev = tk->next;
+
+ fy_input_unref(tk->handle.fyi);
+ fy_atom_reset(&tk->handle);
+ if (tk->comment)
+ free(tk->comment);
+ free(tk);
+ return 0;
+ }
+
+ if (len == FY_NT)
+ len = strlen(text);
+
+ data = NULL;
+
+ fyms = fy_memstream_open(&fp);
+ if (!fyms)
+ goto err_out;
+
+ s = text;
+ e = text + len;
+ lastc = -1;
+ fputs("# ", fp);
+ while ((c = fy_utf8_get(s, e - s, &w)) > 0) {
+ s += w;
+ if (lastc == '\n')
+ fputs("\n# ", fp);
+ if (fy_token_is_lb(fyt, c)) {
+ c = '\n';
+ } else {
+ assert((size_t)w <= sizeof(utf8buf));
+ fy_utf8_put_unchecked(utf8buf, c);
+ fwrite(utf8buf, 1, w, fp);
+ }
+ lastc = c;
+ }
+
+ data = fy_memstream_close(fyms, &sz);
+ fyms = NULL;
+
+ len = sz;
+
+ handle = tk ? &tk->handle : fy_token_comment_handle(fyt, which, true);
+ if (!handle)
+ goto err_out;
+
+ fy_input_unref(handle->fyi);
+ fy_atom_reset(handle);
+
+ fyi = fy_input_from_malloc_data(data, len, handle, true);
+ if (!fyi)
+ goto err_out;
+
+ return 0;
+
+err_out:
+ if (fyms) {
+ data = fy_memstream_close(fyms, &sz);
+ fyms = NULL;
+ }
+ fy_input_unref(fyi);
+ if (data)
+ free(data);
+ return -1;
}
const char *fy_token_get_scalar_path_key(struct fy_token *fyt, size_t *lenp)
case '\v':
fy_emit_accum_utf8_put(&ea, 'v');
break;
- case '\e':
+ case '\x1b':
fy_emit_accum_utf8_put(&ea, 'e');
break;
case 0x85:
out:
text = fy_token_get_text(fyt, &length);
- wlen = length > 8 ? 8 : length;
+ wlen = length > 8 ? 8 : (int)length;
rc = asprintf(&buf, "%s:%.*s%s", typetxt, wlen, text, wlen < (int)length ? "..." : "");
assert(rc != -1);
struct fy_atom *fy_token_comment_handle(struct fy_token *fyt, enum fy_comment_placement placement, bool alloc)
{
- struct fy_atom *handle;
- size_t size;
+ struct fy_token_comment *tk;
if (!fyt || (unsigned int)placement >= fycp_max)
return NULL;
- if (!fyt->comment) {
- if (!alloc)
- return NULL;
-
- size = sizeof(*fyt->comment) * fycp_max;
- fyt->comment = malloc(size);
- if (!fyt->comment)
- return NULL;
- memset(fyt->comment, 0, size);
+ for (tk = fyt->token_comment; tk; tk = tk->next) {
+ if (tk->placement == placement)
+ return &tk->handle;
}
- handle = &fyt->comment[placement];
- return handle;
+ if (!alloc)
+ return NULL;
+
+ tk = malloc(sizeof(*tk));
+ if (!tk)
+ return NULL;
+ memset(tk, 0, sizeof(*tk));
+ tk->placement = placement;
+
+ /* simple list add */
+ tk->next = fyt->token_comment;
+ fyt->token_comment = tk;
+
+ return &tk->handle;
}
bool fy_token_has_any_comment(struct fy_token *fyt)
{
- struct fy_atom *handle;
- enum fy_comment_placement placement;
+ struct fy_token_comment *tk;
- if (!fyt || !fyt->comment)
+ if (!fyt)
return false;
- for (placement = fycp_top; placement <= fycp_bottom; placement++) {
- handle = &fyt->comment[placement];
- if (fy_atom_is_set(handle))
+ for (tk = fyt->token_comment; tk; tk = tk->next) {
+ if (fy_atom_is_set(&tk->handle))
return true;
}
return false;
int maxcol;
};
+struct fy_token_comment {
+ struct fy_token_comment *next;
+ enum fy_comment_placement placement;
+ struct fy_atom handle;
+ char *comment;
+};
+
FY_TYPE_FWD_DECL_LIST(token);
struct fy_token {
struct list_head node;
const char *text;
char *text0; /* this is allocated */
struct fy_atom handle;
- struct fy_atom *comment; /* only when enabled */
+ struct fy_token_comment *token_comment;
+ char *comments; /* this is allocated */
union {
struct {
unsigned int tag_length; /* from start */
fyt->text = NULL;
fyt->text0 = NULL;
fyt->handle.fyi = NULL;
- fyt->comment = NULL;
+ fyt->token_comment = NULL;
+ fyt->comments = NULL;
return fyt;
}
static inline FY_ALWAYS_INLINE void
fy_token_clean(struct fy_token *fyt)
{
- return fy_token_clean_rl(NULL, fyt);
+ fy_token_clean_rl(NULL, fyt);
}
static inline FY_ALWAYS_INLINE void
fy_token_free(struct fy_token *fyt)
{
- return fy_token_free_rl(NULL, fyt);
+ fy_token_free_rl(NULL, fyt);
}
static inline FY_ALWAYS_INLINE struct fy_token *
static inline FY_ALWAYS_INLINE void
fy_token_unref(struct fy_token *fyt)
{
- return fy_token_unref_rl(NULL, fyt);
+ fy_token_unref_rl(NULL, fyt);
}
static inline void
fy_token_list_unref_all(struct fy_token_list *fytl_tofree)
{
- return fy_token_list_unref_all_rl(NULL, fytl_tofree);
+ fy_token_list_unref_all_rl(NULL, fytl_tofree);
}
/* recycling aware */
return fyt;
}
-int fy_tag_token_format_text_length(const struct fy_token *fyt);
+size_t fy_tag_token_format_text_length(const struct fy_token *fyt);
const char *fy_tag_token_format_text(const struct fy_token *fyt, char *buf, size_t maxsz);
-int fy_token_format_utf8_length(struct fy_token *fyt);
+size_t fy_token_format_utf8_length(struct fy_token *fyt);
-int fy_token_format_text_length(struct fy_token *fyt);
+size_t fy_token_format_text_length(struct fy_token *fyt);
const char *fy_token_format_text(struct fy_token *fyt, char *buf, size_t maxsz);
/* non-parser token methods */
/* must be freed */
char *fy_token_debug_text(struct fy_token *fyt);
+#ifdef _MSC_VER
+/* MSVC version using thread-local buffer */
+#define FY_TOKEN_DEBUG_TEXT_A_BUFSZ 4096
+static __declspec(thread) char fy_token_debug_text_a_buf[FY_TOKEN_DEBUG_TEXT_A_BUFSZ];
+static __inline const char *fy_token_debug_text_a_impl(struct fy_token *fyt)
+{
+ char *buf = fy_token_debug_text(fyt);
+ if (!buf) return "";
+ strncpy(fy_token_debug_text_a_buf, buf, FY_TOKEN_DEBUG_TEXT_A_BUFSZ - 1);
+ fy_token_debug_text_a_buf[FY_TOKEN_DEBUG_TEXT_A_BUFSZ - 1] = '\0';
+ free(buf);
+ return fy_token_debug_text_a_buf;
+}
+#define fy_token_debug_text_a(_fyt) fy_token_debug_text_a_impl(_fyt)
+#else
#define fy_token_debug_text_a(_fyt) \
({ \
struct fy_token *__fyt = (_fyt); \
} \
_rbuf; \
})
+#endif
int fy_token_memcmp(struct fy_token *fyt, const void *ptr, size_t len);
int fy_token_strcmp(struct fy_token *fyt, const char *str);
#include <stdio.h>
#include <string.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <errno.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
-#include <unistd.h>
#include <math.h>
#include <limits.h>
#undef DEBUG_EXPR
// #define DEBUG_EXPR
+/* debugging for when expressions go crazy */
+#ifdef DEBUG_EXPR
+struct fy_walk_result *
+_fy_path_exec_walk_result_create(struct fy_path_exec *fypx,
+ const char *file, int line, const char *func,
+ enum fy_walk_result_type type, ...);
+#define fy_path_exec_walk_result_create(_fypx, _type, ...) \
+ _fy_path_exec_walk_result_create((_fypx), \
+ __FILE__, __LINE__, __func__, (_type) __VA_OPT__(,) __VA_ARGS__)
+
+void
+_fy_walk_result_free(struct fy_walk_result *fwr, const char *file, int line, const char *func);
+#define fy_walk_result_free(_fwr) _fy_walk_result_free((_fwr), __FILE__, __LINE__, __func__)
+
+void
+_fy_walk_result_clean(struct fy_walk_result *fwr, const char *file, int line, const char *func);
+#define fy_walk_result_clean(_fwr) _fy_walk_result_clean((_fwr), __FILE__, __LINE__, __func__)
+
+struct fy_walk_result *
+_fy_walk_result_clone(struct fy_walk_result *fwr, const char *file, int line, const char *func);
+#define fy_walk_result_clone(_fwr) _fy_walk_result_clone((_fwr), __FILE__, __LINE__, __func__)
+
+struct fy_walk_result *
+_fy_walk_result_clone_deep(struct fy_walk_result *fwr, const char *file, int line, const char *func);
+#define fy_walk_result_clone_deep(_fwr) _fy_walk_result_clone((_fwr), __FILE__, __LINE__, __func__)
+
+#endif
+
const char *fy_walk_result_type_txt[FWRT_COUNT] = {
[fwrt_none] = "none",
[fwrt_node_ref] = "node-ref",
[fwrt_refs] = "refs",
};
+
+static struct fy_node *fy_node_alias_resolve_by_ypath_internal(struct fy_node *fyn, bool *errorp);
+
void fy_walk_result_dump(struct fy_walk_result *fwr, struct fy_diag *diag, enum fy_error_type errlevel, int level,
const char *fmt, ...);
if (fmt) {
banner = NULL;
rc = vasprintf(&banner, fmt, ap);
- assert(rc != -1);
- assert(banner);
+ if (rc == -1 || !banner)
+ goto err_out;
fy_diag_diag(diag, errlevel, "%-*s%s", level*2, "", banner);
free(banner);
+ banner = NULL;
}
if (!fwr)
goto out;
break;
case fwrt_node_ref:
texta = fy_node_get_path(fwr->fyn);
- assert(texta);
+ if (!texta)
+ goto err_out;
text = texta;
break;
case fwrt_number:
break;
case fwrt_doc:
texta = fy_emit_document_to_string(fwr->fyd, FYECF_WIDTH_INF | FYECF_INDENT_DEFAULT | FYECF_MODE_FLOW_ONELINE);
- assert(texta);
+ if (!texta)
+ goto err_out;
text = texta;
break;
case fwrt_refs:
if (texta)
free(texta);
+ texta = NULL;
if (fwr->type == fwrt_refs) {
for (fwr2 = fy_walk_result_list_head(&fwr->refs); fwr2; fwr2 = fy_walk_result_next(&fwr->refs, fwr2))
}
out:
diag->on_error = save_on_error;
+ return;
+err_out:
+ diag->on_error = true;
+ return;
}
void fy_walk_result_dump(struct fy_walk_result *fwr, struct fy_diag *diag, enum fy_error_type errlevel, int level,
return NULL;
}
+#ifndef DEBUG_EXPR
struct fy_walk_result *fy_walk_result_clone(struct fy_walk_result *fwr)
{
struct fy_walk_result_list *fwrl;
return fy_walk_result_clone_rl(fwrl, fwr, true);
}
+#else
+
+struct fy_walk_result *
+_fy_walk_result_clone(struct fy_walk_result *fwr, const char *file, int line, const char *func)
+{
+ struct fy_walk_result_list *fwrl;
+ struct fy_walk_result *fwrn;
+
+ if (!fwr)
+ return NULL;
+
+ fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
+ fwrn = fy_walk_result_clone_rl(fwrl, fwr, false);
+
+ fprintf(stderr, "%s:%4d @%-48s %-32s fwr=%p (fypx=%p refs=%u)\n",
+ file, line, func, __func__, fwrn, fwrn->fypx, fwrn->fypx ? fwrn->fypx->refs : 0);
+
+ return fwrn;
+}
+
+struct fy_walk_result *
+_fy_walk_result_clone_deep(struct fy_walk_result *fwr, const char *file, int line, const char *func)
+{
+ struct fy_walk_result_list *fwrl;
+ struct fy_walk_result *fwrn;
+
+ if (!fwr)
+ return NULL;
+
+ fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
+ fwrn = fy_walk_result_clone_rl(fwrl, fwr, true);
+
+ fprintf(stderr, "%s:%4d @%-48s %-32s fwr=%p (fypx=%p refs=%u)\n",
+ file, line, func, __func__, fwrn, fwrn->fypx, fwrn->fypx ? fwrn->fypx->refs : 0);
+
+ return fwrn;
+}
+#endif
+
void fy_walk_result_clean_rl(struct fy_walk_result_list *fwrl, struct fy_walk_result *fwr)
{
struct fy_walk_result *fwrn;
}
fwr->type = fwrt_none;
+ fwr->fypx = NULL;
memset(&fwr->_clean, 0, sizeof(fwr->_clean));
}
+#ifndef DEBUG_EXPR
void fy_walk_result_clean(struct fy_walk_result *fwr)
{
struct fy_walk_result_list *fwrl;
fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
fy_walk_result_clean_rl(fwrl, fwr);
}
+#else
+void _fy_walk_result_clean(struct fy_walk_result *fwr,
+ const char *file, int line, const char *func)
+{
+ struct fy_walk_result_list *fwrl;
+
+ if (!fwr)
+ return;
+
+ fprintf(stderr, "%s:%4d @%-48s %-32s fwr=%p (fypx=%p refs=%u)\n",
+ file, line, func, __func__, fwr, fwr->fypx, fwr->fypx ? fwr->fypx->refs : 0);
+
+ fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
+ fy_walk_result_clean_rl(fwrl, fwr);
+
+}
+#endif
void fy_walk_result_free_rl(struct fy_walk_result_list *fwrl, struct fy_walk_result *fwr)
{
fy_walk_result_clean_rl(fwrl, fwr);
+#ifndef DEBUG_EXPR
if (fwrl)
fy_walk_result_list_push(fwrl, fwr);
else
+#endif
free(fwr);
fy_path_exec_unref(fypx); /* NULL is OK */
}
+#ifndef DEBUG_EXPR
void fy_walk_result_free(struct fy_walk_result *fwr)
{
struct fy_walk_result_list *fwrl;
fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
fy_walk_result_free_rl(fwrl, fwr);
}
+#else
+void _fy_walk_result_free(struct fy_walk_result *fwr, const char *file, int line, const char *func)
+{
+ struct fy_walk_result_list *fwrl;
+
+ if (!fwr)
+ return;
+
+ fprintf(stderr, "%s:%4d @%-48s %-32s fwr=%p (fypx=%p refs=%u)\n",
+ file, line, func, __func__, fwr, fwr->fypx, fwr->fypx ? fwr->fypx->refs : 0);
+
+ fwrl = fy_path_exec_walk_result_rl(fwr->fypx);
+ fy_walk_result_free_rl(fwrl, fwr);
+}
+#endif
void fy_walk_result_list_free_rl(struct fy_walk_result_list *fwrl, struct fy_walk_result_list *results)
{
return NULL;
fwrf = fy_walk_result_create_rl(fwrl, fwrt_refs);
- assert(fwrf);
+ if (!fwrf)
+ goto err_out;
fy_walk_result_flatten_internal(fwr, fwrf);
fy_walk_result_free_rl(fwrl, fwr);
return fwrf;
+
+err_out:
+ return NULL;
}
struct fy_walk_result *
{
struct fy_path_expr *expr = NULL;
+#ifndef DEBUG_EXPR
if (!fypp || fypp->suppress_recycling)
expr = fy_path_expr_alloc();
} else
expr = fy_path_expr_alloc();
}
+#else
+ expr = fy_path_expr_alloc();
+#endif
if (!expr)
return NULL;
void fy_path_expr_free_recycle(struct fy_path_parser *fypp, struct fy_path_expr *expr)
{
+#ifndef DEBUG_EXPR
struct fy_path_expr *exprn;
if (!fypp || fypp->suppress_recycling) {
expr->fyt = NULL;
}
fy_path_expr_list_add_tail(&fypp->expr_recycle, expr);
+#else
+ fy_path_expr_free(expr);
+#endif
}
void fy_expr_stack_setup(struct fy_expr_stack *stack)
unsigned int alloc;
size_t size;
- if (!stack || !expr)
- return -1;
-
- assert(stack->items);
- assert(stack->alloc > 0);
-
- assert(expr->fyt);
+ if (!stack || !expr || !stack->items || stack->alloc <= 0 || !expr->fyt)
+ goto err_out;
/* grow the stack if required */
if (stack->top >= stack->alloc) {
stack->items[stack->top++] = expr;
return 0;
+
+err_out:
+ return -1;
}
struct fy_path_expr *fy_expr_stack_peek_at(struct fy_expr_stack *stack, unsigned int pos)
fyr = &fypp->reader;
/* verify that the called context is correct */
- assert(fy_is_num(c) || (c == '-' && fy_is_num(fy_reader_peek_at(fyr, 1))));
+ if (!(fy_is_num(c) || (c == '-' && fy_is_num(fy_reader_peek_at(fyr, 1)))))
+ goto err_out;
i = 0;
indices[0] = indices[1] = -1;
fyr = &fypp->reader;
- assert(fy_is_first_alpha(c));
+ if (!fy_is_first_alpha(c))
+ goto err_out;
type = fytt_plain;
fyr = &fypp->reader;
- assert(c == '.');
+ if (c != '.')
+ goto err_out;
+
fy_reader_advance(fyr, c);
c = fy_reader_peek(fyr);
- assert(fy_is_first_alpha(c));
+ if (!fy_is_first_alpha(c))
+ goto err_out;
/* verify that the called context is correct */
i = 1;
fyr = &fypp->reader;
/* verify that the called context is correct */
- assert(fy_is_path_flow_key_start(c));
+ if (!fy_is_path_flow_key_start(c))
+ goto err_out;
fy_reader_fill_atom_start(fyr, &handle);
fyr = &fypp->reader;
/* verify that the called context is correct */
- assert(fy_is_path_flow_scalar_start(c));
+ if (!fy_is_path_flow_scalar_start(c))
+ goto err_out;
is_single = c == '\'';
fyr = &fypp->reader;
/* verify that the called context is correct */
- assert(fy_is_num(c) || (c == '-' && fy_is_num(fy_reader_peek_at(fyr, 1))));
+ if (!(fy_is_num(c) || (c == '-' && fy_is_num(fy_reader_peek_at(fyr, 1)))))
+ goto err_out;
i = 0;
if (c == '-')
if (fy_is_num(c) || (c == '-' && fy_is_num(fy_reader_peek_at(fyr, 1))))
return fy_path_fetch_number(fypp, c);
-#if 0
- if (c == '.' && fy_is_first_alpha(fy_reader_peek_at(fyr, 1)))
- return fy_path_fetch_dot_method(fypp, c, FYTT_SE_METHOD);
-#endif
+ // if (c == '.' && fy_is_first_alpha(fy_reader_peek_at(fyr, 1)))
+ // return fy_path_fetch_dot_method(fypp, c, FYTT_SE_METHOD);
break;
}
const char *style = "";
const char *text;
size_t len;
- struct fy_node *fyn = NULL, *fyn2, *fyn_seq = NULL;
+ struct fy_node *fyn = NULL, *fyn2 = NULL, *fyn_seq = NULL;
int rc;
text = fy_token_get_text(expr->fyt, &len);
rc = fy_node_sequence_append(fyn_seq, fyn2);
if (rc)
goto err_out;
+ fyn2 = NULL;
}
if (expr->type != fpet_method) {
static inline FY_UNUSED void
dump_operand_stack(struct fy_path_parser *fypp)
{
- return fy_expr_stack_dump(fypp->cfg.diag, &fypp->operands);
+ fy_expr_stack_dump(fypp->cfg.diag, &fypp->operands);
}
static inline int
return NULL;
ms = fy_path_expr_start_mark(expr);
- assert(ms);
+ if (!ms)
+ goto err_out;
me = fy_path_expr_end_mark(expr);
- assert(me);
+ if (!me)
+ goto err_out;
memset(&handle, 0, sizeof(handle));
handle.start_mark = *ms;
handle.chomp = FYAC_CLIP;
return fy_token_create(FYTT_INPUT_MARKER, &handle);
+err_out:
+ return NULL;
}
struct fy_token *
return NULL;
ms = fy_path_expr_start_mark(exprl);
- assert(ms);
+ if (!ms)
+ goto err_out;
me = fy_path_expr_end_mark(exprr);
- assert(me);
+ if (!me)
+ goto err_out;
memset(&handle, 0, sizeof(handle));
handle.start_mark = *ms;
handle.chomp = FYAC_CLIP;
return fy_token_create(FYTT_INPUT_MARKER, &handle);
+err_out:
+ return NULL;
}
int
int ret;
optimize = false;
- assert(exprl || exprr);
+ if (!exprl && !exprr)
+ goto err_out;
fyr = &fypp->reader;
expr->type = type;
expr->fyt = NULL;
- if (exprl) {
- assert(exprl->fyt);
- ms = fy_token_start_mark(exprl->fyt);
- assert(ms);
- } else {
- ms = fy_token_start_mark(exprr->fyt);
- assert(ms);
- }
-
- if (exprr) {
- assert(exprr->fyt);
- me = fy_token_end_mark(exprr->fyt);
- assert(me);
- } else {
- me = fy_token_end_mark(exprl->fyt);
- assert(me);
- }
+ ms = fy_token_start_mark(exprl ? exprl->fyt : exprr->fyt);
+ if (!ms)
+ goto err_out;
- assert(ms && me);
+ me = fy_token_end_mark(exprr ? exprr->fyt : exprl->fyt);
+ if (!me)
+ goto err_out;
memset(&handle, 0, sizeof(handle));
handle.start_mark = *ms;
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs);
+ struct fy_walk_result **args, int nargs,
+ bool *errorp);
static struct fy_walk_result *
common_builtin_collection_exec(const struct fy_method *fym,
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs);
+ struct fy_walk_result **args, int nargs,
+ bool *errorp);
static struct fy_walk_result *
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs);
+ struct fy_walk_result **args, int nargs,
+ bool *errorp);
static struct fy_walk_result *
sum_exec(const struct fy_method *fym,
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs);
+ struct fy_walk_result **args, int nargs,
+ bool *errorp);
static const struct fy_method fy_methods[] = {
[fymi_test] = {
{
if (!fym || fym < fy_methods || fym >= &fy_methods[ARRAY_SIZE(fy_methods)])
return -1;
- return fym - fy_methods;
+ return (int)(fym - fy_methods);
}
static struct fy_walk_result *
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs)
+ struct fy_walk_result **args, int nargs,
+ bool *errorp)
{
enum fy_method_idx midx;
struct fy_walk_result *output = NULL;
struct fy_walk_result *fwr, *fwrn;
struct fy_node *fyn, *fynt;
+ bool error;
int i;
+ if (errorp)
+ *errorp = false;
+
if (!fypx || !input)
- goto out;
+ goto err_out;
i = fy_method_to_builtin_idx(fym);
if (i < 0)
- goto out;
+ goto err_out;
midx = (enum fy_method_idx)i;
switch (midx) {
case fymi_key:
case fymi_value:
if (!args || nargs != 1 || !args[0] || args[0]->type != fwrt_string)
- goto out;
+ goto err_out;
break;
case fymi_index:
if (!args || nargs != 1 || !args[0] || args[0]->type != fwrt_number)
- goto out;
+ goto err_out;
break;
case fymi_root:
case fymi_parent:
case fymi_this:
case fymi_null:
if (nargs != 0)
- goto out;
+ goto err_out;
break;
default:
- goto out;
+ goto err_out;
}
output = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(output);
+ if (!output)
+ goto err_out;
for (fwr = fy_walk_result_iter_start(input); fwr;
fwr = fy_walk_result_iter_next(input, fwr)) {
case fymi_null:
/* dereference alias */
if (fy_node_is_alias(fynt)) {
- // fprintf(stderr, "%s: %s calling fy_node_alias_resolve_by_ypath()\n", __func__, fy_node_get_path_alloca(fyn));
- fynt = fy_node_alias_resolve_by_ypath(fynt);
+ fynt = fy_node_alias_resolve_by_ypath_internal(fynt, &error);
+ if (error)
+ goto err_out;
}
break;
default:
continue;
fwrn = fy_path_exec_walk_result_create(fypx, fwrt_node_ref, fyn);
- assert(fwrn);
-
+ if (!fwrn)
+ goto err_out;
fy_walk_result_list_add_tail(&output->refs, fwrn);
}
output = NULL;
} else if (fy_walk_result_list_is_singular(&output->refs)) {
fwr = fy_walk_result_list_pop(&output->refs);
- assert(fwr);
+ if (!fwr)
+ goto err_out;
fy_walk_result_free(output);
output = fwr;
}
fy_walk_result_free(args[i]);
}
return output;
+err_out:
+ if (errorp)
+ *errorp = true;
+ fy_walk_result_free(output);
+ goto out;
}
static struct fy_walk_result *
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs)
+ struct fy_walk_result **args, int nargs,
+ bool *errorp)
{
enum fy_method_idx midx;
struct fy_walk_result *output = NULL;
struct fy_path_expr *expr_arg;
bool match, done;
int input_count, match_count;
+ bool error;
int i;
+ if (errorp)
+ *errorp = false;
+
if (!fypx || !input)
- goto out;
+ goto err_out;
i = fy_method_to_builtin_idx(fym);
if (i < 0)
- goto out;
+ goto err_out;
midx = (enum fy_method_idx)i;
switch (midx) {
case fymi_all:
case fymi_select:
if (!args || nargs != 1 || !args[0])
- goto out;
+ goto err_out;
break;
default:
- goto out;
+ goto err_out;
}
expr_arg = fy_path_expr_list_head(&expr->children);
- assert(expr_arg);
+ if (!expr_arg)
+ goto err_out;
/* only handle inputs of node and refs */
if (input->type != fwrt_node_ref && input->type != fwrt_refs)
- goto out;
+ goto err_out;
output = NULL;
switch (midx) {
case fymi_select:
output = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(output);
+ if (!output)
+ goto err_out;
break;
default:
break;
input_count++;
fwrt = fy_walk_result_clone(fwr);
- assert(fwrt);
+ if (!fwrt)
+ goto err_out;
- fwrn = fy_path_expr_execute(fypx, level + 1, expr_arg, fwrt, expr->type);
+ fwrn = fy_path_expr_execute(fypx, level + 1, expr_arg, fwrt, expr->type, &error);
+ fwrt = NULL;
+ if (error)
+ goto err_out;
match = fwrn != NULL;
if (match)
break;
if (match) {
fwrt = fy_walk_result_clone(fwr);
- assert(fwrt);
+ if (!fwrt)
+ goto err_out;
fy_walk_result_list_add_tail(&output->refs, fwrt);
}
break;
break;
}
- if (fwrn)
- fy_walk_result_free(fwrn);
+ fy_walk_result_free(fwrn);
+ fwrn = NULL;
}
switch (midx) {
output = NULL;
} else if (fy_walk_result_list_is_singular(&output->refs)) {
fwr = fy_walk_result_list_pop(&output->refs);
- assert(fwr);
+ if (!fwr)
+ goto err_out;
fy_walk_result_free(output);
output = fwr;
}
}
out:
- if (input)
- fy_walk_result_free(input);
+ fy_walk_result_free(input);
if (args) {
for (i = 0; i < nargs; i++)
fy_walk_result_free(args[i]);
}
return output;
+
+err_out:
+ if (errorp)
+ *errorp = true;
+ fy_walk_result_free(output);
+ output = NULL;
+ goto out;
}
static struct fy_walk_result *
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs)
+ struct fy_walk_result **args, int nargs,
+ bool *errorp)
{
int i;
struct fy_walk_result *output = NULL;
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs)
+ struct fy_walk_result **args, int nargs,
+ bool *errorp)
{
int i;
struct fy_walk_result *output = NULL;
fy_path_expr_order(exprm, exprt) < 0) {
exprt = fy_expr_stack_pop(&fypp->operands);
- assert(exprt);
+ if (!exprt)
+ goto err_out;
#ifdef DEBUG_EXPR
FYR_TOKEN_DIAG(fyr, exprt->fyt,
fyr = &fypp->reader;
expr = fy_expr_stack_pop(&fypp->operators);
- fyr_error_check(fyr, expr, err_out,
+ fyr_error_check(fyr, expr && expr->fyt, err_out,
"pop_operator() failed to find token operator to evaluate\n");
- assert(expr->fyt);
-
#ifdef DEBUG_EXPR
FYR_TOKEN_DIAG(fyr, expr->fyt,
FYDF_NOTICE, FYEM_PARSE, "poped operator expression");
expr->fyt = NULL;
} else {
- assert(exprr && exprl);
+ if (!(exprr && exprl))
+ goto err_out;
// fyr_notice(fyr, "CHAIN operator\n");
}
if (exprm && exprm->type == fpet_method) {
exprm = fy_expr_stack_pop(&fypp->operators);
- assert(exprm);
+ if (!exprm)
+ goto err_out;
return evaluate_method(fypp, exprm, exprl, exprr);
}
}
static struct fy_node *
-fy_path_expr_execute_single_result(struct fy_diag *diag, struct fy_path_expr *expr, struct fy_node *fyn)
+fy_path_expr_execute_single_result(struct fy_diag *diag, struct fy_path_expr *expr, struct fy_node *fyn, bool *errorp)
{
struct fy_token *fyt;
struct fy_anchor *fya;
const char *text;
size_t len;
+ bool error;
- assert(expr);
+ if (errorp)
+ *errorp = false;
+
+ if (!expr)
+ goto err_out;
switch (expr->type) {
case fpet_root:
case fpet_this:
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
return fyn;
case fpet_alias:
fyt = expr->fyt;
- assert(fyt);
- assert(fyt->type == FYTT_PE_ALIAS);
+ if (!fyt || fyt->type != FYTT_PE_ALIAS)
+ goto err_out;
text = fy_token_get_text(fyt, &len);
if (!text || len < 1)
- break;
+ goto err_out;
if (*text == '*') {
text++;
}
fya = fy_document_lookup_anchor(fyn->fyd, text, len);
if (!fya)
- break;
+ goto err_out;
+
return fya->fyn;
case fpet_seq_index:
fyt = expr->fyt;
- assert(fyt);
- assert(fyt->type == FYTT_PE_SEQ_INDEX);
+ if (!fyt || fyt->type != FYTT_PE_SEQ_INDEX)
+ goto err_out;
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
/* only on sequence */
case fpet_map_key:
fyt = expr->fyt;
- assert(fyt);
- assert(fyt->type == FYTT_PE_MAP_KEY);
+ if (!fyt || fyt->type != FYTT_PE_MAP_KEY)
+ goto err_out;
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
if (!fy_node_is_mapping(fyn))
case fpet_filter_collection:
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
if (!(fy_node_is_mapping(fyn) || fy_node_is_sequence(fyn)))
case fpet_filter_sequence:
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
if (!fy_node_is_sequence(fyn))
case fpet_filter_mapping:
if (fy_node_is_alias(fyn)) {
- // fprintf(stderr, "%s:%d %s calling fy_node_alias_resolve_by_ypath()\n", __func__, __LINE__, fy_node_get_path_alloca(fyn));
- fyn = fy_node_alias_resolve_by_ypath(fyn);
+ fyn = fy_node_alias_resolve_by_ypath_internal(fyn, &error);
+ if (error)
+ goto err_out;
}
if (!fy_node_is_mapping(fyn))
}
return NULL;
+
+err_out:
+ if (errorp)
+ *errorp = true;
+ return NULL;
}
static double
struct fy_walk_result *fy_walk_result_simplify(struct fy_walk_result *fwr)
{
struct fy_walk_result *fwr2;
-#if 0
- struct fy_walk_result *fwrf;
- bool recursive;
-#endif
/* no fwr */
if (!fwr)
/* single element, switch it out */
if (fy_walk_result_list_is_singular(&fwr->refs)) {
fwr2 = fy_walk_result_list_pop(&fwr->refs);
- assert(fwr2);
+ if (!fwr2)
+ goto err_out;
fy_walk_result_free(fwr);
fwr = fwr2;
}
return fwr;
-#if 0
- /* non recursive return immediately */
- if (fwr->type != fwrt_refs)
- return fwr;
-
- /* flatten if recursive */
- recursive = false;
- for (fwr2 = fy_walk_result_list_head(&fwr->refs); fwr2;
- fwr2 = fy_walk_result_next(&fwr->refs, fwr2)) {
-
- /* refs, recursive */
- if (fwr2->type == fwrt_refs) {
- recursive = true;
- break;
- }
- }
-
- if (!recursive)
- return fwr;
-
- fwrf = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(fwrf);
-
- fy_walk_result_flatten_internal(fwr, fwrf);
-
+err_out:
fy_walk_result_free(fwr);
- return fwrf;
-#endif
-
+ return NULL;
}
-int fy_walk_result_all_children_recursive_internal(struct fy_path_exec *fypx, struct fy_node *fyn, struct fy_walk_result *output)
+int fy_walk_result_all_children_recursive_internal(struct fy_path_exec *fypx, struct fy_node *fyn,
+ struct fy_walk_result *output)
{
struct fy_node *fyni;
struct fy_walk_result *fwr;
if (!fyn)
return 0;
- assert(output);
- assert(output->type == fwrt_refs);
+ if (!output || output->type != fwrt_refs)
+ goto err_out;
/* this node */
fwr = fy_path_exec_walk_result_create(fypx, fwrt_node_ref, fyn);
if (!fwr)
- return -1;
+ goto err_out;
fy_walk_result_list_add_tail(&output->refs, fwr);
+ fwr = NULL;
if (fy_node_is_scalar(fyn))
return 0;
while ((fyni = fy_node_collection_iterate(fyn, &prevp)) != NULL) {
ret = fy_walk_result_all_children_recursive_internal(fypx, fyni, output);
if (ret)
- return ret;
+ goto err_out;
}
return 0;
+err_out:
+ return -1;
}
bool
fy_walk_result_compare_simple(struct fy_path_exec *fypx, enum fy_path_expr_type type,
- struct fy_walk_result *fwrl, struct fy_walk_result *fwrr)
+ struct fy_walk_result *fwrl, struct fy_walk_result *fwrr,
+ bool *errorp)
{
struct fy_token *fyt;
struct fy_walk_result *fwrt;
const char *str;
- bool match;
+ bool match, ret, error;
+
+ if (errorp)
+ *errorp = false;
/* both NULL */
if (!fwrl && !fwrr) {
/* both are non NULL */
/* none should be multiple */
- assert(fwrl->type != fwrt_refs && fwrr->type != fwrt_refs);
+ if (fwrl->type == fwrt_refs || fwrr->type == fwrt_refs)
+ goto err_out;
/* both are the same type */
if (fwrl->type == fwrr->type) {
switch (fwrl->type) {
case fwrt_none:
- FY_IMPOSSIBLE_ABORT();
+ goto err_out;
case fwrt_node_ref:
switch (type) {
return true;
return !fy_node_compare(fwrl->fyn, fwrr->fyn);
default:
- break;
+ goto err_out;
}
break;
case fwrt_refs:
- FY_IMPOSSIBLE_ABORT();
+ goto err_out;
case fwrt_doc:
switch (type) {
match = !match;
return match;
default:
- break;
+ goto err_out;
}
break;
case fpet_gte:
return fwrl->number >= fwrr->number;
default:
- break;
+ goto err_out;
}
break;
case fpet_gte:
return strcmp(fwrl->string, fwrr->string) >= 0;
default:
- break;
+ goto err_out;
}
break;
}
type = fpet_lt;
break;
default:
- break;
+ goto err_out;
}
/* swap left with right */
- return fy_walk_result_compare_simple(fypx, type, fwrr, fwrl);
+ ret = fy_walk_result_compare_simple(fypx, type, fwrr, fwrl, &error);
+ if (error)
+ goto err_out;
+ return ret;
}
switch (fwrl->type) {
}
fyt = fy_node_get_scalar_token(fwrl->fyn);
- assert(fyt);
+ if (!fyt)
+ goto err_out;
str = fy_token_get_text0(fyt);
- assert(str);
+ if (!str)
+ goto err_out;
fwrt = NULL;
/* node ref against */
case fwrt_string:
/* create a new temporary walk result */
fwrt = fy_path_exec_walk_result_create(fypx, fwrt_string, str);
- assert(fwrt);
+ if (!fwrt)
+ goto err_out;
break;
/* create a new temporary walk result */
fwrt = fy_path_exec_walk_result_create(fypx, fwrt_number, strtod(str, NULL));
- assert(fwrt);
+ if (!fwrt)
+ goto err_out;
break;
default:
if (!fwrt)
return false;
- match = fy_walk_result_compare_simple(fypx, type, fwrt, fwrr);
+ match = fy_walk_result_compare_simple(fypx, type, fwrt, fwrr, &error);
+ if (error)
+ goto err_out;
/* free the temporary result */
fy_walk_result_free(fwrt);
+ fwrt = NULL;
return match;
}
return false;
+
+err_out:
+ if (errorp)
+ *errorp = true;
+ return false;
}
struct fy_walk_result *
fy_walk_result_arithmetic_simple(struct fy_path_exec *fypx,
struct fy_path_expr *expr,
struct fy_path_expr *exprl, struct fy_walk_result *fwrl,
- struct fy_path_expr *exprr, struct fy_walk_result *fwrr)
+ struct fy_path_expr *exprr, struct fy_walk_result *fwrr,
+ bool *errorp)
{
struct fy_diag *diag;
struct fy_walk_result *output = NULL;
char *str;
size_t len, len1, len2;
+ if (errorp)
+ *errorp = false;
+
if (!fwrl || !fwrr)
- goto out;
+ goto err_out;
diag = fypx->cfg.diag;
len2 = strlen(fwrr->string);
len = len1 + len2;
str = malloc(len + 1);
- assert(str);
+ if (!str)
+ goto err_out;
memcpy(str, fwrl->string, len1);
memcpy(str + len1, fwrr->string, len2);
str[len] = '\0';
fy_walk_result_free(fwrl);
fy_walk_result_free(fwrr);
return output;
+
+err_out:
+ fy_walk_result_free(output);
+ output = NULL;
+ if (errorp)
+ *errorp = true;
+ goto out;
}
struct fy_walk_result *
fy_walk_result_conditional_simple(struct fy_path_exec *fypx,
struct fy_path_expr *expr,
struct fy_path_expr *exprl, struct fy_walk_result *fwrl,
- struct fy_path_expr *exprr, struct fy_walk_result *fwrr)
+ struct fy_path_expr *exprr, struct fy_walk_result *fwrr,
+ bool *errorp)
{
- bool match;
+ bool match, error;
+
+ if (errorp)
+ *errorp = false;
+
+ match = fy_walk_result_compare_simple(fypx, expr->type, fwrl, fwrr, &error);
+ if (error)
+ goto err_out;
- match = fy_walk_result_compare_simple(fypx, expr->type, fwrl, fwrr);
+ /* path expr, return left hand side result if match */
+
+ fy_walk_result_free(fwrr);
+ fwrr = NULL;
if (!match) {
fy_walk_result_free(fwrl);
- fy_walk_result_free(fwrr);
- return NULL;
+ fwrl = NULL;
}
- /* path expr, return left hand side result */
- fy_walk_result_free(fwrr);
return fwrl;
+
+err_out:
+ fy_walk_result_free(fwrl);
+ fy_walk_result_free(fwrr);
+ if (errorp)
+ *errorp = true;
+ return NULL;
}
struct fy_walk_result *
fy_walk_result_lhs_rhs(struct fy_path_exec *fypx,
struct fy_path_expr *expr,
struct fy_path_expr *exprl, struct fy_walk_result *fwrl,
- struct fy_path_expr *exprr, struct fy_walk_result *fwrr)
+ struct fy_path_expr *exprr, struct fy_walk_result *fwrr,
+ bool *errorp)
{
- struct fy_walk_result *output = NULL, *fwr, *fwrrt, *fwrlt, *fwrlc, *fwrrc;
+ struct fy_walk_result *output = NULL, *fwr = NULL, *fwrrt = NULL, *fwrlt = NULL, *fwrlc = NULL, *fwrrc = NULL;
struct fy_walk_result *outputl = NULL, *outputr = NULL;
+ bool error;
- assert(expr);
- assert(exprl);
- assert(exprr);
+ if (errorp)
+ *errorp = false;
+
+ if (!expr || !exprl || !exprr)
+ goto err_out;
/* only supports those */
if (!fy_path_expr_type_is_conditional(expr->type) &&
}
output = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(output);
+ if (!output)
+ goto err_out;
for (fwrlt = fy_walk_result_iter_start(fwrl); fwrlt;
fwrlt = fy_walk_result_iter_next(fwrl, fwrlt)) {
if (fwrlt->type == fwrt_refs) {
fwrlc = fy_walk_result_clone(fwrlt);
- assert(fwrlc);
+ if (!fwrlc)
+ goto err_out;
fwrrc = fy_walk_result_clone(fwrr);
- assert(fwrrc);
+ if (!fwrrc)
+ goto err_out;
+
+ outputl = fy_walk_result_lhs_rhs(fypx, expr, exprl, fwrlc, exprr, fwrrc, &error);
+ fwrlc = NULL;
+ fwrrc = NULL;
+ if (error)
+ goto err_out;
- outputl = fy_walk_result_lhs_rhs(fypx, expr, exprl, fwrlc, exprr, fwrrc);
if (outputl)
fy_walk_result_list_add_tail(&output->refs, outputl);
- else
+ else {
fy_walk_result_free(outputl);
+ outputl = NULL;
+ }
continue;
}
if (fwrrt->type == fwrt_refs) {
fwrlc = fy_walk_result_clone(fwrlt);
- assert(fwrlc);
+ if (!fwrlc)
+ goto err_out;
fwrrc = fy_walk_result_clone(fwrrt);
- assert(fwrrc);
+ if (!fwrrc)
+ goto err_out;
+
+ outputr = fy_walk_result_lhs_rhs(fypx, expr, exprl, fwrlc, exprr, fwrrc, &error);
+ fwrlc = NULL;
+ fwrrc = NULL;
+ if (error)
+ goto err_out;
- outputr = fy_walk_result_lhs_rhs(fypx, expr, exprl, fwrlc, exprr, fwrrc);
if (outputr)
fy_walk_result_list_add_tail(&output->refs, outputr);
- else
+ else {
fy_walk_result_free(outputr);
+ outputr = NULL;
+ }
continue;
}
fwrlc = fy_walk_result_clone(fwrlt);
- assert(fwrlc);
+ if (!fwrlc)
+ goto err_out;
fwrrc = fy_walk_result_clone(fwrrt);
- assert(fwrrc);
+ if (!fwrrc)
+ goto err_out;
fwr = NULL;
-
- if (fy_path_expr_type_is_conditional(expr->type))
- fwr = fy_walk_result_conditional_simple(fypx, expr, exprl, fwrlc, exprr, fwrrc);
- else if (fy_path_expr_type_is_arithmetic(expr->type))
- fwr = fy_walk_result_arithmetic_simple(fypx, expr, exprl, fwrlc, exprr, fwrrc);
- else
+ if (fy_path_expr_type_is_conditional(expr->type)) {
+ fwr = fy_walk_result_conditional_simple(fypx, expr, exprl, fwrlc, exprr, fwrrc, &error);
+ fwrlc = NULL;
+ fwrrc = NULL;
+ if (error)
+ goto err_out;
+ } else if (fy_path_expr_type_is_arithmetic(expr->type)) {
+ fwr = fy_walk_result_arithmetic_simple(fypx, expr, exprl, fwrlc, exprr, fwrrc, &error);
+ fwrlc = NULL;
+ fwrrc = NULL;
+ if (error)
+ goto err_out;
+ } else
FY_IMPOSSIBLE_ABORT();
- fwrlc = NULL;
- fwrrc = NULL;
-
if (fwr)
fy_walk_result_list_add_tail(&output->refs, fwr);
}
}
out:
+ fy_walk_result_free(fwrlc);
+ fy_walk_result_free(fwrrc);
fy_walk_result_free(fwrl);
fy_walk_result_free(fwrr);
return fy_walk_result_simplify(output);
+err_out:
+ fy_walk_result_free(output);
+ output = NULL;
+ goto out;
}
struct fy_path_expr *
-fy_scalar_walk_result_to_expr(struct fy_path_exec *fypx, struct fy_walk_result *fwr, enum fy_path_expr_type ptype)
+fy_scalar_walk_result_to_expr(struct fy_path_exec *fypx, struct fy_walk_result *fwr,
+ enum fy_path_expr_type ptype, bool *errorp)
{
struct fy_input *fyit = NULL;
struct fy_path_expr *exprt = NULL;
char *buf;
int rc __FY_DEBUG_UNUSED__;
- exprt = NULL;
+ if (errorp)
+ *errorp = false;
if (!fwr)
- return NULL;
+ goto err_out;
collection_addressing = ptype == fpet_chain || ptype == fpet_multi;
switch (fwr->type) {
case fwrt_string:
fyit = fy_input_from_malloc_data(fwr->string, FY_NT, &handle, true);
- assert(fyit);
+ if (!fyit)
+ goto err_out;
fwr->string = NULL;
fy_walk_result_free(fwr);
fwr = NULL;
exprt = fy_path_expr_alloc();
- assert(exprt);
+ if (!exprt)
+ goto err_out;
if (collection_addressing) {
exprt->type = fpet_map_key;
exprt->fyt = fy_token_create(FYTT_PE_MAP_KEY, &handle, NULL);
- assert(exprt->fyt);
+ if (!exprt->fyt)
+ goto err_out;
} else {
exprt->type = fpet_scalar;
exprt->fyt = fy_token_create(FYTT_SCALAR, &handle, FYSS_PLAIN, NULL);
- assert(exprt->fyt);
+ if (!exprt->fyt)
+ goto err_out;
}
break;
case fwrt_number:
rc = asprintf(&buf, "%d", (int)fwr->number);
- assert(rc != -1);
+ if (rc == -1)
+ goto err_out;
fyit = fy_input_from_malloc_data(buf, FY_NT, &handle, true);
- assert(fyit);
+ if (!fyit)
+ goto err_out;
exprt = fy_path_expr_alloc();
- assert(exprt);
+ if (!exprt)
+ goto err_out;
if (collection_addressing) {
exprt->type = fpet_seq_index;
exprt->fyt = fy_token_create(FYTT_PE_SEQ_INDEX, &handle, (int)fwr->number);
- assert(exprt->fyt);
+ if (!exprt->fyt)
+ goto err_out;
} else {
exprt->type = fpet_scalar;
exprt->fyt = fy_token_create(FYTT_SCALAR, &handle, FYSS_PLAIN, NULL);
- assert(exprt->fyt);
+ if (!exprt->fyt)
+ goto err_out;
}
break;
break;
}
+out:
fy_walk_result_free(fwr);
fy_input_unref(fyit);
return exprt;
+err_out:
+ fy_path_expr_free(exprt);
+ exprt = NULL;
+ if (errorp)
+ *errorp = true;
+ goto out;
}
enum fy_walk_result_set_op {
struct fy_walk_result *fwr, *fwrrm, *fwrin;
struct fy_walk_result *output = NULL;
char *relpath = NULL;
- struct fy_node *fyn2, *fynt;
+ struct fy_node *fyn2 = NULL, *fynt;
int rc;
/* no input? return it */
return NULL;
}
- assert(input->type == fwrt_node_ref || input->type == fwrt_refs);
+ if (input->type != fwrt_node_ref && input->type != fwrt_refs)
+ goto err_out;
#ifdef DEBUG_EXPR
fy_walk_result_dump(input, fypx->cfg.diag, FYET_WARNING, 0, "set-op: input\n");
/* get the node at the relative path of the copy */
fyn2 = fy_node_by_path(fwr->fyn, relpath, FY_NT, FYNWF_DONT_FOLLOW);
- if (!fyn2)
+ if (!fyn2) {
+ fy_walk_result_free(fwr);
+ fwr = NULL;
goto err_out;
+ }
free(relpath);
relpath = NULL;
rc = fy_node_delete(fyn2);
if (rc)
goto err_out;
+ fyn2 = NULL;
+ fwr->fyn = NULL;
} else {
fynt = fyn2;
}
}
- if (output && fwr) {
+ if (output && fwr)
fy_walk_result_list_add_tail(&output->refs, fwr);
- }
+ else if (fwr)
+ fy_walk_result_free(fwr);
fwr = NULL;
}
}
+out:
/* get rid of input */
fy_walk_result_free(input);
return output;
err_out:
- fy_walk_result_free(input);
fy_walk_result_free(output);
+ output = NULL;
if (relpath)
free(relpath);
- return NULL;
+ goto out;
}
struct fy_walk_result *
fy_path_expr_execute(struct fy_path_exec *fypx, int level, struct fy_path_expr *expr,
- struct fy_walk_result *input, enum fy_path_expr_type ptype)
+ struct fy_walk_result *input, enum fy_path_expr_type ptype,
+ bool *errorp)
{
struct fy_diag *diag;
- struct fy_walk_result *fwr, *fwrn, *fwrt, *fwrtn;
- struct fy_walk_result *output = NULL, *input1, *output1, *input2, *output2;
+ struct fy_walk_result *fwr = NULL, *fwrn = NULL, *fwrt = NULL, *fwrtn = NULL;
+ struct fy_walk_result *output = NULL, *input1 = NULL, *output1 = NULL, *input2 = NULL, *output2 = NULL;
struct fy_path_expr *exprn, *exprl, *exprr;
struct fy_node *fyn, *fynn, *fyni;
struct fy_token *fyt;
unsigned int nargs;
struct fy_walk_result **fwr_args;
void *prevp;
+ bool error;
int rc __FY_DEBUG_UNUSED__;
/* error */
if (input && input->type == fwrt_refs && !fy_path_expr_type_handles_refs(expr->type)) {
output = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(output);
+ if (!output)
+ goto err_out;
while ((fwr = fy_walk_result_list_pop(&input->refs)) != NULL) {
- fwrn = fy_path_expr_execute(fypx, level + 1, expr, fwr, ptype);
+ fwrn = fy_path_expr_execute(fypx, level + 1, expr, fwr, ptype, &error);
+ fwr = NULL;
+ if (error)
+ goto err_out;
if (fwrn)
fy_walk_result_list_add_tail(&output->refs, fwrn);
}
if (input && input->type == fwrt_node_ref) {
- fynn = fy_path_expr_execute_single_result(diag, expr, input->fyn);
+ fynn = fy_path_expr_execute_single_result(diag, expr, input->fyn, &error);
+ if (error)
+ goto err_out;
if (!fynn)
goto out;
for (exprn = fy_path_expr_list_head(&expr->children); exprn;
exprn = fy_path_expr_next(&expr->children, exprn)) {
- output = fy_path_expr_execute(fypx, level + 1, exprn, output, expr->type);
+ output = fy_path_expr_execute(fypx, level + 1, exprn, output, expr->type, &error);
+ if (error)
+ goto err_out;
if (!output)
break;
}
/* allocate a refs output result */
output = fy_path_exec_walk_result_create(fypx, fwrt_refs);
- assert(output);
+ if (!output)
+ goto err_out;
/* iterate over each multi item */
for (exprn = fy_path_expr_list_head(&expr->children); exprn;
exprn = fy_path_expr_next(&expr->children, exprn)) {
input2 = fy_walk_result_clone(input);
- assert(input2);
+ if (!input2)
+ goto err_out;
- output2 = fy_path_expr_execute(fypx, level + 1, exprn, input2, expr->type);
+ output2 = fy_path_expr_execute(fypx, level + 1, exprn, input2, expr->type, &error);
+ input2 = NULL;
+ if (error)
+ goto err_out;
if (!output2)
continue;
fy_walk_result_list_add_tail(&output->refs, output2);
+ output2 = NULL;
}
fy_walk_result_free(input);
input = NULL;
prevp = NULL;
while ((fyni = fy_node_collection_iterate(fyn, &prevp)) != NULL) {
fwr = fy_path_exec_walk_result_create(fypx, fwrt_node_ref, fyni);
- assert(fwr);
-
+ if (!fwr)
+ goto err_out;
fy_walk_result_list_add_tail(&output->refs, fwr);
}
fy_walk_result_list_init(&output->refs);
rc = fy_walk_result_all_children_recursive_internal(fypx, fyn, output);
- assert(!rc);
-
+ if (rc)
+ goto err_out;
break;
case fpet_seq_slice:
goto out;
/* only valid for node ref on a sequence */
- if (input->type != fwrt_node_ref || !fy_node_is_sequence(input->fyn)) {
+ if (input->type != fwrt_node_ref || !fy_node_is_sequence(input->fyn))
break;
- }
fyn = input->fyn;
fyt = expr->fyt;
- assert(fyt);
- assert(fyt->type == FYTT_PE_SEQ_SLICE);
+ if (!fyt || fyt->type != FYTT_PE_SEQ_SLICE)
+ goto err_out;
start = fyt->seq_slice.start_index;
end = fyt->seq_slice.end_index;
continue;
fwr = fy_path_exec_walk_result_create(fypx, fwrt_node_ref, fynn);
- assert(fwr);
+ if (!fwr)
+ goto err_out;
fy_walk_result_list_add_tail(&output->refs, fwr);
}
case fpet_div:
exprl = fy_path_expr_lhs(expr);
- assert(exprl);
-
+ if (!exprl)
+ goto err_out;
exprr = fy_path_expr_rhs(expr);
- assert(exprr);
+ if (!exprr)
+ goto err_out;
if (input) {
input1 = fy_walk_result_clone(input);
- assert(input1);
+ if (!input1)
+ goto err_out;
input2 = input;
input = NULL;
}
/* execute LHS and RHS */
- output1 = fy_path_expr_execute(fypx, level + 1, exprl, input1, expr->type);
- output2 = fy_path_expr_execute(fypx, level + 1, exprr, input2, expr->type);
+ output1 = fy_path_expr_execute(fypx, level + 1, exprl, input1, expr->type, &error);
+ input1 = NULL;
+ if (error)
+ goto err_out;
- output = fy_walk_result_lhs_rhs(fypx, expr, exprl, output1, exprr, output2);
+ output2 = fy_path_expr_execute(fypx, level + 1, exprr, input2, expr->type, &error);
+ input2 = NULL;
+ if (error)
+ goto err_out;
+ output = fy_walk_result_lhs_rhs(fypx, expr, exprl, output1, exprr, output2, &error);
+ output1 = NULL;
+ output2 = NULL;
+ if (error)
+ goto err_out;
break;
case fpet_scalar:
/* duck typing! */
if (fy_token_is_number(expr->fyt)) {
output = fy_path_exec_walk_result_create(fypx, fwrt_number, token_number(expr->fyt));
- assert(output);
+ if (!output)
+ goto err_out;
} else {
output = fy_path_exec_walk_result_create(fypx, fwrt_string, fy_token_get_text0(expr->fyt));
- assert(output);
+ if (!output)
+ goto err_out;
}
fy_walk_result_free(input);
if (input) {
input1 = fy_walk_result_clone(input);
- assert(input1);
- } else {
+ if (!input1)
+ goto err_out;
+ } else
input1 = NULL;
- }
- output = fy_path_expr_execute(fypx, level + 1, exprn, input1, expr->type);
+ output = fy_path_expr_execute(fypx, level + 1, exprn, input1, expr->type, &error);
+ input1 = NULL;
+ if (error)
+ goto err_out;
+
if (output)
break;
}
if (input) {
input1 = fy_walk_result_clone(input);
- assert(input1);
- } else {
+ if (!input1)
+ goto err_out;
+ } else
input1 = NULL;
- }
- output1 = fy_path_expr_execute(fypx, level + 1, exprn, input1, expr->type);
+ output1 = fy_path_expr_execute(fypx, level + 1, exprn, input1, expr->type, &error);
+ input1 = NULL;
+ if (error)
+ goto err_out;
+
if (output1) {
fy_walk_result_free(output);
output = output1;
+ output1 = NULL;
} else
break;
}
if (fwrt->type == fwrt_refs)
continue;
- assert(fwrt != fwr);
+ if (fwrt == fwr)
+ goto err_out;
- match = fy_walk_result_compare_simple(fypx, fpet_eq, fwr, fwrt);
+ match = fy_walk_result_compare_simple(fypx, fpet_eq, fwr, fwrt, &error);
+ if (error)
+ goto err_out;
if (match) {
fy_walk_result_list_del(&input->refs, fwrt);
case fpet_scalar_expr:
exprl = fy_path_expr_list_head(&expr->children);
- if (!exprl) {
- fy_warning(diag, "%s:%d\n", __FILE__, __LINE__);
+ if (!exprl)
goto out;
- }
- output = fy_path_expr_execute(fypx, level + 1, exprl, NULL, ptype);
- if (!output) {
- fy_warning(diag, "%s:%d\n", __FILE__, __LINE__);
+ output = fy_path_expr_execute(fypx, level + 1, exprl, NULL, ptype, &error);
+ if (error)
+ goto err_out;
+
+ if (!output)
goto out;
- }
- exprt = fy_scalar_walk_result_to_expr(fypx, output, ptype);
+ exprt = fy_scalar_walk_result_to_expr(fypx, output, ptype, &error);
+ if (error)
+ goto err_out;
+
+ fy_walk_result_free(output);
output = NULL;
- if (!exprt) {
- fy_warning(diag, "%s:%d\n", __FILE__, __LINE__);
+
+ if (!exprt)
break;
- }
- output = fy_path_expr_execute(fypx, level + 1, exprt, input, ptype);
- if (!output) {
- fy_warning(diag, "%s:%d\n", __FILE__, __LINE__);
- }
+ output = fy_path_expr_execute(fypx, level + 1, exprt, input, ptype, &error);
input = NULL;
+ if (error)
+ goto err_out;
fy_path_expr_free(exprt);
+ exprt = NULL;
break;
case fpet_path_expr:
if (!exprl)
goto out;
- output = fy_path_expr_execute(fypx, level + 1, exprl, input, ptype);
+ output = fy_path_expr_execute(fypx, level + 1, exprl, input, ptype, &error);
+ input = NULL;
+ if (error)
+ goto err_out;
input = NULL;
break;
case fpet_method:
- assert(expr->fym);
+ if (!expr->fym)
+ goto err_out;
/* execute the arguments */
nargs = expr->fym->nargs;
if (input) {
input1 = fy_walk_result_clone(input);
- assert(input1);
+ if (!input1)
+ goto err_out;
} else
input1 = NULL;
- fwr_args[i] = fy_path_expr_execute(fypx, level + 1, exprt, input1, expr->type);
+ fwr_args[i] = fy_path_expr_execute(fypx, level + 1, exprt, input1,
+ expr->type, &error);
+ input1 = NULL;
+ if (error)
+ goto err_out;
}
} else
fwr_args = NULL;
- output = expr->fym->exec(expr->fym, fypx, level + 1, expr, input, fwr_args, nargs);
+ output = expr->fym->exec(expr->fym, fypx, level + 1, expr, input, fwr_args, nargs, &error);
+ if (error)
+ goto err_out;
input = NULL;
break;
case fpet_unselect:
/* pop the top in either case */
- assert(input);
if (!input)
- goto out;
+ goto err_out;
/* only handle inputs of node and refs */
if (input->type != fwrt_node_ref && input->type != fwrt_refs)
- goto out;
+ goto err_out;
/* execute the expression */
exprn = fy_path_expr_list_head(&expr->children);
- assert(exprn);
if (!exprn)
- goto out;
+ goto err_out;
fwrt = fy_walk_result_clone(input);
- assert(fwrt);
if (!fwrt)
- goto out;
+ goto err_out;
- fwrn = fy_path_expr_execute(fypx, level + 1, exprn, fwrt, expr->type);
+ fwrn = fy_path_expr_execute(fypx, level + 1, exprn, fwrt, expr->type, &error);
+ fwrt = NULL;
+ if (error)
+ goto err_out;
output = fy_walk_result_perform_set_op(fypx, input, fwrn, expr->type == fpet_unselect ? FYWRSO_UNSELECT : FYWRSO_SELECT);
input = NULL;
}
out:
+ fy_walk_result_free(output1);
+ fy_walk_result_free(output2);
+ fy_walk_result_free(input1);
+ fy_walk_result_free(input2);
fy_walk_result_free(input);
output = fy_walk_result_simplify(output);
fy_walk_result_dump(output, diag, FYET_NOTICE, level, "output %s\n", fy_path_expr_type_txt[expr->type]);
#endif
return output;
+
+err_out:
+ if (errorp)
+ *errorp = true;
+ fy_walk_result_free(output);
+ output = NULL;
+ goto out;
}
static int fy_path_exec_execute_internal(struct fy_path_exec *fypx,
struct fy_path_expr *expr, struct fy_node *fyn_start)
{
struct fy_walk_result *fwr;
+ bool error;
if (!fypx || !expr || !fyn_start)
return -1;
fypx->result = NULL;
fwr = fy_path_exec_walk_result_create(fypx, fwrt_node_ref, fyn_start);
- assert(fwr);
+ if (!fwr)
+ goto err_out;
+
+ fwr = fy_path_expr_execute(fypx, 0, expr, fwr, fpet_none, &error);
+ if (error)
+ goto err_out;
- fwr = fy_path_expr_execute(fypx, 0, expr, fwr, fpet_none);
if (!fwr)
return 0;
fypx->result = fwr;
return 0;
+err_out:
+ fy_walk_result_free(fwr);
+ return -1;
}
int fy_path_exec_execute(struct fy_path_exec *fypx, struct fy_path_expr *expr, struct fy_node *fyn_start)
return fy_walk_result_vcreate_rl(fwrl, type, ap);
}
+#ifndef DEBUG_EXPR
struct fy_walk_result *
fy_path_exec_walk_result_create(struct fy_path_exec *fypx, enum fy_walk_result_type type, ...)
{
return fwr;
}
+#else
+struct fy_walk_result *
+_fy_path_exec_walk_result_create(struct fy_path_exec *fypx,
+ const char *file, int line, const char *func,
+ enum fy_walk_result_type type, ...)
+{
+ struct fy_walk_result_list *fwrl;
+ struct fy_walk_result *fwr;
+ va_list ap;
+
+ if (!fypx)
+ return NULL;
+
+ fwrl = fy_path_exec_walk_result_rl(fypx);
+
+ va_start(ap, type);
+ fwr = fy_walk_result_vcreate_rl(fwrl, type, ap);
+ va_end(ap);
+
+ if (!fwr)
+ return NULL;
+
+ fwr->fypx = fy_path_exec_ref(fypx);
+
+ fprintf(stderr, "%s:%4d @%-48s %-32s fwr=%p (fypx=%p refs=%u)\n",
+ file, line, func, __func__, fwr, fwr->fypx, fwr->fypx ? fwr->fypx->refs : 0);
+
+ return fwr;
+}
+#endif
void
fy_path_exec_walk_result_free(struct fy_path_exec *fypx, struct fy_walk_result *fwr)
return rc;
}
pxdd = fyn->fyd->pxdd;
- assert(pxdd);
+ if (!pxdd)
+ goto err_out;
pxnd = malloc(sizeof(*pxnd));
if (!pxnd)
err_no_text:
free(pxnd);
err_no_mem:
+err_out:
return -1;
}
"fy_node_setup_path_expr_data() failed");
pxnd = fyn->pxnd;
- assert(pxnd);
+ if (!pxnd)
+ goto err_out;
pxdd = fyd->pxdd;
- assert(pxdd);
+ if (!pxdd)
+ goto err_out;
if (pxnd->traversals++ > 0) {
FYD_NODE_ERROR(fyd, fyn, FYEM_DOC,
fy_path_exec_set_result_recycle_list(fypx, &pxdd->fwr_recycle);
-#if 0
- {
- struct fy_document *fyd_pe;
- const char *text;
- size_t len;
-
- text = fy_token_get_text(fyn->scalar, &len);
- if (text) {
- fyd_pe = fy_path_expr_to_document(pxnd->expr);
- if (fyd_pe) {
- fprintf(stderr, "%s: %.*s\n", __func__, (int)len, text);
- fy_document_default_emit_to_fp(fyd_pe, stderr);
- fy_document_destroy(fyd_pe);
- }
- }
- }
-#endif
-
- // fprintf(stderr, "%s: %s 2\n", __func__, fy_node_get_path_alloca(fyn));
-
/* execute, starting at this */
rc = fy_path_exec_execute(fypx, pxnd->expr, fyn);
- fyd_error_check(fyd, !rc, err_out,
- "fy_path_exec_execute() failed");
-
- // fprintf(stderr, "%s: %s 3\n", __func__, fy_node_get_path_alloca(fyn));
+ if (rc)
+ goto err_out;
fwr = fy_path_exec_take_results(fypx);
if (!fwr)
return NULL;
- // fprintf(stderr, "%s: %s 4\n", __func__, fy_node_get_path_alloca(fyn));
-
return fwr;
err_out:
return NULL;
}
-struct fy_node *fy_node_alias_resolve_by_ypath(struct fy_node *fyn)
+static struct fy_node *
+fy_node_alias_resolve_by_ypath_internal(struct fy_node *fyn, bool *errorp)
{
struct fy_anchor *fya;
struct fy_walk_result *fwr;
void *iterp;
if (!fyn || !fy_node_is_alias(fyn))
- return NULL;
+ goto err_out;
/* simple and common enough to do it now */
fya = fy_document_lookup_anchor_by_token(fyn->fyd, fyn->scalar);
- if (fya)
+ if (fya) {
+ if (errorp)
+ *errorp = false;
return fya->fyn;
+ }
fwr = fy_node_alias_resolve_by_ypath_result(fyn);
if (!fwr)
- return NULL;
+ goto err_out;
iterp = NULL;
fyn = fy_walk_result_node_iterate(fwr, &iterp);
fy_walk_result_free(fwr);
+ if (errorp)
+ *errorp = false;
+
return fyn;
+err_out:
+ if (errorp)
+ *errorp = true;
+ return NULL;
+}
+
+struct fy_node *fy_node_alias_resolve_by_ypath(struct fy_node *fyn)
+{
+ return fy_node_alias_resolve_by_ypath_internal(fyn, NULL);
}
struct fy_walk_result *
"fy_node_setup_path_expr_data() failed");
pxdd = fyd->pxdd;
- assert(pxdd);
+ if (!pxdd)
+ goto err_out;
fyi = fy_input_from_data(path, len, NULL, false);
fyd_error_check(fyd, fyi, err_no_input,
struct fy_path_exec *fypx, int level,
struct fy_path_expr *expr,
struct fy_walk_result *input,
- struct fy_walk_result **args, int nargs);
+ struct fy_walk_result **args, int nargs,
+ bool *errorp);
};
FY_TYPE_FWD_DECL_LIST(path_expr);
struct fy_walk_result *
fy_path_expr_execute(struct fy_path_exec *fypx, int level, struct fy_path_expr *expr,
- struct fy_walk_result *input, enum fy_path_expr_type ptype);
+ struct fy_walk_result *input, enum fy_path_expr_type ptype,
+ bool *errorp);
static inline struct fy_walk_result_list *
fy_path_exec_walk_result_rl(struct fy_path_exec *fypx)
#include <alloca.h>
#endif
-#include <pthread.h>
#include <stdlib.h>
-#include <unistd.h>
#include <errno.h>
#include <limits.h>
+#ifndef _WIN32
+#include <pthread.h>
+#include <unistd.h>
+#endif
+
#if defined(__linux__)
#include <sys/syscall.h>
#include <linux/futex.h>
#endif
+#include "fy-win32.h"
#include "fy-diag.h"
#include "fy-utils.h"
#include "fy-thread.h"
#undef WORK_SHUTDOWN
#define WORK_SHUTDOWN ((struct fy_thread_work *)(void *)-1)
+/* Platform-specific thread-local storage access */
+#ifdef _WIN32
+#define fy_thread_getspecific(key) TlsGetValue(key)
+#else
+#define fy_thread_getspecific(key) pthread_getspecific(key)
+#endif
+
#ifdef FY_THREAD_DEBUG
#define TDBG(_fmt, ...) \
do { fprintf(stderr, (_fmt) __VA_OPT__(,) __VA_ARGS__); } while(0)
do { /* nothing */ } while(0)
#endif
+#ifdef _WIN32
+static DWORD WINAPI fy_worker_thread_standard(void *arg);
+static DWORD WINAPI fy_worker_thread_steal(void *arg);
+#else
static void *fy_worker_thread_standard(void *arg);
static void *fy_worker_thread_steal(void *arg);
+#endif
static void fy_thread_work_join_standard(struct fy_thread_pool *tp, struct fy_thread_work *works, size_t work_count, fy_work_check_fn check_fn);
static void fy_thread_work_join_steal(struct fy_thread_pool *tp, struct fy_thread_work *works, size_t work_count, fy_work_check_fn check_fn);
static void fy_thread_work_join_steal_2(struct fy_thread_pool *tp, struct fy_thread_work works[2], fy_work_check_fn check_fn);
-#if defined(__linux__) && !defined(FY_THREAD_PORTABLE)
+#if defined(_WIN32)
+
+/* Windows implementation using Events and Critical Sections */
+
+static inline void fy_thread_init_sync(struct fy_thread *t)
+{
+ t->submit_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ t->done_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ InitializeCriticalSection(&t->lock);
+ InitializeCriticalSection(&t->wait_lock);
+}
+
+static inline struct fy_thread_work *fy_worker_wait_for_work(struct fy_thread *t)
+{
+ struct fy_thread_work *work;
+
+ while ((work = fy_atomic_load(&t->work)) == NULL)
+ WaitForSingleObject(t->submit_event, INFINITE);
+
+ return work;
+}
+
+static inline void fy_worker_signal_work_done(struct fy_thread *t, struct fy_thread_work *work)
+{
+ struct fy_thread_work *exp_work;
+
+ EnterCriticalSection(&t->wait_lock);
+
+ exp_work = work;
+ if (!fy_atomic_compare_exchange_strong(&t->work, &exp_work, NULL))
+ assert(exp_work == WORK_SHUTDOWN);
+ SetEvent(t->done_event);
+ LeaveCriticalSection(&t->wait_lock);
+}
+
+static inline int fy_thread_submit_work_internal(struct fy_thread *t, struct fy_thread_work *work)
+{
+ struct fy_thread_work *exp_work;
+ int ret;
+
+ assert(t);
+ assert(work);
+
+ EnterCriticalSection(&t->lock);
+ exp_work = NULL;
+ if (!fy_atomic_compare_exchange_strong(&t->work, &exp_work, work)) {
+ assert(exp_work == WORK_SHUTDOWN);
+ ret = -1;
+ } else {
+ SetEvent(t->submit_event);
+ ret = 0;
+ }
+ LeaveCriticalSection(&t->lock);
+
+ return ret;
+}
+
+static inline int fy_thread_wait_work_internal(struct fy_thread *t)
+{
+ const struct fy_thread_work *work;
+
+ EnterCriticalSection(&t->wait_lock);
+ while ((work = fy_atomic_load(&t->work)) != NULL) {
+ LeaveCriticalSection(&t->wait_lock);
+ WaitForSingleObject(t->done_event, INFINITE);
+ EnterCriticalSection(&t->wait_lock);
+ }
+ LeaveCriticalSection(&t->wait_lock);
+
+ return 0;
+}
+
+void fy_worker_thread_shutdown(struct fy_thread *t)
+{
+ EnterCriticalSection(&t->lock);
+ fy_atomic_store(&t->work, WORK_SHUTDOWN);
+ SetEvent(t->submit_event);
+ LeaveCriticalSection(&t->lock);
+
+ WaitForSingleObject(t->tid, INFINITE);
+ CloseHandle(t->tid);
+ CloseHandle(t->submit_event);
+ CloseHandle(t->done_event);
+ DeleteCriticalSection(&t->lock);
+ DeleteCriticalSection(&t->wait_lock);
+}
+
+#elif defined(__linux__) && !defined(FY_THREAD_PORTABLE)
/* linux pedal to the metal implementation */
static inline int futex(FY_ATOMIC(uint32_t) *uaddr, int futex_op, uint32_t val, const struct timespec *timeout, uint32_t *uaddr2, uint32_t val3)
fy_cacheline_free(tp->threads);
}
+#ifdef _WIN32
+ if (tp->key != TLS_OUT_OF_INDEXES)
+ TlsFree(tp->key);
+#endif
+
memset(tp, 0, sizeof(*tp));
}
struct fy_thread *t;
unsigned int i, num_threads, num_threads_words;
size_t size, free_offset, loot_offset, thread_bitmask_size;
+#ifdef _WIN32
+ LPTHREAD_START_ROUTINE start_routine;
+#else
void *(*start_routine)(void *);
- long scval;
int rc __FY_DEBUG_UNUSED__;
+#endif
+ long scval;
assert(tp);
memset(tp->threads, 0, size);
+#ifdef _WIN32
+ tp->key = TlsAlloc();
+ assert(tp->key != TLS_OUT_OF_INDEXES);
+#else
rc = pthread_key_create(&tp->key, NULL);
assert(!rc);
+#endif
- tp->freep = (void *)tp->threads + free_offset;
- tp->lootp = (void *)tp->threads + loot_offset;
+ tp->freep = (_Atomic(uint64_t) *)((char *)tp->threads + free_offset);
+ tp->lootp = (_Atomic(uint64_t) *)((char *)tp->threads + loot_offset);
/* prime the thread free */
for (i = 0; i < num_threads_words - 1; i++)
fy_worker_thread_steal;
for (i = 0, t = tp->threads; i < tp->num_threads; i++, t++) {
+#ifdef _WIN32
+ t->tid = CreateThread(NULL, 0, start_routine, t, 0, NULL);
+ if (t->tid == NULL)
+ goto err_out;
+#else
rc = pthread_create(&t->tid, NULL, start_routine, t);
if (rc)
goto err_out;
+#endif
}
return 0;
for (i = 0; i < count; i++) {
works[i].fn = fn;
works[i].arg = args;
- args += argsize;
+ args = (char *)args + argsize;
}
fy_thread_work_join(tp, works, count, check_fn);
/*
* the standard (non-stealing implementation)
*/
+#ifdef _WIN32
+static DWORD WINAPI fy_worker_thread_standard(void *arg)
+#else
static void *fy_worker_thread_standard(void *arg)
+#endif
{
struct fy_thread *t = arg;
struct fy_thread_pool *tp;
tp = t->tp;
/* store per thread info */
+#ifdef _WIN32
+ TlsSetValue(tp->key, t);
+#else
pthread_setspecific(tp->key, t);
+#endif
while ((work = fy_worker_wait_for_work(t)) != WORK_SHUTDOWN) {
work->fn(work->arg);
fy_worker_signal_work_done(t, work);
}
+#ifdef _WIN32
+ return 0;
+#else
return NULL;
+#endif
}
static void fy_thread_work_join_standard(struct fy_thread_pool *tp, struct fy_thread_work *works, size_t work_count, fy_work_check_fn check_fn)
*/
static inline struct fy_work_pool *fy_work_pool_init(struct fy_work_pool *wp, size_t work_count)
{
-#if !(defined(__linux__) && !defined(FY_THREAD_PORTABLE))
+#if !(defined(__linux__) && !defined(FY_THREAD_PORTABLE)) && !defined(_WIN32)
int rc __FY_DEBUG_UNUSED__;
#endif
wp->sem = dispatch_semaphore_create(!work_count);
assert(wp->sem != NULL);
(void)rc;
+#elif defined(_WIN32)
+ wp->sem = CreateSemaphore(NULL, !work_count, LONG_MAX, NULL);
+ assert(wp->sem != NULL);
#else
rc = sem_init(&wp->sem, 0, !work_count);
assert(!rc);
static inline void fy_work_pool_cleanup(struct fy_work_pool *wp)
{
-#if !(defined(__linux__) && !defined(FY_THREAD_PORTABLE))
+#if !(defined(__linux__) && !defined(FY_THREAD_PORTABLE)) && !defined(_WIN32)
int rc __FY_DEBUG_UNUSED__;
#endif
if (!wp)
return;
-#if defined(__linux__) && !defined(FY_THREAD_PORTABLE)
+#if defined(_WIN32)
+ CloseHandle(wp->sem);
+#elif defined(__linux__) && !defined(FY_THREAD_PORTABLE)
/* nothing */
#elif defined(__APPLE__)
/* nothing */
static inline bool fy_work_pool_signal(struct fy_work_pool *wp)
{
size_t prev_work_left;
+#if !defined(_WIN32)
int rc __FY_DEBUG_UNUSED__;
+#endif
if (!wp)
return false;
prev_work_left = fy_atomic_fetch_sub(&wp->work_left, 1);
if (prev_work_left == 1) {
-#if defined(__linux__) && !defined(FY_THREAD_PORTABLE)
+#if defined(_WIN32)
+ ReleaseSemaphore(wp->sem, 1, NULL);
+#elif defined(__linux__) && !defined(FY_THREAD_PORTABLE)
rc = fpost(&wp->done);
assert(!rc);
#elif defined(__APPLE__)
static inline void fy_work_pool_wait(struct fy_work_pool *wp)
{
+#if !defined(_WIN32)
int rc __FY_DEBUG_UNUSED__;
+#else
+ DWORD rc __FY_DEBUG_UNUSED__;
+#endif
if (!wp)
return;
while (fy_atomic_load(&wp->work_left) > 0) {
#if defined(__linux__) && !defined(FY_THREAD_PORTABLE)
rc = fwait(&wp->done);
+ assert(!rc || (rc == -1 && errno == EAGAIN));
#elif defined(__APPLE__)
dispatch_semaphore_wait(wp->sem, DISPATCH_TIME_FOREVER);
rc = 0;
+#elif defined(_WIN32)
+ rc = WaitForSingleObject(wp->sem, INFINITE);
+ assert(rc == WAIT_OBJECT_0);
#else
rc = sem_wait(&wp->sem);
-#endif
assert(!rc || (rc == -1 && errno == EAGAIN));
+#endif
}
}
return NULL;
}
+#ifdef _WIN32
+static DWORD WINAPI fy_worker_thread_steal(void *arg)
+#else
static void *fy_worker_thread_steal(void *arg)
+#endif
{
struct fy_thread *t = arg;
struct fy_thread_pool *tp;
tp = t->tp;
/* store per thread info */
+#ifdef _WIN32
+ TlsSetValue(tp->key, t);
+#else
pthread_setspecific(tp->key, t);
+#endif
TDBG("%s: T#%u in steal mode\n", __func__, t->id);
}
TDBG("%s: T#%u leaving steal mode\n", __func__, t->id);
+#ifdef _WIN32
+ return 0;
+#else
return NULL;
+#endif
}
static void fy_thread_work_join_steal(struct fy_thread_pool *tp, struct fy_thread_work *works, size_t work_count, fy_work_check_fn check_fn)
resolved_t = false;
tid = -1;
(void)tid;
+ (void)rc;
#ifdef FY_THREAD_DEBUG
- t = pthread_getspecific(tp->key);
+#ifdef _WIN32
+ t = TlsGetValue(tp->key);
+#else
+ t = fy_thread_getspecific(tp->key);
+#endif
tid = t ? (int)t->id : -1;
resolved_t = true;
#else
if (work_count > 0) {
if (!resolved_t) {
- t = pthread_getspecific(tp->key);
+ t = fy_thread_getspecific(tp->key);
tid = t ? (int)t->id : -1;
resolved_t = true;
}
(void)tid;
#ifdef FY_THREAD_DEBUG
- t = pthread_getspecific(tp->key);
+#ifdef _WIN32
+ t = TlsGetValue(tp->key);
+#else
+ t = fy_thread_getspecific(tp->key);
+#endif
tid = t ? (int)t->id : -1;
resolved_t = true;
#else
} else {
if (!resolved_t) {
- t = pthread_getspecific(tp->key);
+ t = fy_thread_getspecific(tp->key);
tid = t ? (int)t->id : -1;
resolved_t = true;
}
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
-#include <stdatomic.h>
-#include <pthread.h>
+#ifndef _WIN32
+#include <pthread.h>
#ifndef __APPLE__
#include <semaphore.h>
#else
#include <dispatch/dispatch.h>
#endif
+#endif
+#include "fy-win32.h"
#include "fy-bit64.h"
#include "fy-align.h"
#include "fy-atomics.h"
FY_ATOMIC(uint32_t) done;
#elif defined(__APPLE__)
dispatch_semaphore_t sem;
+#elif defined(_WIN32)
+ HANDLE sem;
#else
sem_t sem;
#endif
struct fy_thread {
struct fy_thread_pool *tp;
unsigned int id;
- pthread_t tid;
FY_ATOMIC(struct fy_thread_work *)work;
FY_ATOMIC(struct fy_thread_work *)next_work;
+#ifndef _WIN32
+ pthread_t tid;
+#else
+ HANDLE tid;
+#endif
#if defined(__linux__) && !defined(FY_THREAD_PORTABLE)
FY_ATOMIC(uint32_t) submit;
FY_ATOMIC(uint32_t) done;
+#elif defined(_WIN32)
+ HANDLE submit_event;
+ HANDLE done_event;
+ CRITICAL_SECTION lock;
+ CRITICAL_SECTION wait_lock;
#else
pthread_mutex_t lock;
pthread_cond_t cond;
struct fy_thread *threads;
FY_ATOMIC(uint64_t) *freep;
FY_ATOMIC(uint64_t) *lootp;
+#if !defined(_WIN32)
pthread_key_t key;
+#else // _WIN32
+ DWORD key;
+#endif
};
/* those are internal only */
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
#include <ctype.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <regex.h>
#include <stdalign.h>
#include <inttypes.h>
#include <float.h>
#include <limits.h>
#include <math.h>
+#include <errno.h>
+#include <fcntl.h>
#include <libfyaml.h>
case '\v':
printf("\\v");
break;
- case '\e':
+ case '\x1b':
printf("\\e");
break;
case 0x85:
[fycp_bottom] = "bottom",
};
enum fy_comment_placement placement;
- char buf[4096];
const char *str;
if (!fyt)
return;
for (placement = fycp_top; placement < fycp_max; placement++) {
- str = fy_token_get_comment(fyt, buf, sizeof(buf), placement);
+ str = fy_token_get_comment(fyt, placement);
if (!str)
continue;
fputs("\n", stdout);
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
#include <ctype.h>
-#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <regex.h>
#include <stdalign.h>
#include <inttypes.h>
#include <float.h>
v = 0;
width = bit_width;
- p = ptr + bit_offset / 8;
+ p = (const uint8_t *)ptr + bit_offset / 8;
off = bit_offset & 7;
if (off) {
space = 8 - off;
uint8_t bmask;
width = bit_width;
- p = ptr + bit_offset / 8;
+ p = (uint8_t *)ptr + bit_offset / 8;
off = bit_offset & 7;
if (off) {
space = 8 - off;
#include <stdio.h>
#include <stdbool.h>
+#ifdef _WIN32
+#include "fy-win32.h"
+#include <io.h>
+#else
#include <unistd.h>
#include <termios.h>
+#endif
#include <stdint.h>
#include <string.h>
#define COMPILE_ERROR_ON_ZERO(_e) ((void)(sizeof(char[1 - 2*!!(_e)])))
/* true, if types are the same, false otherwise (depends on builtin_types_compatible_p) */
-#if defined(__has_builtin) && __has_builtin(__builtin_types_compatible_p)
+#if defined(__has_builtin)
+#if __has_builtin(__builtin_types_compatible_p)
#define SAME_TYPE(_a, _b) __builtin_types_compatible_p(__typeof__(_a), __typeof__(_b))
-#else
+#endif
+#endif
+
+#ifndef SAME_TYPE
#define SAME_TYPE(_a, _b) true
#endif
COMPILE_ERROR_ON_ZERO(!SAME_TYPE(_a, _b))
/* type safe add overflow */
-#if defined(__has_builtin) && __has_builtin(__builtin_add_overflow)
+#if defined(__has_builtin)
+#if __has_builtin(__builtin_add_overflow)
#define ADD_OVERFLOW __builtin_add_overflow
+#endif
+#endif
+#ifndef ADD_OVERFLOW
+#if defined(_MSC_VER)
+/* MSVC-compatible version - simple overflow check for unsigned types */
+static inline bool fy_add_overflow_size_t(size_t a, size_t b, size_t *resp)
+{
+ *resp = a + b;
+ return *resp < a;
+}
+#define ADD_OVERFLOW(a, b, resp) fy_add_overflow_size_t((size_t)(a), (size_t)(b), (size_t*)(resp))
#else
#define ADD_OVERFLOW(_a, _b, _resp) \
({ \
__overflow; \
})
#endif
+#endif
/* type safe sub overflow */
-#if defined(__has_builtin) && __has_builtin(__builtin_sub_overflow)
+#if defined(__has_builtin)
+#if __has_builtin(__builtin_sub_overflow)
#define SUB_OVERFLOW __builtin_sub_overflow
+#endif
+#endif
+#ifndef SUB_OVERFLOW
+#if defined(_MSC_VER)
+/* MSVC-compatible version */
+static inline bool fy_sub_overflow_size_t(size_t a, size_t b, size_t *resp)
+{
+ *resp = a - b;
+ return a < b;
+}
+#define SUB_OVERFLOW(a, b, resp) fy_sub_overflow_size_t((size_t)(a), (size_t)(b), (size_t*)(resp))
#else
#define SUB_OVERFLOW(_a, _b, _resp) \
({ \
__overflow; \
})
#endif
+#endif
/* type safe multiply overflow */
-#if defined(__has_builtin) && __has_builtin(__builtin_mul_overflow)
+#if defined(__has_builtin)
+#if __has_builtin(__builtin_mul_overflow)
#define MUL_OVERFLOW __builtin_mul_overflow
+#endif
+#endif
+#ifndef MUL_OVERFLOW
+#if defined(_MSC_VER)
+/* MSVC-compatible version */
+static inline bool fy_mul_overflow_size_t(size_t a, size_t b, size_t *resp)
+{
+ if (a == 0 || b == 0) {
+ *resp = 0;
+ return false;
+ }
+ *resp = a * b;
+ return (*resp / a) != b;
+}
+#define MUL_OVERFLOW(a, b, resp) fy_mul_overflow_size_t((size_t)(a), (size_t)(b), (size_t*)(resp))
#else
#define MUL_OVERFLOW(_a, _b, _resp) \
({ \
__overflow; \
})
#endif
+#endif
/* ANSI colors and escapes */
#define A_RESET "\x1b[0m"
uintmax_t load_bitfield_le(const void *ptr, size_t bit_offset, size_t bit_width, bool is_signed);
void store_bitfield_le(void *ptr, size_t bit_offset, size_t bit_width, uintmax_t v);
-static inline intmax_t signed_integer_max_from_bit_width(int bit_width)
+static inline intmax_t signed_integer_max_from_bit_width(size_t bit_width)
{
- assert((size_t)bit_width <= sizeof(intmax_t) * 8);
+ assert(bit_width <= sizeof(intmax_t) * 8);
return INTMAX_MAX >> (sizeof(intmax_t) * 8 - bit_width);
}
-static inline intmax_t signed_integer_min_from_bit_width(int bit_width)
+static inline intmax_t signed_integer_min_from_bit_width(size_t bit_width)
{
- assert((size_t)bit_width <= sizeof(intmax_t) * 8);
+ assert(bit_width <= sizeof(intmax_t) * 8);
return INTMAX_MIN >> (sizeof(intmax_t) * 8 - bit_width);
}
-static inline uintmax_t unsigned_integer_max_from_bit_width(int bit_width)
+static inline uintmax_t unsigned_integer_max_from_bit_width(size_t bit_width)
{
- assert((size_t)bit_width <= sizeof(uintmax_t) * 8);
+ assert(bit_width <= sizeof(uintmax_t) * 8);
return UINTMAX_MAX >> (sizeof(uintmax_t) * 8 - bit_width);
}
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
#include <ctype.h>
-#include <unistd.h>
+
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
-#include <regex.h>
#include <stdalign.h>
#include <inttypes.h>
#include <float.h>
#include <libfyaml.h>
+#ifndef _WIN32
+#include <unistd.h>
+#include <regex.h>
+#else
+#include "fy-win32.h"
+#endif
+
+#include <getopt.h>
+
#include "fy-valgrind.h"
#include "fy-tool-util.h"
+#ifdef _WIN32
+#undef SORT_DEFAULT
+#endif
+
#define QUIET_DEFAULT false
#define INCLUDE_DEFAULT ""
#define DEBUG_LEVEL_DEFAULT 3
{
const char *s, *e, *sn;
char *targ;
- int len, rc;
+ size_t len;
+ int rc;
if (!arg || !flagsp || !modify_flags)
return -1;
if (!sn)
sn = e;
- len = sn - s;
+ len = (size_t)(sn - s);
targ = alloca(len + 1);
memcpy(targ, s, len);
targ[len] = '\0';
const uint8_t *computed_hash;
char *s;
char c;
- unsigned int i, j, length;
+ unsigned int i, j;
+ size_t length;
size_t linesz;
int line, exit_code;
while (isxdigit((unsigned char)*s))
s++;
- length = s - linebuf;
+ length = (size_t)(s - linebuf);
if (length == 0 || length > (FY_BLAKE3_OUT_LEN * 2) || (length % 1) || !isspace((unsigned char)*s)) {
fprintf(stderr, "Bad line found at file \"%s\" line #%d\n", check_filename, line);
fy_valgrind_check(&argc, &argv);
+#ifdef _WIN32
+ /* On Windows, set stdin/stdout to binary mode to prevent CRLF conversion */
+ _setmode(_fileno(stdin), _O_BINARY);
+ _setmode(_fileno(stdout), _O_BINARY);
+
+ /* Enable ANSI escape sequence processing for colored output.
+ * Skip this on Wine - the host terminal handles ANSI natively and
+ * enabling VT processing causes Wine to interpret sequences internally. */
+ if (!GetModuleHandleA("ntdll.dll") ||
+ !GetProcAddress(GetModuleHandleA("ntdll.dll"), "wine_get_version")) {
+ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ HANDLE hErr = GetStdHandle(STD_ERROR_HANDLE);
+ DWORD dwMode = 0;
+ if (hOut != INVALID_HANDLE_VALUE && GetConsoleMode(hOut, &dwMode)) {
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ SetConsoleMode(hOut, dwMode);
+ }
+ if (hErr != INVALID_HANDLE_VALUE && GetConsoleMode(hErr, &dwMode)) {
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ SetConsoleMode(hErr, dwMode);
+ }
+ }
+#endif
+
/* select the appropriate tool mode */
progname = strrchr(argv[0], '/');
+#ifdef _WIN32
+ /* On Windows, also check for backslash */
+ {
+ char *p = strrchr(argv[0], '\\');
+ if (p && (!progname || p > progname))
+ progname = p;
+ }
+#endif
if (!progname)
progname = argv[0];
else
progname++;
+#ifdef _WIN32
+ /* On Windows, strip .exe extension for comparison */
+ {
+ static char progname_buf[256];
+ size_t len = strlen(progname);
+ if (len > 4 && !_stricmp(progname + len - 4, ".exe")) {
+ if (len - 4 < sizeof(progname_buf)) {
+ memcpy(progname_buf, progname, len - 4);
+ progname_buf[len - 4] = '\0';
+ progname = progname_buf;
+ }
+ }
+ }
+#endif
+
/* default mode is dump */
if (!strcmp(progname, "fy-filter"))
tool_mode = OPT_FILTER;
#if defined(__GNUC__) || defined(__clang__)
#define FY_ALIGNED_TO(x) __attribute__ ((aligned(x)))
#elif defined(_MSC_VER)
-#define FY_ALIGNED_TO(x) __declspec(align(x))
+#define FY_ALIGNED_TO(x) /* nothing - MSVC doesn't support trailing alignment */
#else
#define FY_ALIGNED_TO(x) /* nothing */
#endif
#define FY_CACHELINE_SIZE_ALIGN(_x) FY_ALIGN(FY_CACHELINE_SIZE, _x)
#define FY_CACHELINE_ALIGN FY_ALIGNED_TO(FY_CACHELINE_SIZE)
-/* provide posix_memalign for platforms that don't have it */
-#ifdef _WIN32
-static inline int posix_memalign(void **ptr, size_t align, size_t size)
-{
- void *p;
-
- /* must be a power of two */
- if ((size & (size -1)) != 0) {
- *ptr = NULL;
- return EINVAL;
- }
-
- p = _aligned_malloc(size, align);
- if (!p) {
- *ptr = NULL;
- return ENOMEM;
- }
- return p;
-}
-
-static inline void posix_memalign_free(void *p)
-{
- _aligned_free(p);
-}
-
-#else
-/* normal implementations just use free */
-static inline void posix_memalign_free(void *p)
-{
- free(p);
-}
-#endif
-
static inline void *fy_align_alloc(size_t align, size_t size)
{
void *p;
- int rc;
size = FY_ALIGN(align, size);
- rc = posix_memalign(&p, align, size);
- if (rc)
+#ifndef _WIN32
+ if (posix_memalign(&p, align, size))
return NULL;
+#else
+ p = _aligned_malloc(size, align);
+ if (!p)
+ return NULL;
+#endif
return p;
}
static inline void fy_align_free(void *p)
{
- if (p)
- posix_memalign_free(p);
+ if (!p)
+ return;
+#ifndef _WIN32
+ free(p);
+#else
+ _aligned_free(p);
+#endif
}
static inline void *fy_cacheline_alloc(size_t size)
#endif
}
-#define fy_atomic_get_and_clear_counter(_ptr) \
- ({ \
- __typeof__(_ptr) __ptr = (_ptr); \
- __typeof__(*__ptr + 0) __v = fy_atomic_load(__ptr); \
- fy_atomic_fetch_sub(__ptr, __v); \
- __v; \
- })
+static inline uint64_t
+fy_atomic_get_and_clear_counter(FY_ATOMIC(uint64_t) *ptr)
+{
+ uint64_t v;
+
+ v = fy_atomic_load(ptr);
+ fy_atomic_fetch_sub(ptr, v);
+ return v;
+}
#endif
return FY_BIT64_FFS(x);
}
+#elif defined(_MSC_VER) /* MSVC implementation */
+
+#include <intrin.h>
+
+#if defined(_M_X64) || defined(_M_AMD64) || defined(_M_ARM64)
+/* 64-bit MSVC - use native 64-bit intrinsics */
+
+static inline unsigned int fy_bit64_lowest(uint64_t x)
+{
+ unsigned long index;
+ if (_BitScanForward64(&index, x))
+ return (unsigned int)index;
+ return 64;
+}
+
+static inline unsigned int fy_bit64_highest(uint64_t x)
+{
+ unsigned long index;
+ if (_BitScanReverse64(&index, x))
+ return 63 - (unsigned int)index;
+ return 64;
+}
+
+static inline unsigned int fy_bit64_popcnt(uint64_t x)
+{
+ return (unsigned int)__popcnt64(x);
+}
+
+static inline unsigned int fy_bit64_ffs(uint64_t x)
+{
+ unsigned long index;
+ if (x == 0)
+ return 0;
+ _BitScanForward64(&index, x);
+ return (unsigned int)index + 1;
+}
+
+#else
+/* 32-bit MSVC - use 32-bit intrinsics on halves */
+
+static inline unsigned int fy_bit64_lowest(uint64_t x)
+{
+ unsigned long index;
+ uint32_t lo = (uint32_t)x;
+ uint32_t hi = (uint32_t)(x >> 32);
+
+ if (lo && _BitScanForward(&index, lo))
+ return (unsigned int)index;
+ if (hi && _BitScanForward(&index, hi))
+ return (unsigned int)index + 32;
+ return 64;
+}
+
+static inline unsigned int fy_bit64_highest(uint64_t x)
+{
+ unsigned long index;
+ uint32_t lo = (uint32_t)x;
+ uint32_t hi = (uint32_t)(x >> 32);
+
+ if (hi && _BitScanReverse(&index, hi))
+ return 63 - ((unsigned int)index + 32);
+ if (lo && _BitScanReverse(&index, lo))
+ return 63 - (unsigned int)index;
+ return 64;
+}
+
+static inline unsigned int fy_bit64_popcnt(uint64_t x)
+{
+ uint32_t lo = (uint32_t)x;
+ uint32_t hi = (uint32_t)(x >> 32);
+ return (unsigned int)(__popcnt(lo) + __popcnt(hi));
+}
+
+static inline unsigned int fy_bit64_ffs(uint64_t x)
+{
+ unsigned long index;
+ uint32_t lo = (uint32_t)x;
+ uint32_t hi = (uint32_t)(x >> 32);
+
+ if (x == 0)
+ return 0;
+ if (lo && _BitScanForward(&index, lo))
+ return (unsigned int)index + 1;
+ if (hi && _BitScanForward(&index, hi))
+ return (unsigned int)index + 33;
+ return 0;
+}
+
+#endif /* 64-bit vs 32-bit MSVC */
+
+#define FY_BIT64_LOWEST(_x) fy_bit64_lowest(_x)
+#define FY_BIT64_HIGHEST(_x) fy_bit64_highest(_x)
+#define FY_BIT64_POPCNT(_x) fy_bit64_popcnt(_x)
+#define FY_BIT64_FFS(_x) fy_bit64_ffs(_x)
+
#else /* portable implementation */
static inline unsigned int fy_bit64_lowest(uint64_t x)
}
#define FY_BIT64_LOWEST(_x) fy_bit64_lowest(_x)
-#define FY_BIT64_HIGEST(_x) fy_bit64_highest(_x)
+#define FY_BIT64_HIGHEST(_x) fy_bit64_highest(_x)
#define FY_BIT64_POPCNT(_x) fy_bit64_popcnt(_x)
#define FY_BIT64_FFS(_x) fy_bit64_ffs(_x)
#include "config.h"
#endif
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
+#include <fcntl.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <sys/stat.h>
+#endif
+#include "fy-win32.h"
#include "fy-blob.h"
/* define optimized methods for probing */
static inline const void * \
fy_find_ ## _kind (const void *s, size_t len) \
{ \
- const void *e = s + len; \
+ const char *sc = (const char *)s; \
+ const char *e = sc + len; \
int c, w; \
- for (; s < e && (c = fy_utf8_get(s, e - s, &w)) >= 0; s += w) { \
+ for (; sc < e && (c = fy_utf8_get(sc, (size_t)(e - sc), &w)) >= 0; sc += w) { \
assert(w); \
if (fy_is_ ## _kind (c)) \
- return s; \
+ return sc; \
} \
return NULL; \
} \
static inline const void * \
fy_find_non_ ## _kind (const void *s, size_t len) \
{ \
- const void *e = s + len; \
+ const char *sc = (const char *)s; \
+ const char *e = sc + len; \
int c, w; \
- for (; s < e && (c = fy_utf8_get(s, e - s, &w)) >= 0; s += w) { \
+ for (; sc < e && (c = fy_utf8_get(sc, (size_t)(e - sc), &w)) >= 0; sc += w) { \
assert(w); \
if (!(fy_is_ ## _kind (c))) \
- return s; \
+ return sc; \
assert(w); \
} \
return NULL; \
if (c == '\r' && left > (size_t)width && *(char *)ptr == '\n')
width++;
- return ptr + width;
+ return (const char *)ptr + width;
}
/* given a pointer to a chunk of memory, return pointer to first
#ifndef FY_ENDIAN_H
#define FY_ENDIAN_H
-#if defined(__linux__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__)
+#if defined(__linux__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__) || defined(__EMSCRIPTEN__)
# include <endian.h>
#elif defined(__APPLE__)
# include <libkern/OSByteOrder.h>
# include <machine/endian.h>
#elif defined(__NetBSD__) || defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/endian.h>
-#elif defined(_MSC_VER)
-# include <winsock2.h>
-# ifdef __GNUC__
-# include <sys/param.h>
-# endif
+#elif defined(_WIN32) || defined(_MSC_VER)
+/* Windows is always little-endian on supported platforms */
+# define __LITTLE_ENDIAN 1234
+# define __BIG_ENDIAN 4321
+# define __BYTE_ORDER __LITTLE_ENDIAN
#else
# error unsupported platform
#endif
#define FY_ID_H
#include <stdlib.h>
-#include <strings.h>
#include <string.h>
#include <assert.h>
-
#include <stdint.h>
#include "fy-bit64.h"
fy_id_bits_non_atomic v, new_v;
for (i = 0; i < count; i++, bits++) {
-
for (;;) {
v = fy_atomic_load(bits);
pos = fy_id_ffs(~v);
break;
new_v = v | FY_ID_BIT_MASK(pos);
if (fy_atomic_compare_exchange_strong(bits, &v, new_v))
- return (i * FY_ID_BITS_BITS) + pos;
+ return ((int)i * FY_ID_BITS_BITS) + pos;
}
}
return -1;
};
static const struct fy_utf8_fmt_esc_map esc_all = {
- .ch = (const int []){ '\\', '\0', '\b', '\r', '\t', '\f', '\n', '\v', '\a', '\e', 0x85, 0xa0, 0x2028, 0x2029, -1 },
+ .ch = (const int []){ '\\', '\0', '\b', '\r', '\t', '\f', '\n', '\v', '\a', '\x1b', 0x85, 0xa0, 0x2028, 0x2029, -1 },
.map = (const int []){ '\\', '0', 'b', 'r', 't', 'f', 'n', 'v', 'a', 'e', 'N', '_', 'L', 'P', 0 }
};
const void *fy_utf8_memchr_generic(const void *s, int c, size_t n)
{
int cc, w;
- const void *e;
+ const char *sc, *e;
- e = s + n;
- while (s < e && (cc = fy_utf8_get(s, e - s, &w)) >= 0) {
+ sc = (const char *)s;
+ e = sc + n;
+ while (sc < e && (cc = fy_utf8_get(sc, e - sc, &w)) >= 0) {
if (c == cc)
- return s;
- s += w;
+ return sc;
+ sc += w;
}
return NULL;
value = '\v';
break;
case 'e':
- value = '\e';
+ value = '\x1b';
break;
case ' ':
value = ' ';
return NULL;
tmpargv = mem;
- tmparg = mem + (argv_count + 1) * sizeof(*tmpargv);
+ tmparg = (char *)mem + (argv_count + 1) * sizeof(*tmpargv);
for (i = 0; i < argv_count; i++) {
tmpargv[i] = tmparg;
strcpy(tmparg, argv[i]);
- tmparg += strlen(argv[i]) + 1;
+ tmparg = tmparg + strlen(argv[i]) + 1;
}
tmpargv[i] = NULL;
width = fy_utf8_width_by_first_octet(p[0]);
if (!width)
return FYUG_INV;
- if (ptr + width > ptr_end)
+ if ((const char *)ptr + width > (const char *)ptr_end)
return FYUG_PARTIAL;
/* initial value */
#include <alloca.h>
#endif
-
+#include "fy-win32.h"
#include "fy-utils.h"
#define FY_UTF8_MIN_WIDTH 1
static inline FY_ALWAYS_INLINE int
fy_utf8_get_end(const void *ptr, const void *ptr_end, int *widthp)
{
- return fy_utf8_get(ptr, (size_t)(ptr_end - ptr), widthp);
+ return fy_utf8_get(ptr, (size_t)((const char *)ptr_end - (const char *)ptr), widthp);
}
static inline FY_ALWAYS_INLINE int
{
int w;
- return fy_utf8_get(ptr, (size_t)(ptr_end - ptr), &w);
+ return fy_utf8_get(ptr, (size_t)((const char *)ptr_end - (const char *)ptr), &w);
}
int fy_utf8_get_right_generic(const void *ptr, size_t left, int *widthp);
static inline int fy_utf8_get_right(const void *ptr, size_t left, int *widthp)
{
- const uint8_t *p = ptr + left;
+ const uint8_t *p = (const uint8_t *)ptr + left;
/* single byte (hot path) */
if (left > 0 && !(p[-1] & 0x80)) {
char *fy_utf8_format(int c, char *buf, const enum fy_utf8_escape esc);
+#ifdef _MSC_VER
+/* MSVC doesn't support GCC statement expressions - use static buffers */
+static __declspec(thread) char fy_utf8_format_a_buf[FY_UTF8_FORMAT_BUFMIN];
+static __declspec(thread) char fy_utf8_format_text_a_buf[4096];
+
+#define fy_utf8_format_a(_c, _esc) \
+ strcpy(alloca(FY_UTF8_FORMAT_BUFMIN + 1), \
+ fy_utf8_format((_c), fy_utf8_format_a_buf, (_esc)))
+
+#define fy_utf8_format_text_a(_buf, _len, _esc) \
+ strcpy(alloca(sizeof(fy_utf8_format_text_a_buf) + 1), \
+ fy_utf8_format_text((_buf), (_len), \
+ fy_utf8_format_text_a_buf, sizeof(fy_utf8_format_text_a_buf) - 1, (_esc)))
+#else
+/* GCC/Clang version with statement expressions */
#define fy_utf8_format_a(_c, _esc) \
({ \
char *_buf = alloca(FY_UTF8_FORMAT_BUFMIN); \
fy_utf8_format((_c), _buf, _esc); \
})
+#endif
size_t fy_utf8_format_text_length(const char *buf, size_t len,
enum fy_utf8_escape esc);
char *out, size_t maxsz,
enum fy_utf8_escape esc);
+#ifndef _MSC_VER
#define fy_utf8_format_text_a(_buf, _len, _esc) \
({ \
const char *__buf = (_buf); \
char *_out = alloca(_outsz + 1); \
fy_utf8_format_text(__buf, __len, _out, _outsz, __esc); \
})
+#endif
char *fy_utf8_format_text_alloc(const char *buf, size_t len, const enum fy_utf8_escape esc);
static inline int fy_utf8_count(const void *ptr, size_t len)
{
- const uint8_t *s = ptr, *e = ptr + len;
+ const uint8_t *s = (const uint8_t *)ptr, *e = (const uint8_t *)ptr + len;
int w, count;
count = 0;
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <ctype.h>
+
+#ifndef _WIN32
#include <termios.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
-#include <ctype.h>
+#endif
+#include "fy-win32.h"
#include "fy-utf8.h"
#include "fy-ctype.h"
#include "fy-utils.h"
c = fy_utf8_get(s, e - s, &w);
if (c == -1)
- return len;
+ return (int)len;
if (fy_is_ws(c))
- return s - data;
+ return (int)(s - data);
/* if first character is !, empty handle */
if (c == '!') {
s += w;
- return s - data;
+ return (int)(s - data);
}
if (!fy_is_first_alpha(c))
return -1;
if (c == '!')
s += w;
- return s - data;
+ return (int)(s - data);
}
int fy_tag_uri_length(const char *data, size_t len)
break;
s += w;
}
- uri_length = s - data;
+ uri_length = (int)(s - data);
if (!fy_tag_uri_is_valid(data, uri_length))
return -1;
}
/* simple terminal methods; mainly for getting size of terminal */
-int fy_term_set_raw(int fd, struct termios *oldt)
+/* These functions are not available on Windows */
+#ifndef _WIN32
+static int
+fy_term_set_raw(int fd, struct termios *oldt)
{
struct termios newt, t;
int ret;
return 0;
}
-int fy_term_restore(int fd, const struct termios *oldt)
+static int
+fy_term_restore(int fd, const struct termios *oldt)
{
/* must be a terminal */
if (!isatty(fd))
return tcsetattr(fd, TCSANOW, oldt);
}
-ssize_t fy_term_write(int fd, const void *data, size_t count)
+static ssize_t
+fy_term_write(int fd, const void *data, size_t count)
{
ssize_t wrn, r;
return wrn > 0 ? wrn : r;
}
-int fy_term_safe_write(int fd, const void *data, size_t count)
+static int
+fy_term_safe_write(int fd, const void *data, size_t count)
{
if (!isatty(fd))
return -1;
return fy_term_write(fd, data, count) == (ssize_t)count ? 0 : -1;
}
-ssize_t fy_term_read(int fd, void *data, size_t count, int timeout_us)
+static ssize_t
+fy_term_read(int fd, void *data, size_t count, int timeout_us)
{
ssize_t rdn, r;
struct timeval tv, tvto, *tvp;
return rdn > 0 ? rdn : r;
}
-ssize_t fy_term_read_escape(int fd, void *buf, size_t count)
+static ssize_t
+fy_term_read_escape(int fd, void *buf, size_t count)
{
char *p;
int r, rdn;
return rdn;
}
-int fy_term_query_size_raw(int fd, int *rows, int *cols)
+static int
+fy_term_query_size_raw(int fd, int *rows, int *cols)
{
char buf[32];
char *s, *e;
return ret;
}
+#else /* _WIN32 */
+
+int fy_term_query_size(int fd, int *rows, int *cols)
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ HANDLE h;
+
+ if (fd != _fileno(stdout) && fd != _fileno(stderr))
+ return -1;
+
+ h = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (!GetConsoleScreenBufferInfo(h, &csbi))
+ return -1;
+
+ *cols = (int)(csbi.srWindow.Right - csbi.srWindow.Left + 1);
+ *rows = (int)(csbi.srWindow.Bottom - csbi.srWindow.Top + 1);
+ return 0;
+}
+
+#endif /* !_WIN32 - end of terminal functions */
+
int fy_comment_iter_begin(const char *comment, size_t size, struct fy_comment_iter *iter)
{
if (!comment || !iter)
char *fy_get_cooked_comment(const char *raw_comment, size_t size)
{
+ struct fy_memstream *fyms = NULL;
struct fy_comment_iter iter;
FILE *fp;
char *buf;
if (!raw_comment)
return NULL;
- fp = open_memstream(&buf, &len);
- if (!fp)
+ fyms = fy_memstream_open(&fp);
+ if (!fyms)
return NULL;
ret = 0;
}
fy_comment_iter_end(&iter);
- fclose(fp);
-
+ buf = fy_memstream_close(fyms, &len);
if (ret < 0) {
if (buf)
free(buf);
hash++;
return hash;
}
+
+struct fy_memstream {
+ FILE *fp;
+ char *buf;
+ size_t size;
+};
+
+struct fy_memstream *fy_memstream_open(FILE **fpp)
+{
+ struct fy_memstream *fyms;
+
+ if (!fpp)
+ return NULL;
+
+ *fpp = NULL;
+
+ fyms = malloc(sizeof(*fyms));
+ if (!fyms)
+ return NULL;
+ memset(fyms, 0, sizeof(*fyms));
+#if !defined(_WIN32)
+ fyms->fp = open_memstream(&fyms->buf, &fyms->size);
+#else
+ fyms->fp = tmpfile();
+#endif
+ if (!fyms->fp) {
+ free(fyms);
+ return NULL;
+ }
+ *fpp = fyms->fp;
+ return fyms;
+}
+
+char *fy_memstream_close(struct fy_memstream *fyms, size_t *sizep)
+{
+ char *buf;
+#if defined(_WIN32)
+ long sz;
+#endif
+
+ if (!fyms) {
+ *sizep = 0;
+ return NULL;
+ }
+
+#if defined(_WIN32)
+ if (fyms->fp && fflush(fyms->fp) == 0 &&
+ (sz = ftell(fyms->fp)) >= 0 &&
+ (fyms->buf = malloc((size_t)sz + 1)) != NULL) {
+ rewind(fyms->fp);
+ fyms->size = fread(fyms->buf, 1, (size_t)sz, fyms->fp);
+ fyms->buf[fyms->size] = '\0';
+ }
+#endif
+
+ if (fyms->fp)
+ fclose(fyms->fp);
+
+ /* the buffer is updated only after close */
+ buf = fyms->buf;
+ *sizep = buf ? fyms->size : 0;
+
+ free(fyms);
+
+ return buf;
+}
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
-#include <unistd.h>
-#include <termios.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <termios.h>
#include <sys/uio.h>
+#endif
+
+#include "fy-win32.h"
/*
* Define FY_CPP_SHORT_NAMES to use shortened macro names in the implementation.
#define FY_BIT(x) (1U << (x))
#endif
+/* MSVC doesn't support __attribute__, so disable it */
+#if defined(_MSC_VER) && !defined(__clang__)
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
#if defined(__linux__)
#include <sys/sysmacros.h>
#endif
int fy_tag_scan(const char *data, size_t len, struct fy_tag_scan_info *info);
+/* container_of - use a fallback for MSVC which doesn't support typeof */
#ifndef container_of
+#if defined(_MSC_VER)
+#define container_of(ptr, type, member) \
+ ((type *)((char *)(ptr) - offsetof(type, member)))
+#else
#define container_of(ptr, type, member) \
({ \
const __typeof__(((type *)0)->member) *__mptr = (ptr); \
(type *)((void *)__mptr - offsetof(type,member)); \
})
-#endif
+#endif /* _MSC_VER */
+#endif /* container_of */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) ((sizeof(x)/sizeof((x)[0])))
#endif
-#if defined(NDEBUG) && (defined(__GNUC__) && __GNUC__ >= 4)
+/* even if we're compiling for windows with _MSC_VER defined, clang-cl has attributes */
+#if (defined(__GNUC__) && __GNUC__ >= 4) || defined(__clang__)
+#define FY_HAS_GCC_ATTRIBUTES
+#else
+#undef FY_HAS_GCC_ATTRIBUTES
+#endif
+
+#if defined(FY_HAS_GCC_ATTRIBUTES) && defined(NDEBUG)
#define FY_ALWAYS_INLINE __attribute__((always_inline))
#else
#define FY_ALWAYS_INLINE /* nothing */
#endif
-#if defined(__GNUC__) && __GNUC__ >= 4
+#if defined(FY_HAS_GCC_ATTRIBUTES)
#define FY_UNUSED __attribute__((unused))
#else
#define FY_UNUSED /* nothing */
#endif
-#if defined(NDEBUG) && defined(__GNUC__) && __GNUC__ >= 4
+#if defined(FY_HAS_GCC_ATTRIBUTES) && defined(NDEBUG)
#define FY_DEBUG_UNUSED __attribute__((unused))
#else
#define FY_DEBUG_UNUSED /* nothing */
#endif
-#if defined(__GNUC__) && __GNUC__ >= 4
+#if defined(FY_HAS_GCC_ATTRIBUTES)
#define FY_CONSTRUCTOR __attribute__((constructor))
#define FY_DESTRUCTOR __attribute__((destructor))
#define FY_HAS_CONSTRUCTOR
return (size + (align - 1)) & ~(align - 1);
}
-int fy_term_set_raw(int fd, struct termios *oldt);
-int fy_term_restore(int fd, const struct termios *oldt);
-ssize_t fy_term_write(int fd, const void *data, size_t count);
-int fy_term_safe_write(int fd, const void *data, size_t count);
-ssize_t fy_term_read(int fd, void *data, size_t count, int timeout_us);
-ssize_t fy_term_read_escape(int fd, void *buf, size_t count);
-
-/* the raw methods require the terminal to be in raw mode */
-int fy_term_query_size_raw(int fd, int *rows, int *cols);
-
-/* the non raw methods will set the terminal to raw and then restore */
+/* this is expected to be supported */
int fy_term_query_size(int fd, int *rows, int *cols);
struct fy_comment_iter {
#endif
/* true, if types are the same, false otherwise (depends on builtin_types_compatible_p) */
+#if !defined(_MSC_VER) && defined(__has_builtin)
#if __has_builtin(__builtin_types_compatible_p)
#define FY_SAME_TYPE(_a, _b) __builtin_types_compatible_p(__typeof__(_a), __typeof__(_b))
-#else
+#endif
+#endif
+#ifndef FY_SAME_TYPE
#define FY_SAME_TYPE(_a, _b) true
#endif
FY_COMPILE_ERROR_ON_ZERO(!FY_SAME_TYPE(_a, _b))
/* type safe add overflow */
+#if !defined(_MSC_VER) && defined(__has_builtin)
#if __has_builtin(__builtin_add_overflow)
#define FY_ADD_OVERFLOW __builtin_add_overflow
-#else
+#endif
+#endif
+#ifdef _MSC_VER
+/* MSVC: simple implementation, returns false (no overflow detection) */
+#define FY_ADD_OVERFLOW(_a, _b, _resp) ((void)((*(_resp) = (_a) + (_b))), false)
+#elif !defined(FY_ADD_OVERFLOW)
#define FY_ADD_OVERFLOW(_a, _b, _resp) \
({ \
__typeof__(_a) __a = (_a), __res; \
#endif
/* type safe sub overflow */
+#if !defined(_MSC_VER) && defined(__has_builtin)
#if __has_builtin(__builtin_sub_overflow)
#define FY_SUB_OVERFLOW __builtin_sub_overflow
-#else
+#endif
+#endif
+#ifdef _MSC_VER
+/* MSVC: simple implementation, returns false (no overflow detection) */
+#define FY_SUB_OVERFLOW(_a, _b, _resp) ((void)((*(_resp) = (_a) - (_b))), false)
+#elif !defined(FY_SUB_OVERFLOW)
#define FY_SUB_OVERFLOW(_a, _b, _resp) \
({ \
__typeof__(_a) __a = (_a), __res; \
#endif
/* type safe multiply overflow */
+#if !defined(_MSC_VER) && defined(__has_builtin)
#if __has_builtin(__builtin_mul_overflow)
#define FY_MUL_OVERFLOW __builtin_mul_overflow
-#else
+#endif
+#endif
+#ifdef _MSC_VER
+/* MSVC: simple implementation, returns false (no overflow detection) */
+#define FY_MUL_OVERFLOW(_a, _b, _resp) ((void)((*(_resp) = (_a) * (_b))), false)
+#elif !defined(FY_MUL_OVERFLOW)
#define FY_MUL_OVERFLOW(_a, _b, _resp) \
({ \
__typeof__(_a) __a = (_a), __res; \
}
/* alloca formatted print methods */
+#ifdef _MSC_VER
+/*
+ * MSVC doesn't support GCC statement expressions, so we provide
+ * function-based alternatives. These use a static thread-local buffer
+ * which is less flexible but works for typical use cases.
+ */
+#define FY_ALLOCA_SPRINTF_BUFSZ 4096
+
+static __declspec(thread) char fy_alloca_sprintf_buf[FY_ALLOCA_SPRINTF_BUFSZ];
+
+static inline char *fy_alloca_vsprintf_impl(const char *fmt, va_list ap)
+{
+ va_list ap_copy;
+ int len;
+ char *s;
+
+ va_copy(ap_copy, ap);
+ len = vsnprintf(fy_alloca_sprintf_buf, FY_ALLOCA_SPRINTF_BUFSZ, fmt, ap_copy);
+ va_end(ap_copy);
+ if (len < 0)
+ return NULL;
+ /* strip trailing newlines */
+ s = fy_alloca_sprintf_buf + strlen(fy_alloca_sprintf_buf);
+ while (s > fy_alloca_sprintf_buf && s[-1] == '\n')
+ *--s = '\0';
+ return fy_alloca_sprintf_buf;
+}
+
+/* For MSVC, we can't use variadic macros that return values easily,
+ * so fy_vsprintfa needs a different approach
+ * This is not very efficient and wastes memory but it's the best
+ * we can do with the potato compiler
+ */
+#define fy_vsprintfa(_fmt, _ap) \
+ strcpy(alloca(FY_ALLOCA_SPRINTF_BUFSZ + 1), \
+ fy_alloca_vsprintf_impl((_fmt), (_ap)))
+#define fy_sprintfa(_fmt, ...) \
+ strcpy(alloca(FY_ALLOCA_SPRINTF_BUFSZ + 1), \
+ (snprintf(fy_alloca_sprintf_buf, FY_ALLOCA_SPRINTF_BUFSZ, (_fmt), __VA_ARGS__) < 0 ? \
+ "" : fy_alloca_sprintf_buf))
+#else
+/* GCC/Clang version with statement expressions */
#define fy_vsprintfa(_fmt, _ap) \
({ \
const char *__fmt = (_fmt); \
(void)snprintf(_buf, _size + 1, __fmt, __VA_ARGS__); \
_buf; \
})
+#endif
#if !defined(NDEBUG) && defined(HAVE_DEVMODE) && HAVE_DEVMODE
#define FY_DEVMODE
#undef FY_DEVMODE
#endif
-#ifdef FY_DEVMODE
-#define __FY_DEBUG_UNUSED__ /* nothing */
-#else
-#if defined(__GNUC__) && __GNUC__ >= 4
+#if defined(FY_HAS_GCC_ATTRIBUTES) && !defined(FY_DEVMODE)
#define __FY_DEBUG_UNUSED__ __attribute__((__unused__))
#else
#define __FY_DEBUG_UNUSED__ /* nothing */
#endif
-#endif
// C preprocessor magic follows (pilfered and adapted from h4x0r.org)
size_t size;
int i;
- for (i = 0; i < iovcnt; i++, dst += size) {
+ for (i = 0; i < iovcnt; i++, dst = (void *)((char *)dst + size)) {
size = iov[i].iov_len;
memcpy(dst, iov[i].iov_base, size);
}
size_t size;
int i;
- for (i = 0; i < iovcnt; i++, src += size) {
+ for (i = 0; i < iovcnt; i++, src = (const void *)((const char *)src + size)) {
size = iov[i].iov_len;
memcpy(iov[i].iov_base, src, size);
}
size_t size;
int i, ret;
- for (i = 0; i < iovcnt; i++) {
+ for (i = 0; i < iovcnt; i++, s = (const void *)((const char *)s + size)) {
size = iov[i].iov_len;
ret = memcmp(iov[i].iov_base, s, size);
if (ret)
return ret;
- s += size;
}
return 0;
}
#define FY_HAVE_NESTED_FUNC_LAMBDAS
#endif
+/* wrapper for memstream, on all platforms */
+struct fy_memstream; // opaque
+
+struct fy_memstream *fy_memstream_open(FILE **fpp);
+char *fy_memstream_close(struct fy_memstream *fyms, size_t *sizep);
+
#endif
--- /dev/null
+/*
+ * fy-win32.h - Windows compatibility layer
+ *
+ * Copyright (c) 2024-2026 libfyaml contributors
+ *
+ * SPDX-License-Identifier: MIT
+ *
+ * This header provides Unix-like APIs on Windows to allow libfyaml to
+ * build and run on Windows platforms.
+ */
+#ifndef FY_WIN32_H
+#define FY_WIN32_H
+
+#ifdef _WIN32
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#ifndef _CRT_SECURE_NO_WARNINGS
+#define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include <windows.h>
+/* Undefine Windows macros that conflict with common identifiers */
+#ifdef near
+#undef near
+#endif
+#ifdef far
+#undef far
+#endif
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <direct.h>
+#include <process.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <stdarg.h>
+#include <malloc.h>
+
+/* ssize_t is not defined on Windows */
+#ifndef _SSIZE_T_DEFINED
+#define _SSIZE_T_DEFINED
+#ifdef _WIN64
+typedef __int64 ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#endif
+
+/* Provide SSIZE_MAX if not defined */
+#ifndef SSIZE_MAX
+#ifdef _WIN64
+#define SSIZE_MAX _I64_MAX
+#else
+#define SSIZE_MAX INT_MAX
+#endif
+#endif
+
+/*
+ * Memory mapping emulation using Windows Virtual Memory APIs
+ */
+
+/* mmap protection flags */
+#ifndef PROT_NONE
+#define PROT_NONE 0x0
+#define PROT_READ 0x1
+#define PROT_WRITE 0x2
+#define PROT_EXEC 0x4
+#endif
+
+/* mmap flags */
+#ifndef MAP_SHARED
+#define MAP_SHARED 0x01
+#define MAP_PRIVATE 0x02
+#define MAP_ANONYMOUS 0x20
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FAILED ((void *)-1)
+#endif
+
+static inline void *fy_win32_mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
+{
+ DWORD flProtect = 0;
+ DWORD dwDesiredAccess = 0;
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ HANDLE hMapping = NULL;
+ void *ptr = NULL;
+
+ (void)addr; /* Hint address is ignored */
+
+ /* Anonymous mapping - use VirtualAlloc */
+ if (flags & MAP_ANONYMOUS) {
+ DWORD flAllocationType = MEM_RESERVE | MEM_COMMIT;
+ DWORD flAllocProtect = 0;
+
+ if (prot == PROT_NONE)
+ flAllocProtect = PAGE_NOACCESS;
+ else if (prot & PROT_EXEC) {
+ if (prot & PROT_WRITE)
+ flAllocProtect = PAGE_EXECUTE_READWRITE;
+ else
+ flAllocProtect = PAGE_EXECUTE_READ;
+ } else if (prot & PROT_WRITE)
+ flAllocProtect = PAGE_READWRITE;
+ else
+ flAllocProtect = PAGE_READONLY;
+
+ ptr = VirtualAlloc(NULL, length, flAllocationType, flAllocProtect);
+ if (!ptr)
+ return MAP_FAILED;
+ return ptr;
+ }
+
+ /* File mapping */
+ if (fd < 0) {
+ errno = EBADF;
+ return MAP_FAILED;
+ }
+
+ hFile = (HANDLE)_get_osfhandle(fd);
+ if (hFile == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return MAP_FAILED;
+ }
+
+ /* Set protection and access flags */
+ if (prot == PROT_NONE) {
+ flProtect = PAGE_NOACCESS;
+ dwDesiredAccess = 0;
+ } else if (prot & PROT_EXEC) {
+ if (prot & PROT_WRITE) {
+ flProtect = PAGE_EXECUTE_READWRITE;
+ dwDesiredAccess = FILE_MAP_WRITE | FILE_MAP_EXECUTE;
+ } else {
+ flProtect = PAGE_EXECUTE_READ;
+ dwDesiredAccess = FILE_MAP_READ | FILE_MAP_EXECUTE;
+ }
+ } else if (prot & PROT_WRITE) {
+ if (flags & MAP_PRIVATE) {
+ flProtect = PAGE_WRITECOPY;
+ dwDesiredAccess = FILE_MAP_COPY;
+ } else {
+ flProtect = PAGE_READWRITE;
+ dwDesiredAccess = FILE_MAP_WRITE;
+ }
+ } else {
+ flProtect = PAGE_READONLY;
+ dwDesiredAccess = FILE_MAP_READ;
+ }
+
+ hMapping = CreateFileMapping(hFile, NULL, flProtect, 0, 0, NULL);
+ if (!hMapping) {
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+
+ ptr = MapViewOfFile(hMapping, dwDesiredAccess,
+ (DWORD)((uint64_t)offset >> 32), (DWORD)offset, length);
+ CloseHandle(hMapping);
+
+ if (!ptr) {
+ errno = ENOMEM;
+ return MAP_FAILED;
+ }
+
+ return ptr;
+}
+
+static inline int fy_win32_munmap(void *addr, size_t length)
+{
+ (void)length;
+
+ /*
+ * We try both VirtualFree (for anonymous mappings) and
+ * UnmapViewOfFile (for file mappings). One of them will succeed.
+ */
+ if (UnmapViewOfFile(addr))
+ return 0;
+ if (VirtualFree(addr, 0, MEM_RELEASE))
+ return 0;
+
+ errno = EINVAL;
+ return -1;
+}
+
+/* Define mmap/munmap macros that use our implementations */
+#define mmap(addr, length, prot, flags, fd, offset) \
+ fy_win32_mmap(addr, length, prot, flags, fd, offset)
+#define munmap(addr, length) \
+ fy_win32_munmap(addr, length)
+
+/* mremap is not supported on Windows - will never be defined */
+
+/*
+ * File descriptor operations
+ */
+
+/* open() flags that may be missing */
+#ifndef O_RDONLY
+#define O_RDONLY _O_RDONLY
+#endif
+#ifndef O_WRONLY
+#define O_WRONLY _O_WRONLY
+#endif
+#ifndef O_RDWR
+#define O_RDWR _O_RDWR
+#endif
+#ifndef O_CREAT
+#define O_CREAT _O_CREAT
+#endif
+#ifndef O_TRUNC
+#define O_TRUNC _O_TRUNC
+#endif
+#ifndef O_APPEND
+#define O_APPEND _O_APPEND
+#endif
+#ifndef O_BINARY
+#define O_BINARY _O_BINARY
+#endif
+
+/* Standard file descriptor numbers */
+#ifndef STDIN_FILENO
+#define STDIN_FILENO 0
+#endif
+#ifndef STDOUT_FILENO
+#define STDOUT_FILENO 1
+#endif
+#ifndef STDERR_FILENO
+#define STDERR_FILENO 2
+#endif
+
+static inline int fy_win32_open(const char *pathname, int flags, ...)
+{
+ /* always use O_BINARY to avoid CRLF mangling */
+ return _open(pathname, flags | O_BINARY);
+}
+
+/* Use _open, _close on Windows */
+#ifndef open
+#define open fy_win32_open
+#endif
+#ifndef close
+#define close _close
+#endif
+
+/*
+ * Windows _read/_write use unsigned int (32-bit) for count.
+ * Provide wrappers that handle size_t properly by chunking large I/O.
+ */
+static inline ssize_t fy_win32_read(int fd, void *buf, size_t count)
+{
+ unsigned char *p = (unsigned char *)buf;
+ size_t remaining = count;
+ ssize_t total = 0;
+
+ while (remaining > 0) {
+ unsigned int chunk = (remaining > UINT_MAX) ? UINT_MAX : (unsigned int)remaining;
+ int ret = _read(fd, p, chunk);
+ if (ret < 0)
+ return total > 0 ? total : -1;
+ if (ret == 0)
+ break;
+ total += ret;
+ p += ret;
+ remaining -= ret;
+ if ((unsigned int)ret < chunk)
+ break; /* short read */
+ }
+ return total;
+}
+
+static inline ssize_t fy_win32_write(int fd, const void *buf, size_t count)
+{
+ const unsigned char *p = (const unsigned char *)buf;
+ size_t remaining = count;
+ ssize_t total = 0;
+
+ while (remaining > 0) {
+ unsigned int chunk = (remaining > UINT_MAX) ? UINT_MAX : (unsigned int)remaining;
+ int ret = _write(fd, p, chunk);
+ if (ret < 0)
+ return total > 0 ? total : -1;
+ if (ret == 0)
+ break;
+ total += ret;
+ p += ret;
+ remaining -= ret;
+ if ((unsigned int)ret < chunk)
+ break; /* short write */
+ }
+ return total;
+}
+
+#ifndef read
+#define read fy_win32_read
+#endif
+#ifndef write
+#define write fy_win32_write
+#endif
+#ifndef lseek
+#define lseek _lseek
+#endif
+#ifndef fileno
+#define fileno _fileno
+#endif
+#ifndef fdopen
+#define fdopen _fdopen
+#endif
+#ifndef dup
+#define dup _dup
+#endif
+#ifndef dup2
+#define dup2 _dup2
+#endif
+#ifndef access
+#define access _access
+#endif
+
+/* stat structure and functions */
+#ifndef stat
+#define stat _stat64
+#endif
+#ifndef fstat
+#define fstat _fstat64
+#endif
+
+#ifndef isatty
+
+static inline int
+fy_win32_isatty(int fd)
+{
+ HANDLE h;
+ DWORD mode;
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE || h == NULL)
+ return 0;
+
+ return GetConsoleMode(h, &mode) != 0;
+}
+
+#define isatty(fd) fy_win32_isatty(fd)
+#endif
+
+/* S_ISREG and S_ISDIR macros */
+#ifndef S_ISREG
+#define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+#endif
+#ifndef S_ISDIR
+#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+#endif
+#ifndef S_IFREG
+#define S_IFREG _S_IFREG
+#endif
+#ifndef S_IFMT
+#define S_IFMT _S_IFMT
+#endif
+
+/* Unix file permission macros - Windows doesn't have these */
+#ifndef S_IRUSR
+#define S_IRUSR _S_IREAD
+#endif
+#ifndef S_IWUSR
+#define S_IWUSR _S_IWRITE
+#endif
+#ifndef S_IXUSR
+#define S_IXUSR _S_IEXEC
+#endif
+/* Group/other permissions don't exist on Windows, define as 0 */
+#ifndef S_IRGRP
+#define S_IRGRP 0
+#endif
+#ifndef S_IWGRP
+#define S_IWGRP 0
+#endif
+#ifndef S_IXGRP
+#define S_IXGRP 0
+#endif
+#ifndef S_IROTH
+#define S_IROTH 0
+#endif
+#ifndef S_IWOTH
+#define S_IWOTH 0
+#endif
+#ifndef S_IXOTH
+#define S_IXOTH 0
+#endif
+
+/*
+ * System configuration - sysconf() emulation
+ */
+#ifndef _SC_PAGESIZE
+#define _SC_PAGESIZE 1
+#endif
+#ifndef _SC_NPROCESSORS_ONLN
+#define _SC_NPROCESSORS_ONLN 2
+#endif
+
+static inline long fy_win32_sysconf(int name)
+{
+ SYSTEM_INFO si;
+
+ switch (name) {
+ case _SC_PAGESIZE:
+ GetSystemInfo(&si);
+ return (long)si.dwPageSize;
+ case _SC_NPROCESSORS_ONLN:
+ GetSystemInfo(&si);
+ return (long)si.dwNumberOfProcessors;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+}
+
+#define sysconf(name) fy_win32_sysconf(name)
+
+/*
+ * asprintf() implementation for Windows
+ */
+#ifndef HAVE_ASPRINTF
+
+static inline int fy_win32_vasprintf(char **strp, const char *fmt, va_list ap)
+{
+ int len;
+ va_list ap_copy;
+
+ va_copy(ap_copy, ap);
+ len = _vscprintf(fmt, ap_copy);
+ va_end(ap_copy);
+
+ if (len < 0) {
+ *strp = NULL;
+ return -1;
+ }
+
+ *strp = (char *)malloc(len + 1);
+ if (!*strp)
+ return -1;
+
+ len = vsprintf(*strp, fmt, ap);
+ if (len < 0) {
+ free(*strp);
+ *strp = NULL;
+ return -1;
+ }
+
+ return len;
+}
+
+static inline int fy_win32_asprintf(char **strp, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = fy_win32_vasprintf(strp, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+#define asprintf fy_win32_asprintf
+#define vasprintf fy_win32_vasprintf
+
+#endif /* HAVE_ASPRINTF */
+
+/*
+ * Directory functions
+ */
+#ifndef getcwd
+#define getcwd _getcwd
+#endif
+#ifndef mkdir
+#define mkdir(path, mode) _mkdir(path)
+#endif
+#ifndef rmdir
+#define rmdir _rmdir
+#endif
+#ifndef chdir
+#define chdir _chdir
+#endif
+
+/*
+ * Process functions
+ */
+#ifndef getpid
+#define getpid _getpid
+#endif
+
+/*
+ * String functions
+ */
+#ifndef strcasecmp
+#define strcasecmp _stricmp
+#endif
+#ifndef strncasecmp
+#define strncasecmp _strnicmp
+#endif
+#ifndef strdup
+#define strdup _strdup
+#endif
+
+/*
+ * Sleep functions
+ */
+static inline unsigned int fy_win32_sleep(unsigned int seconds)
+{
+ Sleep(seconds * 1000);
+ return 0;
+}
+
+static inline int fy_win32_usleep(unsigned int usec)
+{
+ HANDLE timer;
+ LARGE_INTEGER ft;
+
+ ft.QuadPart = -(10 * (LONGLONG)usec);
+ timer = CreateWaitableTimer(NULL, TRUE, NULL);
+ if (!timer)
+ return -1;
+ SetWaitableTimer(timer, &ft, 0, NULL, NULL, 0);
+ WaitForSingleObject(timer, INFINITE);
+ CloseHandle(timer);
+ return 0;
+}
+
+#define sleep(s) fy_win32_sleep(s)
+#define usleep(us) fy_win32_usleep(us)
+
+/*
+ * clock_gettime emulation for Windows
+ */
+#ifndef CLOCK_MONOTONIC
+#define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+#endif
+
+/*
+ * struct timespec is defined in UCRT's time.h for MSVC 2015+ (VS2015+)
+ * time.h is included above to ensure it's available.
+ */
+
+static inline int fy_win32_clock_gettime(int clock_id, struct timespec *tp)
+{
+ LARGE_INTEGER freq, count;
+ FILETIME ft;
+ ULARGE_INTEGER uli;
+
+ if (clock_id == CLOCK_MONOTONIC) {
+ if (!QueryPerformanceFrequency(&freq))
+ return -1;
+ if (!QueryPerformanceCounter(&count))
+ return -1;
+ tp->tv_sec = (time_t)(count.QuadPart / freq.QuadPart);
+ tp->tv_nsec = (long)((count.QuadPart % freq.QuadPart) * 1000000000LL / freq.QuadPart);
+ } else {
+ /* CLOCK_REALTIME */
+ GetSystemTimeAsFileTime(&ft);
+ uli.LowPart = ft.dwLowDateTime;
+ uli.HighPart = ft.dwHighDateTime;
+ /* FILETIME is 100-nanosecond intervals since January 1, 1601 */
+ /* Convert to Unix epoch (seconds since January 1, 1970) */
+ uli.QuadPart -= 116444736000000000ULL;
+ tp->tv_sec = (time_t)(uli.QuadPart / 10000000ULL);
+ tp->tv_nsec = (long)((uli.QuadPart % 10000000ULL) * 100);
+ }
+ return 0;
+}
+
+#define clock_gettime(clock_id, tp) fy_win32_clock_gettime(clock_id, tp)
+
+/*
+ * EAGAIN may be different from EWOULDBLOCK on some systems
+ */
+#ifndef EAGAIN
+#define EAGAIN EWOULDBLOCK
+#endif
+
+/*
+ * alloca is available as _alloca on Windows
+ */
+#ifndef alloca
+#define alloca _alloca
+#endif
+
+/*
+ * iovec structure for scatter/gather I/O
+ * Defined here since sys/uio.h doesn't exist on Windows
+ */
+#ifndef _FY_IOVEC_DEFINED
+#define _FY_IOVEC_DEFINED
+struct iovec {
+ void *iov_base; /* Starting address */
+ size_t iov_len; /* Number of bytes to transfer */
+};
+#endif
+
+#if defined(_MSC_VER) && !defined(__clang__)
+typedef union {
+ void* p;
+ double d;
+ __int64 i64;
+} max_align_t;
+#endif
+
+#endif /* _WIN32 */
+
+#endif /* FY_WIN32_H */
#include "config.h"
#endif
+/* Valgrind is not available on Windows */
+#ifdef _WIN32
+
+static inline void fy_valgrind_check(int *argcp, char ***argvp)
+{
+ (void)argcp;
+ (void)argvp;
+}
+
+#else /* !_WIN32 */
+
#include <stdlib.h>
#include <string.h>
#include <assert.h>
fprintf(stderr, "warning: failed to start valgrind, continue without");
}
-#endif
+#endif /* !_WIN32 */
+
+#endif /* FY_VALGRIND_H */
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH128_digest_endian(state_in, XXH_littleEndian, (unsigned long long*)out);
+ XXH128_digest_endian(state_in, XXH_littleEndian, (unsigned long long*)out);
else
- return XXH128_digest_endian(state_in, XXH_bigEndian, (unsigned long long*)out);
+ XXH128_digest_endian(state_in, XXH_bigEndian, (unsigned long long*)out);
}
XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
- return XXH256_digest_endian(state_in, XXH_littleEndian, (unsigned long long*)out);
+ XXH256_digest_endian(state_in, XXH_littleEndian, (unsigned long long*)out);
else
- return XXH256_digest_endian(state_in, XXH_bigEndian, (unsigned long long*)out);
+ XXH256_digest_endian(state_in, XXH_bigEndian, (unsigned long long*)out);
}
EXTRA_DIST = test-env $(TESTS)
-# Add the error test files
-EXTRA_DIST += \
- test-errors/0002/=== \
- test-errors/0002/in.yaml \
- test-errors/0002/test.error \
- test-errors/0003/=== \
- test-errors/0003/in.yaml \
- test-errors/0003/test.error \
- test-errors/0004/=== \
- test-errors/0004/in.yaml \
- test-errors/0004/test.error \
- test-errors/0005/=== \
- test-errors/0005/in.yaml \
- test-errors/0005/test.error \
- test-errors/0006/=== \
- test-errors/0006/in.yaml \
- test-errors/0006/test.error \
- test-errors/0007/=== \
- test-errors/0007/in.yaml \
- test-errors/0007/test.error \
- test-errors/0008/=== \
- test-errors/0008/in.yaml \
- test-errors/0008/test.error \
- test-errors/0009/=== \
- test-errors/0009/in.yaml \
- test-errors/0009/test.error \
- test-errors/0010/=== \
- test-errors/0010/in.yaml \
- test-errors/0010/test.error \
- test-errors/0011/=== \
- test-errors/0011/in.yaml \
- test-errors/0011/test.error
-
-# Add the emitter test files
+# Add everyting
EXTRA_DIST += \
emitter-examples/anchors-1.yaml \
emitter-examples/anchors-2.yaml \
emitter-examples/anchors-3.yaml \
emitter-examples/anchors-4.1.yaml \
emitter-examples/anchors-4.yaml \
+ emitter-examples/anchors-on-empty-scalars.yaml \
emitter-examples/anchors-on-empty-scalars1.yaml \
emitter-examples/anchors-on-empty-scalars2.yaml \
emitter-examples/anchors-on-empty-scalars3.yaml \
emitter-examples/anchors-on-empty-scalars4.yaml \
- emitter-examples/anchors-on-empty-scalars.yaml \
emitter-examples/anchors.yaml \
emitter-examples/array.yaml \
+ emitter-examples/block.yaml \
emitter-examples/block2.yaml \
emitter-examples/block3.yaml \
emitter-examples/block4.yaml \
emitter-examples/block7.yaml \
emitter-examples/blocked.yaml \
emitter-examples/blockind.yaml \
- emitter-examples/block.yaml \
+ emitter-examples/c1.yaml \
emitter-examples/c10.yaml \
emitter-examples/c11.yaml \
emitter-examples/c12.yaml \
emitter-examples/c13.yaml \
- emitter-examples/c1.yaml \
emitter-examples/c2.yaml \
emitter-examples/c3.yaml \
emitter-examples/c4.yaml \
emitter-examples/c9.yaml \
emitter-examples/compact1.yaml \
emitter-examples/compactblockmap.yaml \
+ emitter-examples/complexkey.yaml \
emitter-examples/complexkey2.yaml \
emitter-examples/complexkey3.yaml \
emitter-examples/complexkey4.yaml \
emitter-examples/complexkey7.yaml \
emitter-examples/complexkey8.yaml \
emitter-examples/complexkey9.yaml \
- emitter-examples/complexkey.yaml \
emitter-examples/docstartend.yaml \
emitter-examples/dqscalar.yaml \
emitter-examples/dqzero.yaml \
emitter-examples/emptydoc.yaml \
emitter-examples/emptykey.yaml \
emitter-examples/emptystream.yaml \
+ emitter-examples/flow.yaml \
emitter-examples/flow1.yaml \
emitter-examples/flow2.yaml \
- emitter-examples/flow.yaml \
+ emitter-examples/fold-tricky.yaml \
+ emitter-examples/fold.yaml \
emitter-examples/fold2.yaml \
emitter-examples/fold3.yaml \
emitter-examples/fold4.yaml \
emitter-examples/fold5.yaml \
- emitter-examples/folded2.yaml \
+ emitter-examples/folded-endbreaks.yaml \
emitter-examples/folded.yaml \
+ emitter-examples/folded2.yaml \
emitter-examples/folding.yaml \
- emitter-examples/fold.yaml \
emitter-examples/global-tag.yaml \
emitter-examples/invoice.yaml \
emitter-examples/json.yaml \
emitter-examples/keyflow.yaml \
- emitter-examples/keykey2.yaml \
emitter-examples/keykey.yaml \
+ emitter-examples/keykey2.yaml \
emitter-examples/line.yaml \
+ emitter-examples/literal-endbreaks.yaml \
+ emitter-examples/literal.yaml \
emitter-examples/literal1.yaml \
emitter-examples/literal2.yaml \
emitter-examples/literal3.yaml \
emitter-examples/literal4.yaml \
- emitter-examples/literal.yaml \
emitter-examples/mapping.yaml \
emitter-examples/mergekeyspec.yaml \
emitter-examples/multi-document.yaml \
emitter-examples/multiline-quoted-key.yaml \
emitter-examples/multiline-simple-key.yaml \
- emitter-examples/nodeprop2.yaml \
emitter-examples/nodeprop.yaml \
+ emitter-examples/nodeprop2.yaml \
emitter-examples/numbers-flow.yaml \
emitter-examples/numbers.yaml \
- emitter-examples/plainlines.yaml \
emitter-examples/plain-scalars-with-commas.yaml \
+ emitter-examples/plainlines.yaml \
emitter-examples/plainscalar.yaml \
- emitter-examples/quotedbackslash.yaml \
emitter-examples/quoted.yaml \
+ emitter-examples/quotedbackslash.yaml \
emitter-examples/scalar-multiline.yaml \
- emitter-examples/scalars2.yaml \
emitter-examples/scalar-singlequoted.yaml \
- emitter-examples/scalar-space1.yaml \
emitter-examples/scalar-space.yaml \
+ emitter-examples/scalar-space1.yaml \
emitter-examples/scalars.yaml \
+ emitter-examples/scalars2.yaml \
+ emitter-examples/scanner-c-1.yaml \
emitter-examples/scanner-c-10.yaml \
emitter-examples/scanner-c-11.yaml \
emitter-examples/scanner-c-12.yaml \
emitter-examples/scanner-c-13.yaml \
- emitter-examples/scanner-c-1.yaml \
emitter-examples/scanner-c-2.yaml \
emitter-examples/scanner-c-3.yaml \
emitter-examples/scanner-c-4.yaml \
emitter-examples/scanner-c-8-2.yaml \
emitter-examples/scanner-c-8.yaml \
emitter-examples/scanner-c-9.yaml \
+ emitter-examples/seq.yaml \
emitter-examples/seq1.yaml \
emitter-examples/seq2.yaml \
emitter-examples/seq3.yaml \
emitter-examples/seq4.yaml \
emitter-examples/seq5.yaml \
emitter-examples/seq6.yaml \
- emitter-examples/seq.yaml \
emitter-examples/sets.yaml \
+ emitter-examples/simple.yaml \
emitter-examples/simple1.yaml \
emitter-examples/simple2.yaml \
+ emitter-examples/simpleanchor.yaml \
emitter-examples/simpleanchor1.yaml \
emitter-examples/simpleanchor2.yaml \
emitter-examples/simpleanchor3.yaml \
emitter-examples/simpleanchor4.yaml \
- emitter-examples/simpleanchor.yaml \
emitter-examples/simplefolded.yaml \
+ emitter-examples/simplekey.yaml \
emitter-examples/simplekey1.yaml \
emitter-examples/simplekey2.yaml \
emitter-examples/simplekey3.yaml \
emitter-examples/simplekey4.yaml \
emitter-examples/simplekey5.yaml \
- emitter-examples/simplekey.yaml \
emitter-examples/simpleliteral.yaml \
- emitter-examples/simpleseq1.yaml \
emitter-examples/simpleseq.yaml \
- emitter-examples/simple.yaml \
- emitter-examples/singlepairimp2.yaml \
+ emitter-examples/simpleseq1.yaml \
emitter-examples/singlepairimp.yaml \
- emitter-examples/sqscalarspace.yaml \
+ emitter-examples/singlepairimp2.yaml \
emitter-examples/sqscalar.yaml \
+ emitter-examples/sqscalarspace.yaml \
emitter-examples/strings.yaml \
+ emitter-examples/t.yaml \
emitter-examples/t1.yaml \
emitter-examples/t2.yaml \
emitter-examples/t3.yaml \
emitter-examples/tagesc.yaml \
emitter-examples/tags-1.yaml \
emitter-examples/tags.yaml \
+ emitter-examples/test.yaml \
emitter-examples/test1.yaml \
emitter-examples/test2.yaml \
- emitter-examples/test.yaml \
- emitter-examples/t.yaml \
+ emitter-examples/u.yaml \
emitter-examples/u1.yaml \
emitter-examples/u2.yaml \
emitter-examples/u3.yaml \
emitter-examples/utf8-simple.yaml \
emitter-examples/utf8.yaml \
- emitter-examples/u.yaml \
+ emitter-examples/v.yaml \
emitter-examples/v1.yaml \
emitter-examples/v2.yaml \
emitter-examples/version.yaml \
- emitter-examples/v.yaml \
emitter-examples/weirdplain.yaml \
emitter-examples/ws0.yaml \
emitter-examples/ws1.yaml \
emitter-examples/ws2.yaml \
emitter-examples/ws3.yaml \
- emitter-examples/yaml-version.yaml \
emitter-examples/y.yaml \
+ emitter-examples/yaml-version.yaml \
emitter-examples/yy.yaml \
- emitter-examples/zeroexplicit.yaml
+ emitter-examples/zeroexplicit.yaml \
+ test-errors/0002/=== \
+ test-errors/0002/in.yaml \
+ test-errors/0002/test.error \
+ test-errors/0003/=== \
+ test-errors/0003/in.yaml \
+ test-errors/0003/test.error \
+ test-errors/0004/=== \
+ test-errors/0004/in.yaml \
+ test-errors/0004/test.error \
+ test-errors/0005/=== \
+ test-errors/0005/in.yaml \
+ test-errors/0005/test.error \
+ test-errors/0006/=== \
+ test-errors/0006/in.yaml \
+ test-errors/0006/test.error \
+ test-errors/0007/=== \
+ test-errors/0007/in.yaml \
+ test-errors/0007/test.error \
+ test-errors/0008/=== \
+ test-errors/0008/in.yaml \
+ test-errors/0008/test.error \
+ test-errors/0009/=== \
+ test-errors/0009/in.yaml \
+ test-errors/0009/test.error \
+ test-errors/0010/=== \
+ test-errors/0010/in.yaml \
+ test-errors/0010/test.error \
+ test-errors/0011/=== \
+ test-errors/0011/in.yaml \
+ test-errors/0011/test.error
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <check.h>
{
#undef MANUAL_SCALAR_ESC
#undef MANUAL_SCALAR_ESC_TXT
-#define MANUAL_SCALAR_ESC "\\\"\0\a\b\t\v\f\r\e\xc2\x85\xc2\xa0\xe2\x80\xa8\xe2\x80\xa9"
+#define MANUAL_SCALAR_ESC "\\\"\0\a\b\t\v\f\r\x1b\xc2\x85\xc2\xa0\xe2\x80\xa8\xe2\x80\xa9"
#define MANUAL_SCALAR_ESC_TXT "\"\\\\\\\"\\0\\a\\b\\t\\v\\f\\r\\e\\N\\_\\L\\P\""
const char *what = MANUAL_SCALAR_ESC;
size_t what_sz = sizeof(MANUAL_SCALAR_ESC) - 1;
}
END_TEST
+/* test style change on a plain */
+START_TEST(style_set_plain_scalar)
+{
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ enum fy_node_style style;
+ char *buf;
+
+ fyd = fy_document_build_from_string(NULL, "foo\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ fprintf(stderr, "--------------\n");
+ fprintf(stderr, "-- original --\n");
+ fprintf(stderr, "--------------\n");
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+ fprintf(stderr, "--------------\n");
+
+ fprintf(stderr, "-----------\n");
+ fprintf(stderr, "-- plain --\n");
+ fprintf(stderr, "-----------\n");
+ style = fy_node_set_style(fyn, FYNS_PLAIN);
+ ck_assert(style == FYNS_PLAIN);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "foo\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- single quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_SINGLE_QUOTED);
+ ck_assert(style == FYNS_SINGLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "'foo'\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- double quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_DOUBLE_QUOTED);
+ ck_assert(style == FYNS_DOUBLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "\"foo\"\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------\n");
+ fprintf(stderr, "-- literal --\n");
+ fprintf(stderr, "-------------\n");
+ style = fy_node_set_style(fyn, FYNS_LITERAL);
+ ck_assert(style == FYNS_LITERAL);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "|-\n foo\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ /* NOTE we don't try folded, because we never support emitting one */
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+/* test style change on a double quoted scalar which ends with colon */
+START_TEST(style_set_double_quoted_scalar_colon)
+{
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ enum fy_node_style style;
+ char *buf;
+
+ /* simple double quoted scalar that can't be a plain */
+ fyd = fy_document_build_from_string(NULL, "\"foo:\"\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ fprintf(stderr, "--------------\n");
+ fprintf(stderr, "-- original --\n");
+ fprintf(stderr, "--------------\n");
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+ fprintf(stderr, "--------------\n");
+
+ /* we can't convert to a plain, it ends with : */
+ fprintf(stderr, "-----------\n");
+ fprintf(stderr, "-- plain --\n");
+ fprintf(stderr, "-----------\n");
+ style = fy_node_set_style(fyn, FYNS_PLAIN);
+ ck_assert(style != FYNS_PLAIN);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- single quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_SINGLE_QUOTED);
+ ck_assert(style == FYNS_SINGLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "'foo:'\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- double quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_DOUBLE_QUOTED);
+ ck_assert(style == FYNS_DOUBLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "\"foo:\"\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ /* literal has no problem with it */
+ fprintf(stderr, "-------------\n");
+ fprintf(stderr, "-- literal --\n");
+ fprintf(stderr, "-------------\n");
+ style = fy_node_set_style(fyn, FYNS_LITERAL);
+ ck_assert(style == FYNS_LITERAL);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "|-\n foo:\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ /* NOTE we don't try folded, because we never support emitting one */
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+/* test style change on a double quoted scalar which contains a \0 */
+START_TEST(style_set_double_quoted_scalar_0)
+{
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ enum fy_node_style style;
+ char *buf;
+
+ /* simple double quoted scalar that can't be anything else */
+ fyd = fy_document_build_from_string(NULL, "\"foo\\0\"\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ fprintf(stderr, "--------------\n");
+ fprintf(stderr, "-- original --\n");
+ fprintf(stderr, "--------------\n");
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+ fprintf(stderr, "--------------\n");
+
+ /* we can't convert to a plain */
+ fprintf(stderr, "-----------\n");
+ fprintf(stderr, "-- plain --\n");
+ fprintf(stderr, "-----------\n");
+ style = fy_node_set_style(fyn, FYNS_PLAIN);
+ ck_assert(style != FYNS_PLAIN);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- single quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_SINGLE_QUOTED);
+ ck_assert(style != FYNS_SINGLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-------------------\n");
+ fprintf(stderr, "-- double quoted --\n");
+ fprintf(stderr, "-------------------\n");
+ style = fy_node_set_style(fyn, FYNS_DOUBLE_QUOTED);
+ ck_assert(style == FYNS_DOUBLE_QUOTED);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "\"foo\\0\"\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ /* literal has no problem with it */
+ fprintf(stderr, "-------------\n");
+ fprintf(stderr, "-- literal --\n");
+ fprintf(stderr, "-------------\n");
+ style = fy_node_set_style(fyn, FYNS_LITERAL);
+ ck_assert(style != FYNS_LITERAL);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ /* NOTE we don't try folded, because we never support emitting one */
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+/* test style change on a collection */
+START_TEST(style_set_collection)
+{
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ enum fy_node_style style;
+ char *buf;
+
+ fyd = fy_document_build_from_string(NULL, "- one\n- two\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ fprintf(stderr, "--------------\n");
+ fprintf(stderr, "-- original --\n");
+ fprintf(stderr, "--------------\n");
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ fprintf(stderr, "%s", buf);
+ free(buf);
+ fprintf(stderr, "--------------\n");
+
+ fprintf(stderr, "----------\n");
+ fprintf(stderr, "-- flow --\n");
+ fprintf(stderr, "----------\n");
+ style = fy_node_set_style(fyn, FYNS_FLOW);
+ ck_assert(style == FYNS_FLOW);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "[\n one,\n two\n]\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fprintf(stderr, "-----------\n");
+ fprintf(stderr, "-- block --\n");
+ fprintf(stderr, "-----------\n");
+ style = fy_node_set_style(fyn, FYNS_BLOCK);
+ ck_assert(style == FYNS_BLOCK);
+ buf = fy_emit_document_to_string(fyd, FYECF_DEFAULT);
+ ck_assert_ptr_ne(buf, NULL);
+ ck_assert_str_eq(buf, "- one\n- two\n");
+ fprintf(stderr, "%s", buf);
+ free(buf);
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
TCase *libfyaml_case_core(void)
{
TCase *tc;
tcase_add_test(tc, token_test);
+ tcase_add_test(tc, style_set_plain_scalar);
+ tcase_add_test(tc, style_set_double_quoted_scalar_colon);
+ tcase_add_test(tc, style_set_double_quoted_scalar_0);
+ tcase_add_test(tc, style_set_collection);
+
return tc;
}
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <check.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <check.h>
struct fy_document_iterator *fydi;
struct fy_node *fyn;
struct fy_token *fyt;
- char buf[256];
bool found_comment = false;
+ const char *comment;
/* Build document with comments */
fyd = fy_document_build_from_string(&cfg,
/* Try to get comments at different placements */
for (int placement = fycp_top; placement < fycp_max; placement++) {
- if (fy_token_get_comment(fyt, buf, sizeof(buf), placement)) {
- ck_assert_ptr_ne(buf, NULL);
- ck_assert_int_gt(strlen(buf), 0);
+ comment = fy_token_get_comment(fyt, placement);
+ if (comment) {
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_int_gt(strlen(comment), 0);
found_comment = true;
}
}
}
END_TEST
+START_TEST(parser_comments_0)
+{
+ struct fy_parse_cfg cfg;
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ const char *comment;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.flags = FYPCF_DEFAULT_DOC | FYPCF_PARSE_COMMENTS;
+
+ /* root scalar right comment */
+ fyd = fy_document_build_from_string(&cfg, "foo # right\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ /* no top */
+ comment = fy_node_get_comment(fyn, fycp_top);
+ ck_assert_ptr_eq(comment, NULL);
+
+ /* right */
+ comment = fy_node_get_comment(fyn, fycp_right);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "right"), NULL);
+
+ /* no bootm */
+ comment = fy_node_get_comment(fyn, fycp_bottom);
+ ck_assert_ptr_eq(comment, NULL);
+
+ /* all */
+ comment = fy_node_get_comments(fyn);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "right"), NULL);
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+START_TEST(parser_comments_1)
+{
+ struct fy_parse_cfg cfg;
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ const char *comment;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.flags = FYPCF_DEFAULT_DOC | FYPCF_PARSE_COMMENTS;
+
+ /* root scalar top & right comment */
+ fyd = fy_document_build_from_string(&cfg, "# top\nfoo # right\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ /* top */
+ comment = fy_node_get_comment(fyn, fycp_top);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top"), NULL);
+ ck_assert_ptr_eq(strstr(comment, "right"), NULL);
+
+ /* right */
+ comment = fy_node_get_comment(fyn, fycp_right);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_eq(strstr(comment, "top"), NULL);
+ ck_assert_ptr_ne(strstr(comment, "right"), NULL);
+
+ /* no bootm */
+ comment = fy_node_get_comment(fyn, fycp_bottom);
+ ck_assert_ptr_eq(comment, NULL);
+
+ /* all */
+ comment = fy_node_get_comments(fyn);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top"), NULL);
+ ck_assert_ptr_ne(strstr(comment, "right"), NULL);
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+START_TEST(parser_comments_2)
+{
+ struct fy_parse_cfg cfg;
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ const char *comment;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.flags = FYPCF_DEFAULT_DOC | FYPCF_PARSE_COMMENTS;
+
+ /* root scalar right comment */
+ fyd = fy_document_build_from_string(&cfg, "# top\n[]\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ /* top */
+ comment = fy_node_get_comment(fyn, fycp_top);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top"), NULL);
+
+ /* all */
+ comment = fy_node_get_comments(fyn);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top"), NULL);
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
+START_TEST(parser_comments_3)
+{
+ struct fy_parse_cfg cfg;
+ struct fy_document *fyd;
+ struct fy_node *fyn;
+ const char *comment;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.flags = FYPCF_DEFAULT_DOC | FYPCF_PARSE_COMMENTS;
+
+ /* root scalar right comment */
+ fyd = fy_document_build_from_string(&cfg, "# top seq\n- foo # right item\n", FY_NT);
+ ck_assert_ptr_ne(fyd, NULL);
+
+ fyn = fy_document_root(fyd);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ /* top */
+ comment = fy_node_get_comment(fyn, fycp_top);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top seq"), NULL);
+
+ /* all */
+ comment = fy_node_get_comments(fyn);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "top seq"), NULL);
+
+ /* get the first item of the sequence */
+ fyn = fy_node_by_path(fy_document_root(fyd), "/0", FY_NT, FYNWF_DONT_FOLLOW);
+ ck_assert_ptr_ne(fyn, NULL);
+
+ /* right */
+ comment = fy_node_get_comment(fyn, fycp_right);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "right item"), NULL);
+
+ /* all */
+ comment = fy_node_get_comments(fyn);
+ ck_assert_ptr_ne(comment, NULL);
+ ck_assert_ptr_ne(strstr(comment, "right item"), NULL);
+
+ fy_document_destroy(fyd);
+}
+END_TEST
+
TCase *libfyaml_case_parser(void)
{
TCase *tc;
/* Compose callback tests */
tcase_add_test(tc, parser_compose_callback);
+ /* Comment extraction tests */
+ tcase_add_test(tc, parser_comments_0);
+ tcase_add_test(tc, parser_comments_1);
+ tcase_add_test(tc, parser_comments_2);
+ tcase_add_test(tc, parser_comments_3);
+
return tc;
}
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#ifdef HAVE_ALLOCA_H
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <check.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
-#include <getopt.h>
-#include <unistd.h>
#include <limits.h>
#include <check.h>
#include <libfyaml.h>
-#include <stdatomic.h>
+#include "fy-atomics.h"
/* Test: Basic thread pool creation and destruction */
START_TEST(thread_pool_create_destroy)
int v, exp_v;
/* Atomically increase the counter */
- v = atomic_load(p);
+ v = fy_atomic_load(p);
for (;;) {
exp_v = v;
- if (atomic_compare_exchange_strong(p, &exp_v, v + 1))
+ if (fy_atomic_compare_exchange_strong(p, &exp_v, v + 1))
return;
v = exp_v;
}
}
/* Verify counter was incremented 4 times */
- ck_assert_int_eq(atomic_load(&counter), 4);
+ ck_assert_int_eq(fy_atomic_load(&counter), 4);
/* Unreserve all threads */
for (i = 0; i < 4; i++) {
ck_assert_ptr_ne(tp, NULL);
/* Use arg_join to execute the same function multiple times */
- fy_thread_arg_join(tp, atomic_increment_worker, NULL, &counter, num_tasks);
+ fy_thread_arg_join(tp, atomic_increment_worker, NULL, (void *)&counter, num_tasks);
/* Verify counter was incremented num_tasks times */
- ck_assert_int_eq(atomic_load(&counter), (int)num_tasks);
+ ck_assert_int_eq(fy_atomic_load(&counter), (int)num_tasks);
fy_thread_pool_destroy(tp);
}
/* Increment counter 100 times */
for (i = 0; i < 100; i++) {
- v = atomic_load(p);
+ v = fy_atomic_load(p);
for (;;) {
exp_v = v;
- if (atomic_compare_exchange_strong(p, &exp_v, v + 1))
+ if (fy_atomic_compare_exchange_strong(p, &exp_v, v + 1))
break;
v = exp_v;
}
ck_assert_ptr_ne(tp, NULL);
/* Execute many tasks with work stealing enabled */
- fy_thread_arg_join(tp, steal_mode_worker, NULL, &counter, num_tasks);
+ fy_thread_arg_join(tp, steal_mode_worker, NULL, (void *)&counter, num_tasks);
/* Verify all tasks completed: 16 tasks * 100 increments each */
- ck_assert_int_eq(atomic_load(&counter), (int)(num_tasks * 100));
+ ck_assert_int_eq(fy_atomic_load(&counter), (int)(num_tasks * 100));
fy_thread_pool_destroy(tp);
}
#endif
#include <stdio.h>
-#include <getopt.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <check.h>
#define QUIET_DEFAULT false
-static struct option lopts[] = {
- {"quiet", no_argument, 0, 'q' },
- {"help", no_argument, 0, 'h' },
- {0, 0, 0, 0 },
-};
-
static void display_usage(FILE *fp, char *progname)
{
fprintf(fp, "Usage: %s [options] [files]\n", progname);
int main(int argc, char *argv[])
{
- int exitcode = EXIT_FAILURE, opt, lidx;
+ int exitcode = EXIT_FAILURE;
bool quiet = QUIET_DEFAULT;
- int number_failed;
+ int i, number_failed;
Suite *s;
SRunner *sr;
fy_valgrind_check(&argc, &argv);
- while ((opt = getopt_long(argc, argv, "qh", lopts, &lidx)) != -1) {
- switch (opt) {
- case 'q':
+ /* don't use getopt - it's not there in windows */
+ for (i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-q") || !strcmp(argv[1], "--quiet")) {
quiet = true;
- break;
- case 'h' :
- default:
- if (opt != 'h')
- fprintf(stderr, "Unknown option\n");
- display_usage(opt == 'h' ? stdout : stderr, argv[0]);
+ } else if (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
+ display_usage(stdout, argv[0]);
return EXIT_SUCCESS;
+ } else {
+ display_usage(stderr, argv[0]);
+ return EXIT_FAILURE;
}
}