From: Timo Röhling Date: Tue, 27 Jan 2026 10:45:13 +0000 (+0100) Subject: New upstream version 0.9.3 X-Git-Tag: archive/raspbian/0.9.4-1+rpi1~1^2~1^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=1c4ce4ec5b2608c5ffc9b48f0d896facef793cd4;p=libfyaml.git New upstream version 0.9.3 --- diff --git a/.tarball-version b/.tarball-version index 2003b63..965065d 100644 --- a/.tarball-version +++ b/.tarball-version @@ -1 +1 @@ -0.9.2 +0.9.3 diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b0a930..ae5157b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,9 +5,54 @@ All notable changes to libfyaml will be documented in this file. 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.3] - 2026-01-14 + +### Added + +- fy-tool: `-winf` option for infinite width output +- fy-tool: `--no-output-newline` option (useful with oneline mode) +- Emitter: `FYEXCF_OUTPUT_FILENAME` extended option for direct file output + +### Changed + +- JSON emit mode now works like YAML flow mode (less special-casing) +- Compact emit mode now produces truly compact output (no indentation) +- Emitter only changes plain scalar style when space or linebreak is present (preserves numeric scalars better) + +### Fixed + +- **#170**: Wrong length return when buffer ends mid UTF-8 sequence +- **#167**: Oneline styles now correctly use infinite width +- **#139**: Walk path parser now always creates diagnostics (fixes token reference leak) +- **#137**: Walk memory leak on parse error path +- **#136**: Walk memory leak when no output is generated +- **#131**: Walk memory leak when expression error occurs +- Composer: Memory leak when back-to-back complex keys exist +- Emitter: Broken flow mode output +- Emitter: Unnecessary plain scalar style changes + +### Platform Support + +**Supported platforms**: Linux, macOS, FreeBSD, OpenBSD, and NetBSD. + +- **NetBSD**: Disabled mremap (different semantics than Linux) +- **NetBSD**: CMake shared libraries now correctly built with -fPIC +- **NetBSD**: Only include alloca.h if it exists +- **NetBSD**: Fixed ctype(3) argument casting (unsigned char) +- **GNU/Hurd**: Use `` for endianness detection +- Use `getopt_long` instead of `getopt_long_only` for portability +- Fix test(1) operator in test suite (use POSIX `=` not bash `==`) +- Fix `-Wformat` warning (use PRIx64 for uint64_t) + +### Statistics + +- 25 commits since v0.9.2 +- 6 bug fix issues closed + ## [0.9.2] - 2025-12-29 ### Fixed +- **#156**: automake: Respect --disable-static and don't build internals - **#157**: dist tarball now includes the missing CMake files ## [0.9.1] - 2025-12-28 @@ -129,5 +174,7 @@ Jose Luis Blanco-Claraco, Andrey Somov, Orange_233, Martin Diehl Initial public release with comprehensive YAML 1.2 support. +[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 [0.9]: https://github.com/pantoniou/libfyaml/releases/tag/v0.9 diff --git a/CMakeLists.txt b/CMakeLists.txt index d4f0999..135e3d2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,6 +148,7 @@ if(NOT CMAKE_USE_PTHREADS_INIT) endif() # Check for headers and functions +check_include_file("alloca.h" HAVE_ALLOCA_H) check_include_file("byteswap.h" HAVE_BYTESWAP_H) check_function_exists(__builtin_bswap16 HAVE___BUILTIN_BSWAP16) check_function_exists(__builtin_bswap32 HAVE___BUILTIN_BSWAP32) @@ -554,6 +555,12 @@ if(NOT MSVC) endif() +# the options for the libs +set(LIB_OPTS "") +if(BUILD_SHARED_LIBS) + list(APPEND LIB_OPTS "-fPIC") +endif() + # Network tests if(ENABLE_NETWORK) set(HAVE_NETWORK 1) @@ -670,7 +677,7 @@ target_compile_definitions(b3portable PRIVATE HASHER_SUFFIX=portable SIMD_DEGREE=1 ) -target_compile_options(b3portable PRIVATE ${COMMON_C_FLAGS}) +target_compile_options(b3portable PRIVATE ${COMMON_C_FLAGS} ${LIB_OPTS}) # BLAKE3 SIMD libraries set(BLAKE3_TARGETS b3portable) @@ -692,7 +699,7 @@ if(TARGET_HAS_SSE2) HASHER_SUFFIX=sse2 SIMD_DEGREE=4 ) - target_compile_options(b3sse2 PRIVATE ${COMMON_C_FLAGS} -msse2) + target_compile_options(b3sse2 PRIVATE ${COMMON_C_FLAGS} -msse2 ${LIB_OPTS}) list(APPEND BLAKE3_TARGETS b3sse2) endif() @@ -713,7 +720,7 @@ if(TARGET_HAS_SSE41) HASHER_SUFFIX=sse41 SIMD_DEGREE=4 ) - target_compile_options(b3sse41 PRIVATE ${COMMON_C_FLAGS} -msse4.1) + target_compile_options(b3sse41 PRIVATE ${COMMON_C_FLAGS} -msse4.1 ${LIB_OPTS}) list(APPEND BLAKE3_TARGETS b3sse41) endif() @@ -734,7 +741,7 @@ if(TARGET_HAS_AVX2) HASHER_SUFFIX=avx2 SIMD_DEGREE=8 ) - target_compile_options(b3avx2 PRIVATE ${COMMON_C_FLAGS} -mavx2) + target_compile_options(b3avx2 PRIVATE ${COMMON_C_FLAGS} -mavx2 ${LIB_OPTS}) list(APPEND BLAKE3_TARGETS b3avx2) endif() @@ -755,7 +762,7 @@ if(TARGET_HAS_AVX512) HASHER_SUFFIX=avx512 SIMD_DEGREE=16 ) - target_compile_options(b3avx512 PRIVATE ${COMMON_C_FLAGS} -mavx512f -mavx512vl) + target_compile_options(b3avx512 PRIVATE ${COMMON_C_FLAGS} -mavx512f -mavx512vl ${LIB_OPTS}) list(APPEND BLAKE3_TARGETS b3avx512) endif() @@ -775,7 +782,7 @@ if(TARGET_HAS_NEON) HASHER_SUFFIX=neon SIMD_DEGREE=4 ) - target_compile_options(b3neon PRIVATE ${COMMON_C_FLAGS}) + target_compile_options(b3neon PRIVATE ${COMMON_C_FLAGS} ${LIB_OPTS}) if(TARGET_CPU_ARM) target_compile_options(b3neon PRIVATE -mfpu=neon) endif() @@ -928,12 +935,9 @@ target_compile_options(fyaml PRIVATE ${COMMON_C_FLAGS}) # Shared options between GCC and CLANG if(NOT MSVC) + target_compile_options(fyaml PRIVATE ${LIB_OPTS}) 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() diff --git a/cmake/config.h.in b/cmake/config.h.in index f287269..5f21f9d 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -3,6 +3,9 @@ #ifndef CONFIG_H #define CONFIG_H +/* Define to 1 if you have alloca.h */ +#cmakedefine HAVE_ALLOCA_H + /* Define to 1 if you have byteswap.h */ #cmakedefine HAVE_BYTESWAP_H diff --git a/configure.ac b/configure.ac index 0c15913..2854bd7 100644 --- a/configure.ac +++ b/configure.ac @@ -125,7 +125,7 @@ AC_TYPE_OFF_T AC_TYPE_UID_T AC_CHECK_DECLS(environ) -AC_CHECK_HEADERS([byteswap.h]) +AC_CHECK_HEADERS([alloca.h byteswap.h]) AC_CHECK_FUNCS([__builtin_bswap16 __builtin_bswap32 __builtin_bswap64]) dnl for old autoconf version AX_APPEND_COMPILE_FLAGS does not work @@ -169,12 +169,12 @@ AC_ARG_ENABLE([portable-target], AS_HELP_STRING([--enable-portable-target], [Enable portable mode (disable per-target optimizations)])) HAVE_PORTABLE_TARGET=0 -if test "x$enable_portable_target" == "xyes"; then +if test "x$enable_portable_target" = "xyes"; then HAVE_PORTABLE_TARGET=1 fi AC_SUBST(HAVE_PORTABLE_TARGET) AC_DEFINE_UNQUOTED([HAVE_PORTABLE_TARGET], [$HAVE_PORTABLE_TARGET], [Define to 1 if PORTABLE_TARGET is enabled]) -AM_CONDITIONAL([HAVE_PORTABLE_TARGET], [ test x$HAVE_PORTABLE_TARGET == x1 ]) +AM_CONDITIONAL([HAVE_PORTABLE_TARGET], [ test x$HAVE_PORTABLE_TARGET = x1 ]) dnl Detect cross-compilation if test "x$build" != "x$host" ; then @@ -228,7 +228,7 @@ AC_ARG_ENABLE([asan], HAVE_ASAN=0 ASAN_CFLAGS="" ASAN_LIBS="" -if test "x$enable_asan" == "xyes" ; then +if test "x$enable_asan" = "xyes" ; then AC_MSG_CHECKING([location of ASAN library]) ASANLIB1=`${CC} -print-file-name=libasan.so` ASANLIB=`readlink -f "${ASANLIB1}"` @@ -474,12 +474,12 @@ if test "x$with_libclang" != "xno"; then fi fi if test "x$with_libclang" != "xno"; then - if test "x$with_libclang" == "xauto"; then + if test "x$with_libclang" = "xauto"; then # try to auto detect (llvm 20 down to 10) check="llvm-config llvm-config-20 llvm-config-19 llvm-config-18 llvm-config-17 llvm-config-16 \ llvm-config-15 llvm-config-14 llvm-config-13 llvm-config-12 llvm-config-11 llvm-config-10" else - if test "x$with_libclang" == "xlatest"; then + if test "x$with_libclang" = "xlatest"; then check="llvm-config" else check="llvm-config-$with_libclang" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 0390ef8..1400b77 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,3 +1,4 @@ +set(CMAKE_PREFIX_PATH "/home/panto/work/libfyaml/build") cmake_minimum_required(VERSION 3.12) project(libfyaml-examples C) diff --git a/include/libfyaml.h b/include/libfyaml.h index af8c820..9a0acee 100644 --- a/include/libfyaml.h +++ b/include/libfyaml.h @@ -2027,6 +2027,7 @@ struct fy_emitter_cfg { * @FYEXCF_OUTPUT_FILE: Output to the fp FILE pointer * @FYEXCF_OUTPUT_FD: Output to the fd file descriptor * @FYEXCF_NULL_OUTPUT: No output + * @FYEXCF_OUTPUT_FILENAME: Output to the given filename */ enum fy_emitter_xcfg_flags { FYEXCF_COLOR_AUTO = FYEXCF_COLOR(0), @@ -2037,6 +2038,7 @@ enum fy_emitter_xcfg_flags { FYEXCF_OUTPUT_FILE = FYEXCF_OUTPUT(2), FYEXCF_OUTPUT_FD = FYEXCF_OUTPUT(2), FYEXCF_NULL_OUTPUT = FYEXCF_OUTPUT(3), + FYEXCF_OUTPUT_FILENAME = FYEXCF_OUTPUT(4), FYEXCF_VISIBLE_WS = FY_BIT(5), FYEXCF_EXTENDED_INDICATORS = FY_BIT(6), }; @@ -2052,6 +2054,7 @@ enum fy_emitter_xcfg_flags { * @colors: ANSI color overrides for the default output method * @output_fp: The output FILE \*, FYEXCF\_FILE\_OUTPUT must be set * @output_fd: The output file descriptor, FYEXCF\_FD\_OUTPUT must be set + * @output_filename: The output filename, FYEXCF\_FILENAME\_OUTPUT must be set */ struct fy_emitter_xcfg { struct fy_emitter_cfg cfg; @@ -2060,6 +2063,7 @@ struct fy_emitter_xcfg { union { FILE *output_fp; int output_fd; + const char *output_filename; }; }; diff --git a/src/allocator/fy-allocator-dedup.c b/src/allocator/fy-allocator-dedup.c index 50193cb..e964fcf 100644 --- a/src/allocator/fy-allocator-dedup.c +++ b/src/allocator/fy-allocator-dedup.c @@ -812,7 +812,8 @@ again: if (a->flags & FYAF_TRACE) { int i; size_t j; - printf("%s: %p: dup-store %p 0x%016lx %zx:", __func__, a, de->mem, hash, total_size); + printf("%s: %p: dup-store %p 0x%016"PRIx64" %zx:", __func__, + a, de->mem, hash, total_size); for (i = 0; i < iovcnt; i++) { for (j = 0; j < iov[i].iov_len; j++) { printf("%02x", (int)(((uint8_t *)iov[i].iov_base)[j]) & 0xff); @@ -894,7 +895,8 @@ again: if (a->flags & FYAF_TRACE) { int i; size_t j; - printf("%s: %p: new-store %p 0x%016lx %zx:", __func__, a, de->mem, hash, total_size); + printf("%s: %p: new-store %p 0x%016"PRIx64" %zx:", __func__, + a, de->mem, hash, total_size); for (i = 0; i < iovcnt; i++) { for (j = 0; j < iov[i].iov_len; j++) { printf("%02x", (int)(((uint8_t *)iov[i].iov_base)[j]) & 0xff); diff --git a/src/allocator/fy-allocator-linear.c b/src/allocator/fy-allocator-linear.c index 96ae891..f516f9e 100644 --- a/src/allocator/fy-allocator-linear.c +++ b/src/allocator/fy-allocator-linear.c @@ -15,7 +15,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include diff --git a/src/allocator/fy-allocator-mremap.c b/src/allocator/fy-allocator-mremap.c index cbf16fb..d943221 100644 --- a/src/allocator/fy-allocator-mremap.c +++ b/src/allocator/fy-allocator-mremap.c @@ -16,7 +16,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include @@ -28,7 +32,9 @@ // #define DEBUG_ARENA -// #define DISABLE_MREMAP +#if defined(__NetBSD__) +#define DISABLE_MREMAP +#endif #if HAVE_MREMAP && !defined(DISABLE_MREMAP) #define USE_MREMAP 1 diff --git a/src/blake3/blake3.c b/src/blake3/blake3.c index ff1bbd5..65983a2 100644 --- a/src/blake3/blake3.c +++ b/src/blake3/blake3.c @@ -6,7 +6,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include diff --git a/src/blake3/blake3_backend.c b/src/blake3/blake3_backend.c index 72ff22e..4f00dd6 100644 --- a/src/blake3/blake3_backend.c +++ b/src/blake3/blake3_backend.c @@ -6,7 +6,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include diff --git a/src/blake3/blake3_be_cpusimd.c b/src/blake3/blake3_be_cpusimd.c index 8074176..8a00951 100644 --- a/src/blake3/blake3_be_cpusimd.c +++ b/src/blake3/blake3_be_cpusimd.c @@ -6,7 +6,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include diff --git a/src/blake3/blake3_host_state.c b/src/blake3/blake3_host_state.c index f76b9cb..4699fa3 100644 --- a/src/blake3/blake3_host_state.c +++ b/src/blake3/blake3_host_state.c @@ -6,7 +6,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include #include diff --git a/src/blake3/fy-blake3.c b/src/blake3/fy-blake3.c index 6931abc..e14234d 100644 --- a/src/blake3/fy-blake3.c +++ b/src/blake3/fy-blake3.c @@ -5,7 +5,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include diff --git a/src/internal/fy-allocators.c b/src/internal/fy-allocators.c index b1ed602..79e83e2 100644 --- a/src/internal/fy-allocators.c +++ b/src/internal/fy-allocators.c @@ -20,7 +20,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include #include @@ -257,7 +261,7 @@ int main(int argc, char *argv[]) const char *parent_allocator = "linear"; size_t size = 0; - while ((opt = getopt_long_only(argc, argv, "a:p:s:h", lopts, &lidx)) != -1) { + while ((opt = getopt_long(argc, argv, "a:p:s:h", lopts, &lidx)) != -1) { switch (opt) { case 'a': case 'p': diff --git a/src/internal/fy-b3sum.c b/src/internal/fy-b3sum.c index a0e21fb..9e81e42 100644 --- a/src/internal/fy-b3sum.c +++ b/src/internal/fy-b3sum.c @@ -20,7 +20,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include #include @@ -233,12 +237,12 @@ static int do_check_file(struct blake3_hasher *hasher, const char *check_filenam length = 0; s = linebuf; - while (isxdigit(*s)) + while (isxdigit((unsigned char)*s)) s++; length = s - linebuf; - if (length == 0 || length > (BLAKE3_OUT_LEN * 2) || (length % 1) || !isspace(*s)) { + 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); fprintf(stderr, "%s\n", linebuf); goto err_out; @@ -246,7 +250,7 @@ static int do_check_file(struct blake3_hasher *hasher, const char *check_filenam *s++ = '\0'; - while (isspace(*s)) + while (isspace((unsigned char)*s)) s++; length >>= 1; /* to bytes */ @@ -316,7 +320,7 @@ int main(int argc, char *argv[]) uint8_t key[BLAKE3_OUT_LEN]; ssize_t rdn; - while ((opt = getopt_long_only(argc, argv, "cl:b:dh", lopts, &lidx)) != -1) { + while ((opt = getopt_long(argc, argv, "cl:b:dh", lopts, &lidx)) != -1) { switch (opt) { case OPT_DERIVE_KEY: diff --git a/src/internal/fy-thread.c b/src/internal/fy-thread.c index 2880b00..ac21563 100644 --- a/src/internal/fy-thread.c +++ b/src/internal/fy-thread.c @@ -20,7 +20,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include #include @@ -550,7 +554,7 @@ int main(int argc, char *argv[]) unsigned int num_threads = 0; int exitcode = EXIT_FAILURE, opti; - while ((opt = getopt_long_only(argc, argv, "h", lopts, &lidx)) != -1) { + while ((opt = getopt_long(argc, argv, "h", lopts, &lidx)) != -1) { switch (opt) { case OPT_NUM_THREADS: opti = atoi(optarg); diff --git a/src/internal/libfyaml-parser.c b/src/internal/libfyaml-parser.c index 7253cce..8d0fb8d 100644 --- a/src/internal/libfyaml-parser.c +++ b/src/internal/libfyaml-parser.c @@ -4172,7 +4172,7 @@ int main(int argc, char *argv[]) fy_valgrind_check(&argc, &argv); - while ((opt = getopt_long_only(argc, argv, "I:m:i:w:d:rsc:C:D:M:W:S:qh", lopts, &lidx)) != -1) { + while ((opt = getopt_long(argc, argv, "I:m:i:w:d:rsc:C:D:M:W:S:qh", lopts, &lidx)) != -1) { switch (opt) { case 'I': tmp = alloca(strlen(cfg.search_path) + 1 + strlen(optarg) + 1); diff --git a/src/lib/fy-atom.c b/src/lib/fy-atom.c index c8d9e8e..4d554fe 100644 --- a/src/lib/fy-atom.c +++ b/src/lib/fy-atom.c @@ -1470,7 +1470,7 @@ int fy_atom_iter_utf8_quoted_get(struct fy_atom_iter *iter, size_t *lenp, uint8_ nread = fy_atom_iter_read(iter, buf + 1, w - 1); if (nread != (w - 1)) { if (nread != -1 && nread < (w - 1)) - *lenp += nread; + *lenp = nread; return 0; } } diff --git a/src/lib/fy-composer.c b/src/lib/fy-composer.c index 85b17bf..a4c7ea4 100644 --- a/src/lib/fy-composer.c +++ b/src/lib/fy-composer.c @@ -173,6 +173,9 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_event *fye, fyc_error_check(fyc, fyd, err_out, "fy_document_builder_take_document() failed\n"); + fy_document_builder_destroy(fypp->fydb); + fypp->fydb = NULL; + fypc_last->map.is_complex_key = true; fypc_last->map.accumulating_complex_key = false; fypc_last->map.complex_key = fyd; diff --git a/src/lib/fy-diag.c b/src/lib/fy-diag.c index 27c920e..58a6dad 100644 --- a/src/lib/fy-diag.c +++ b/src/lib/fy-diag.c @@ -52,7 +52,7 @@ enum fy_error_type fy_string_to_error_type(const char *str) if (!str) return FYET_MAX; - if (isdigit(*str)) { + if (isdigit((unsigned char)*str)) { level = atoi(str); if (level >= 0 && level < FYET_MAX) return (enum fy_error_type)level; diff --git a/src/lib/fy-doc.c b/src/lib/fy-doc.c index 826c562..c3b10ff 100644 --- a/src/lib/fy-doc.c +++ b/src/lib/fy-doc.c @@ -4186,7 +4186,7 @@ fy_node_by_path_internal(struct fy_node *fyn, switch (ptr_flags) { default: case FYNWF_PTR_YAML: - while (s < e && isspace(*s)) + while (s < e && isspace((unsigned char)*s)) s++; c = *s; @@ -4203,13 +4203,13 @@ fy_node_by_path_internal(struct fy_node *fyn, s = end_idx; - while (s < e && isspace(*s)) + while (s < e && isspace((unsigned char)*s)) s++; if (c == '[' && *s++ != ']') return NULL; - while (s < e && isspace(*s)) + while (s < e && isspace((unsigned char)*s)) s++; break; @@ -4480,7 +4480,7 @@ struct fy_node *fy_node_by_path(struct fy_node *fyn, /* first path component may be an alias */ if ((flags & FYNWF_FOLLOW) && fyn && path) { - while (s < e && isspace(*s)) + while (s < e && isspace((unsigned char)*s)) s++; if (s >= e || *s != '*') @@ -6248,10 +6248,10 @@ int fy_node_vscanf(struct fy_node *fyn, const char *fmt, va_list ap) } /* trim spaces from key */ - while (isspace(*s)) + while (isspace((unsigned char)*s)) s++; te = t; - while (te > s && isspace(te[-1])) + while (te > s && isspace((unsigned char)te[-1])) *--te = '\0'; key = s; @@ -6259,7 +6259,7 @@ int fy_node_vscanf(struct fy_node *fyn, const char *fmt, va_list ap) /* we have to scan until the next space that's not in char set */ fmtspec = t; while (t < e) { - if (isspace(*t)) + if (isspace((unsigned char)*t)) break; /* character set (may include space) */ if (*t == '[') { diff --git a/src/lib/fy-emit.c b/src/lib/fy-emit.c index 97ca397..cf1ef91 100644 --- a/src/lib/fy-emit.c +++ b/src/lib/fy-emit.c @@ -128,6 +128,9 @@ static inline int fy_emit_width(struct fy_emitter *emit) { int width; + if (fy_emit_is_oneline(emit)) + return INT_MAX; + width = (emit->xcfg.cfg.flags & FYECF_WIDTH(FYECF_WIDTH_MASK)) >> FYECF_WIDTH_SHIFT; if (width == 0) return 80; @@ -556,10 +559,6 @@ void fy_emit_document_start_indicator(struct fy_emitter *emit) if (emit->column) fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - /* stripping doc indicators, do not emit */ - if (emit->xcfg.cfg.flags & FYECF_STRIP_DOC) - goto no_doc_emit; - /* ok, emit document start indicator */ fy_emit_puts_simple(emit, fyewt_document_indicator, "---"); emit->flags &= ~FYEF_WHITESPACE; @@ -716,7 +715,7 @@ void fy_emit_common_node_preamble(struct fy_emitter *emit, if ((flags & DDNF_ROOT) && emit->column != 0 && !(emit->flags & FYEF_HAD_DOCUMENT_START)) { fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } } @@ -746,7 +745,7 @@ void fy_emit_node_internal(struct fy_emitter *emit, struct fy_node *fyn, int fla if (type != FYNT_SCALAR && (flags & DDNF_ROOT) && emit->column != 0) { fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } switch (type) { @@ -1423,8 +1422,8 @@ fy_emit_token_scalar_style(struct fy_emitter *emit, struct fy_token *fyt, if (flow && (style == FYNS_ANY || style == FYNS_LITERAL || style == FYNS_FOLDED)) { - /* if there's a linebreak, use double quoted style */ - if (ta->flags & FYTTAF_HAS_ANY_LB) { + /* if there's a linebreak, or ends in a colon, use double quoted style */ + if (ta->flags & (FYTTAF_HAS_ANY_LB | FYTTAF_ENDS_WITH_COLON)) { style = FYNS_DOUBLE_QUOTED; goto out; } @@ -1470,8 +1469,9 @@ out: ((ta->flags & FYTTAF_QUOTE_AT_0) && indent == 0)) style = FYNS_DOUBLE_QUOTED; - /* make it double quoted, but only if not already over the width */ - if (style == FYNS_PLAIN && emit->column < fy_emit_width(emit) && (emit->column + ta->maxspan) > fy_emit_width(emit)) + /* make it double quoted, but only if not already over the width (and contains a space/lb) */ + if (style == FYNS_PLAIN && (ta->flags & (FYTTAF_HAS_LB | FYTTAF_HAS_WS)) && + emit->column < fy_emit_width(emit) && (emit->column + ta->maxspan) > fy_emit_width(emit)) style = FYNS_DOUBLE_QUOTED; } @@ -1544,24 +1544,26 @@ static void fy_emit_sequence_prolog(struct fy_emitter *emit, struct fy_emit_save sc->flow = sc->empty; else sc->flow = fy_emit_is_flow_mode(emit) || emit->flow_level || sc->flow_token || sc->empty; + } else + sc->flow = true; - if (sc->flow) { - if (!emit->flow_level) { - sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); - sc->old_indent = sc->indent; - } - - sc->flags = (sc->flags | DDNF_FLOW) | (sc->flags & ~DDNF_INDENTLESS); - fy_emit_write_indicator(emit, di_left_bracket, sc->flags, sc->indent, fyewt_indicator); - } else { - sc->flags = (sc->flags & ~DDNF_FLOW); + if (sc->flow) { + if (!emit->flow_level) { + sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); + sc->old_indent = sc->indent; } - } else { + sc->flags = (sc->flags | DDNF_FLOW) | (sc->flags & ~DDNF_INDENTLESS); fy_emit_write_indicator(emit, di_left_bracket, sc->flags, sc->indent, fyewt_indicator); + + /* we need an indent afterward if not compact */ + if (!fy_emit_is_oneline_or_compact(emit)) + sc->flags |= DDNF_HANGING_INDENT; + } else { + sc->flags = (sc->flags & ~DDNF_FLOW); } - if (!fy_emit_is_oneline(emit)) { + if (!fy_emit_is_oneline_or_compact(emit)) { if (was_flow || (sc->flags & (DDNF_ROOT | DDNF_SEQ))) sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); } @@ -1587,7 +1589,7 @@ static void fy_emit_sequence_item_prolog(struct fy_emitter *emit, struct fy_emit sc->flags |= DDNF_SEQ; if (fy_emit_token_has_comment(emit, fyt_value, fycp_top) || - (!fy_emit_is_oneline_or_compact(emit) && !sc->flow) || + !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); @@ -1605,13 +1607,19 @@ static void fy_emit_sequence_item_prolog(struct fy_emitter *emit, struct fy_emit static void fy_emit_sequence_item_epilog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc, bool last, struct fy_token *fyt_value) { + bool needs_hanging_indent; + 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 (last && sc->flow && (sc->flags & DDNF_HANGING_INDENT) && !fy_emit_is_oneline_or_compact(emit) && !sc->empty) + needs_hanging_indent = sc->flow && !fy_emit_is_oneline_or_compact(emit) && !sc->empty; + + if (last && needs_hanging_indent && (sc->flags & DDNF_HANGING_INDENT)) fy_emit_write_indent(emit, sc->old_indent); + else if (needs_hanging_indent) + sc->flags |= DDNF_HANGING_INDENT; sc->flags &= ~DDNF_SEQ; } @@ -1662,24 +1670,26 @@ static void fy_emit_mapping_prolog(struct fy_emitter *emit, struct fy_emit_save_ sc->flow = sc->empty; else sc->flow = fy_emit_is_flow_mode(emit) || emit->flow_level || sc->flow_token || sc->empty; + } else + sc->flow = true; - if (sc->flow) { - if (!emit->flow_level) { - sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); - sc->old_indent = sc->indent; - } - - sc->flags = (sc->flags | DDNF_FLOW) | (sc->flags & ~DDNF_INDENTLESS); - fy_emit_write_indicator(emit, di_left_brace, sc->flags, sc->indent, fyewt_indicator); - } else { - sc->flags &= ~(DDNF_FLOW | DDNF_INDENTLESS); + if (sc->flow) { + if (!emit->flow_level) { + sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); + sc->old_indent = sc->indent; } - } else { + sc->flags = (sc->flags | DDNF_FLOW) | (sc->flags & ~DDNF_INDENTLESS); fy_emit_write_indicator(emit, di_left_brace, sc->flags, sc->indent, fyewt_indicator); + + /* we need an indent afterward if not compact */ + if (!fy_emit_is_oneline_or_compact(emit)) + sc->flags |= DDNF_HANGING_INDENT; + } else { + sc->flags &= ~(DDNF_FLOW | DDNF_INDENTLESS); } - if (!fy_emit_is_oneline(emit) && !sc->empty) + if (!fy_emit_is_oneline_or_compact(emit) && !sc->empty) sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent); sc->flags &= ~DDNF_ROOT; @@ -1702,6 +1712,10 @@ static void fy_emit_mapping_key_prolog(struct fy_emitter *emit, struct fy_emit_s sc->flags = DDNF_MAP | (sc->flags & DDNF_FLOW); + 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 (simple_key) { sc->flags |= DDNF_SIMPLE; if (fyt_key && fyt_key->type == FYTT_SCALAR) @@ -1713,10 +1727,10 @@ static void fy_emit_mapping_key_prolog(struct fy_emitter *emit, struct fy_emit_s } do_indent = false; - if (!fy_emit_is_oneline(emit)) { + if (!fy_emit_is_oneline_or_compact(emit)) { if (fyt_key && fyt_key->type != FYTT_SCALAR) /* always indent on non scalar keys */ - key_over = false; + key_over = true; else { /* for scalar keys, check if key + 2 + quotes go over */ ta = fy_token_text_analyze(fyt_key); @@ -1776,7 +1790,7 @@ static void fy_emit_mapping_value_prolog(struct fy_emitter *emit, struct fy_emit bool value_over; /* don't do anything for those cases */ - if (!sc->flow || fy_emit_is_oneline(emit) || !fyt_value || fyt_value->type != FYTT_SCALAR) + if (!sc->flow || fy_emit_is_oneline_or_compact(emit) || !fyt_value || fyt_value->type != FYTT_SCALAR) return; ta = fy_token_text_analyze(fyt_value); @@ -1791,13 +1805,19 @@ static void fy_emit_mapping_value_prolog(struct fy_emitter *emit, struct fy_emit static void fy_emit_mapping_value_epilog(struct fy_emitter *emit, struct fy_emit_save_ctx *sc, bool last, struct fy_token *fyt_value) { + bool needs_hanging_indent; + 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 (last && sc->flow && (sc->flags & DDNF_HANGING_INDENT) && !fy_emit_is_oneline_or_compact(emit) && !sc->empty) + needs_hanging_indent = sc->flow && !fy_emit_is_oneline_or_compact(emit) && !sc->empty; + + if (last && needs_hanging_indent && (sc->flags & DDNF_HANGING_INDENT)) fy_emit_write_indent(emit, sc->old_indent); + else if (needs_hanging_indent) + sc->flags |= DDNF_HANGING_INDENT; sc->flags &= ~DDNF_MAP; } @@ -1937,18 +1957,21 @@ int fy_emit_common_document_start(struct fy_emitter *emit, enum fy_emitter_cfg_flags dsm_flags = flags & FYECF_DOC_START_MARK(FYECF_DOC_START_MARK_MASK); bool vd, td, dsm; bool had_non_default_tag = false; + bool strip_doc = false; if (!emit || !fyds || emit->fyds) return -1; + strip_doc = !!(emit->xcfg.cfg.flags & FYECF_STRIP_DOC); + emit->fyds = fy_document_state_ref(fyds); vd = ((vd_flags == FYECF_VERSION_DIR_AUTO && fyds->version_explicit) || vd_flags == FYECF_VERSION_DIR_ON) && - !(emit->xcfg.cfg.flags & FYECF_STRIP_DOC); + !strip_doc; td = ((td_flags == FYECF_TAG_DIR_AUTO && fyds->tags_explicit) || td_flags == FYECF_TAG_DIR_ON) && - !(emit->xcfg.cfg.flags & FYECF_STRIP_DOC); + !strip_doc; /* if either a version or directive tags exist, and no previous * explicit document end existed, output one now @@ -1956,7 +1979,7 @@ int fy_emit_common_document_start(struct fy_emitter *emit, if (!fy_emit_is_json_mode(emit) && (vd || td) && !(emit->flags & FYEF_HAD_DOCUMENT_END)) { if (emit->column) fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - if (!(emit->xcfg.cfg.flags & FYECF_STRIP_DOC)) { + if (!strip_doc) { fy_emit_puts_simple(emit, fyewt_document_indicator, "..."); emit->flags &= ~FYEF_WHITESPACE; emit->flags |= FYEF_HAD_DOCUMENT_END; @@ -1969,7 +1992,7 @@ int fy_emit_common_document_start(struct fy_emitter *emit, fy_emit_printf(emit, fyewt_version_directive, "%%YAML %d.%d", fyds->version.major, fyds->version.minor); fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } if (!fy_emit_is_json_mode(emit) && td) { @@ -1991,7 +2014,7 @@ int fy_emit_common_document_start(struct fy_emitter *emit, (int)td_handle_size, td_handle, (int)td_prefix_size, td_prefix); fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } } @@ -2003,8 +2026,8 @@ int fy_emit_common_document_start(struct fy_emitter *emit, */ dsm = (dsm_flags == FYECF_DOC_START_MARK_AUTO && (!fyds->start_implicit || - fyds->tags_explicit || fyds->version_explicit || - had_non_default_tag)) || + (fyds->tags_explicit && had_non_default_tag) || + fyds->version_explicit )) || dsm_flags == FYECF_DOC_START_MARK_ON; /* if there was previous output without document end */ @@ -2012,8 +2035,13 @@ int fy_emit_common_document_start(struct fy_emitter *emit, !(emit->flags & FYEF_HAD_DOCUMENT_END)) dsm = true; + /* there was *any* document end output (and no document end) */ + if (!dsm && (emit->flags & FYEF_HAD_DOCUMENT_END_OUTPUT) && + !(emit->flags & FYEF_HAD_DOCUMENT_END)) + dsm = true; + /* output document start indicator if we should */ - if (dsm) + if (dsm && !fy_emit_is_json_mode(emit)) fy_emit_document_start_indicator(emit); /* clear that in any case */ @@ -2070,13 +2098,13 @@ int fy_emit_common_document_end(struct fy_emitter *emit, bool override_state, bo if (!(emit->xcfg.cfg.flags & FYECF_NO_ENDING_NEWLINE)) { if (emit->column != 0) { fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } if (!fy_emit_is_json_mode(emit) && dem) { fy_emit_puts_simple(emit, fyewt_document_indicator, "..."); fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; emit->flags |= FYEF_HAD_DOCUMENT_END; } else emit->flags &= ~FYEF_HAD_DOCUMENT_END; @@ -2084,7 +2112,7 @@ int fy_emit_common_document_end(struct fy_emitter *emit, bool override_state, bo if (!fy_emit_is_json_mode(emit) && dem) { if (emit->column != 0) { fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } fy_emit_puts_simple(emit, fyewt_document_indicator, "..."); emit->flags &= ~(FYEF_WHITESPACE | FYEF_INDENTATION); @@ -2122,13 +2150,13 @@ int fy_emit_common_explicit_document_end(struct fy_emitter *emit) if (emit->column != 0) { fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } if (!fy_emit_is_json_mode(emit)) { fy_emit_puts_simple(emit, fyewt_document_indicator, "..."); fy_emit_putc_simple(emit, fyewt_linebreak, '\n'); - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; emit->flags |= FYEF_HAD_DOCUMENT_END; } else emit->flags &= ~FYEF_HAD_DOCUMENT_END; @@ -2163,9 +2191,9 @@ void fy_emit_reset(struct fy_emitter *emit, bool reset_events) emit->column = 0; emit->flow_level = 0; emit->output_error = 0; - /* start as if there was a previous document with an explicit end */ - /* this allows implicit documents start without an indicator */ - emit->flags = FYEF_WHITESPACE | FYEF_INDENTATION | FYEF_HAD_DOCUMENT_END; + /* clear/set flags for a fresh start */ + emit->flags &= ~(FYEF_OPEN_ENDED | FYEF_HAD_DOCUMENT_START | FYEF_HAD_DOCUMENT_OUTPUT); + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; emit->state = FYES_NONE; @@ -2319,6 +2347,9 @@ void fy_emit_cleanup(struct fy_emitter *emit) free(emit->sc_stack); fy_diag_unref(emit->diag); + + if (emit->owned_output_fp) + fclose(emit->owned_output_fp); } int fy_emit_node_no_check(struct fy_emitter *emit, struct fy_node *fyn) @@ -3113,7 +3144,7 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_parser *fyp if (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; + emit->flags |= FYEF_WHITESPACE | FYEF_INDENTATION; } emit->s_flags = flags; @@ -3295,6 +3326,7 @@ static int fy_emit_handle_document_end(struct fy_emitter *emit, struct fy_parser fy_emit_reset(emit, false); fy_emit_goto_state(emit, FYES_DOCUMENT_START); + emit->flags |= FYEF_HAD_DOCUMENT_END_OUTPUT; return 0; } @@ -3725,6 +3757,10 @@ static FILE *fy_emitter_get_output_fp(struct fy_emitter *fye) return stderr; case FYEXCF_OUTPUT_FILE: return fye->xcfg.output_fp; + case FYEXCF_OUTPUT_FILENAME: + if (!fye->owned_output_fp && fye->xcfg.output_filename) + fye->owned_output_fp = fopen(fye->xcfg.output_filename, "wb"); + return fye->owned_output_fp; default: break; } diff --git a/src/lib/fy-emit.h b/src/lib/fy-emit.h index 5d23377..9269c62 100644 --- a/src/lib/fy-emit.h +++ b/src/lib/fy-emit.h @@ -28,6 +28,7 @@ #define FYEF_HAD_DOCUMENT_START 0x0008 #define FYEF_HAD_DOCUMENT_END 0x0010 #define FYEF_HAD_DOCUMENT_OUTPUT 0x0020 +#define FYEF_HAD_DOCUMENT_END_OUTPUT 0x0040 struct fy_document; struct fy_emitter; @@ -89,6 +90,7 @@ struct fy_emitter { FILE *output_fp; int output_fd; bool output_colorize; + FILE *owned_output_fp; struct fy_document *fyd; struct fy_document_state *fyds; /* fyd->fyds when fyd != NULL */ diff --git a/src/lib/fy-input.c b/src/lib/fy-input.c index 6095cfb..da7665d 100644 --- a/src/lib/fy-input.c +++ b/src/lib/fy-input.c @@ -129,7 +129,8 @@ static void fy_input_from_data_setup(struct fy_input *fyi, handle->end_mark.line = 0; handle->end_mark.column = fy_utf8_count(data, size); /* if it's plain, all is good */ - if ((simple || (aflags & FYACF_FLOW_PLAIN)) && !(aflags & FYACF_LB)) { + if ((simple || (aflags & FYACF_FLOW_PLAIN)) && + !(aflags & (FYACF_LB | FYACF_ENDS_WITH_COLON))) { handle->storage_hint = size; /* maximum */ handle->storage_hint_valid = false; handle->direct_output = !!(aflags & FYACF_JSON_ESCAPE); diff --git a/src/lib/fy-token.c b/src/lib/fy-token.c index a16bc04..58f8315 100644 --- a/src/lib/fy-token.c +++ b/src/lib/fy-token.c @@ -861,10 +861,13 @@ fy_token_text_analyze(struct fy_token *fyt) /* last character */ if (cn < 0) { - /* if ends with whitespace or linebreak, can't be plain */ - if (fy_is_ws(c) || fy_token_is_lb(fyt, c)) + /* if ends with whitespace or linebreak, or : can't be plain */ + if (fy_is_ws(c) || fy_token_is_lb(fyt, c) || c == ':') { flags &= ~(FYTTAF_CAN_BE_PLAIN | FYTTAF_CAN_BE_PLAIN_FLOW); + if (c == ':') + flags |= FYTTAF_ENDS_WITH_COLON; + } } } @@ -1485,6 +1488,12 @@ unsigned int fy_analyze_scalar_content(const char *data, size_t size, s = data; e = data + size; + /* if it ends in : can't be a plain */ + if (e > s && e[-1] == ':') { + flags &= ~(FYACF_BLOCK_PLAIN | FYACF_FLOW_PLAIN); + flags |= FYACF_ENDS_WITH_COLON; + } + col = 0; first = true; lastc = -1; diff --git a/src/lib/fy-token.h b/src/lib/fy-token.h index 93c1d94..c0a76f5 100644 --- a/src/lib/fy-token.h +++ b/src/lib/fy-token.h @@ -79,6 +79,7 @@ static inline bool fy_token_type_is_mapping_marker(enum fy_token_type type) #define FYACF_SIZE0 0x020000 /* contains absolutely nothing */ #define FYACF_VALID_ANCHOR 0x040000 /* contains valid anchor (without & prefix) */ #define FYACF_JSON_ESCAPE 0x080000 /* contains a character that JSON escapes */ +#define FYACF_ENDS_WITH_COLON 0x100000 /* ends with : */ /* analysis flags */ #define FYTTAF_HAS_LB FY_BIT(0) @@ -102,6 +103,7 @@ static inline bool fy_token_type_is_mapping_marker(enum fy_token_type type) #define FYTTAF_HAS_START_IND FY_BIT(19) /* has --- at col 0 */ #define FYTTAF_HAS_END_IND FY_BIT(20) /* has ... at col 0 */ #define FYTTAF_HAS_NON_PRINT FY_BIT(21) /* has any non printable utf8 */ +#define FYTTAF_ENDS_WITH_COLON FY_BIT(22) /* ends with a colon */ #define FYTTAF_ANALYZED FY_BIT(31) /* analyzed mark */ diff --git a/src/lib/fy-walk.c b/src/lib/fy-walk.c index b1daa56..8c83d9c 100644 --- a/src/lib/fy-walk.c +++ b/src/lib/fy-walk.c @@ -754,12 +754,19 @@ static const struct fy_reader_ops fy_path_parser_reader_ops = { void fy_path_parser_setup(struct fy_path_parser *fypp, const struct fy_path_parse_cfg *pcfg) { + struct fy_diag_cfg dcfg; + if (!fypp) return; memset(fypp, 0, sizeof(*fypp)); if (pcfg) fypp->cfg = *pcfg; + if (!fypp->cfg.diag) { + fy_diag_cfg_default(&dcfg); + fypp->cfg.diag = fy_diag_create(&dcfg); + fypp->owns_diag = true; + } fy_reader_setup(&fypp->reader, &fy_path_parser_reader_ops); fy_token_list_init(&fypp->queued_tokens); fypp->last_queued_token_type = FYTT_NONE; @@ -774,12 +781,12 @@ void fy_path_parser_setup(struct fy_path_parser *fypp, const struct fy_path_pars fypp->paren_nest_level = 0; } -void fy_path_parser_cleanup(struct fy_path_parser *fypp) +int fy_path_parser_reset(struct fy_path_parser *fypp) { struct fy_path_expr *expr; if (!fypp) - return; + return -1; fy_expr_stack_cleanup(&fypp->operands); fy_expr_stack_cleanup(&fypp->operators); @@ -796,6 +803,19 @@ void fy_path_parser_cleanup(struct fy_path_parser *fypp) fypp->stream_error = false; fypp->token_activity_counter = 0; fypp->paren_nest_level = 0; + + return 0; +} + +void fy_path_parser_cleanup(struct fy_path_parser *fypp) +{ + if (!fypp) + return; + + fy_path_parser_reset(fypp); + if (fypp->owns_diag && fypp->cfg.diag) + fy_diag_unref(fypp->cfg.diag); + memset(fypp, 0, sizeof(*fypp)); } int fy_path_parser_open(struct fy_path_parser *fypp, @@ -1110,7 +1130,7 @@ err_out: int fy_path_fetch_tokens(struct fy_path_parser *fypp) { enum fy_token_type type; - struct fy_token *fyt; + struct fy_token *fyt = NULL; struct fy_reader *fyr; int c, cn, rc, simple_token_count; @@ -1119,6 +1139,7 @@ int fy_path_fetch_tokens(struct fy_path_parser *fypp) fyt = fy_path_token_queue(fypp, FYTT_STREAM_START, fy_reader_fill_atom_a(fyr, 0)); fyr_error_check(fyr, fyt, err_out, "fy_path_token_queue() failed\n"); + fyt = NULL; fypp->stream_start_produced = true; return 0; @@ -1136,6 +1157,7 @@ int fy_path_fetch_tokens(struct fy_path_parser *fypp) /* produce stream end continuously */ fyt = fy_path_token_queue(fypp, FYTT_STREAM_END, fy_reader_fill_atom_a(fyr, 0)); fyr_error_check(fyr, fyt, err_out, "fy_path_token_queue() failed\n"); + fyt = NULL; return 0; } @@ -1381,6 +1403,7 @@ do_token: if (simple_token_count > 0) { fyt = fy_path_token_queue(fypp, type, fy_reader_fill_atom_a(fyr, simple_token_count)); fyr_error_check(fyr, fyt, err_out, "fy_path_token_queue() failed\n"); + fyt = NULL; return 0; } @@ -3205,7 +3228,7 @@ fy_path_parse_expression(struct fy_path_parser *fypp) struct fy_reader *fyr; struct fy_token *fyt = NULL; enum fy_token_type fytt; - struct fy_path_expr *expr, *expr_top, *exprt; + struct fy_path_expr *expr = NULL, *expr_top, *exprt; enum fy_expr_mode old_scan_mode, prev_scan_mode; int ret, rc; @@ -3509,6 +3532,8 @@ fy_path_parse_expression(struct fy_path_parser *fypp) return expr; err_out: + if (expr) + fy_path_expr_free(expr); #ifdef DEBUG_EXPR fy_notice(fypp->cfg.diag, "operator stack (error)\n"); fy_expr_stack_dump(fypp->cfg.diag, &fypp->operators); @@ -3686,14 +3711,6 @@ void fy_path_parser_destroy(struct fy_path_parser *fypp) free(fypp); } -int fy_path_parser_reset(struct fy_path_parser *fypp) -{ - if (!fypp) - return -1; - fy_path_parser_cleanup(fypp); - return 0; -} - struct fy_path_expr * fy_path_parse_expr_from_string(struct fy_path_parser *fypp, const char *str, size_t len) @@ -4441,7 +4458,11 @@ fy_walk_result_perform_set_op(struct fy_path_exec *fypx, struct fy_walk_result * if (!set) { /* on unselect, return input, on select return NULL */ - return op == FYWRSO_UNSELECT ? input : NULL; + if (op == FYWRSO_UNSELECT) + return input; + + fy_walk_result_free(input); + return NULL; } assert(input->type == fwrt_node_ref || input->type == fwrt_refs); @@ -4520,7 +4541,11 @@ fy_walk_result_perform_set_op(struct fy_path_exec *fypx, struct fy_walk_result * if (!output) { /* nothing? nothing was removed or nothing was selected */ - return op == FYWRSO_UNSELECT ? input : NULL; + if (op == FYWRSO_UNSELECT) + return input; + + fy_walk_result_free(input); + return NULL; } /* simplify (might remove everything if empty) */ diff --git a/src/lib/fy-walk.h b/src/lib/fy-walk.h index 0578ac0..3697e9c 100644 --- a/src/lib/fy-walk.h +++ b/src/lib/fy-walk.h @@ -325,6 +325,7 @@ struct fy_path_parser { bool stream_start_produced; bool stream_end_produced; bool stream_error; + bool owns_diag; int token_activity_counter; struct fy_input *fyi; diff --git a/src/thread/fy-thread.c b/src/thread/fy-thread.c index bcd3214..08b7771 100644 --- a/src/thread/fy-thread.c +++ b/src/thread/fy-thread.c @@ -13,7 +13,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include #include #include diff --git a/src/tool/fy-tool.c b/src/tool/fy-tool.c index b8b15cd..3529e4f 100644 --- a/src/tool/fy-tool.c +++ b/src/tool/fy-tool.c @@ -69,6 +69,7 @@ #define ALLOW_DUPLICATE_KEYS_DEFAULT false #define STRIP_EMPTY_KV_DEFAULT false #define TSV_FORMAT_DEFAULT false +#define NO_ENDING_NEWLINE_DEFAULT false #define OPT_DUMP 1000 #define OPT_TESTSUITE 1001 @@ -108,6 +109,7 @@ #define OPT_DISABLE_DOC_MARKERS 2022 #define OPT_DISABLE_SCALAR_STYLES 2023 #define OPT_NO_STREAMING 2024 +#define OPT_NO_ENDING_NEWLINE 2025 #define OPT_DISABLE_DIAG 3000 #define OPT_ENABLE_DIAG 3001 @@ -169,9 +171,9 @@ static struct option lopts[] = { {"disable-depth-limit", no_argument, 0, OPT_DISABLE_DEPTH_LIMIT }, {"disable-mmap", no_argument, 0, OPT_DISABLE_MMAP }, {"disable-diag", required_argument, 0, OPT_DISABLE_DIAG }, - {"enable-diag", required_argument, 0, OPT_ENABLE_DIAG }, + {"enable-diag", required_argument, 0, OPT_ENABLE_DIAG }, {"show-diag", required_argument, 0, OPT_SHOW_DIAG }, - {"hide-diag", required_argument, 0, OPT_HIDE_DIAG }, + {"hide-diag", required_argument, 0, OPT_HIDE_DIAG }, {"yaml-1.1", no_argument, 0, OPT_YAML_1_1 }, {"yaml-1.2", no_argument, 0, OPT_YAML_1_2 }, {"yaml-1.3", no_argument, 0, OPT_YAML_1_3 }, @@ -185,6 +187,7 @@ static struct option lopts[] = { {"document-event-stream",no_argument, 0, OPT_DOCUMENT_EVENT_STREAM }, {"noexec", no_argument, 0, OPT_NOEXEC }, {"null-output", no_argument, 0, OPT_NULL_OUTPUT }, + {"no-ending-newline", no_argument, 0, OPT_NO_ENDING_NEWLINE }, {"collect-errors", no_argument, 0, OPT_COLLECT_ERRORS }, {"allow-duplicate-keys",no_argument, 0, OPT_ALLOW_DUPLICATE_KEYS }, {"strip-empty-kv", no_argument, 0, OPT_STRIP_EMPTY_KV }, @@ -208,7 +211,7 @@ static struct option lopts[] = { {"help", no_argument, 0, 'h' }, {"version", no_argument, 0, 'v' }, - {0, 0, 0, 0 }, + {0, 0, 0, 0 }, }; static void display_usage(FILE *fp, char *progname, int tool_mode) @@ -229,7 +232,7 @@ static void display_usage(FILE *fp, char *progname, int tool_mode) fprintf(fp, "\t--indent, -i : Set dump indent to " " (default indent %d)\n", INDENT_DEFAULT); - fprintf(fp, "\t--width, -w : Set dump width to " + fprintf(fp, "\t--width, -w : Set dump width to - inf for infinite" " (default width %d)\n", WIDTH_DEFAULT); fprintf(fp, "\t--resolve, -r : Perform anchor and merge key resolution" @@ -277,6 +280,7 @@ static void display_usage(FILE *fp, char *progname, int tool_mode) fprintf(fp, "\t--ypath-aliases : Use YPATH aliases (default %s)\n", YPATH_ALIASES_DEFAULT ? "true" : "false"); fprintf(fp, "\t--null-output : Do not generate output (for scanner profiling)\n"); + fprintf(fp, "\t--no-ending-newline : Do not generate a final newline\n"); fprintf(fp, "\t--collect-errors : Collect errors instead of outputting directly" " (default %s)\n", COLLECT_ERRORS_DEFAULT ? "true" : "false"); @@ -871,12 +875,12 @@ static int do_b3sum_check_file(struct fy_blake3_hasher *hasher, const char *chec length = 0; s = linebuf; - while (isxdigit(*s)) + while (isxdigit((unsigned char)*s)) s++; length = s - linebuf; - if (length == 0 || length > (FY_BLAKE3_OUT_LEN * 2) || (length % 1) || !isspace(*s)) { + 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); fprintf(stderr, "%s\n", linebuf); goto err_out; @@ -884,7 +888,7 @@ static int do_b3sum_check_file(struct fy_blake3_hasher *hasher, const char *chec *s++ = '\0'; - while (isspace(*s)) + while (isspace((unsigned char)*s)) s++; length >>= 1; /* to bytes */ @@ -1165,7 +1169,7 @@ int main(int argc, char *argv[]) FYEXCF_COLOR_NONE) | FYEXCF_OUTPUT_STDOUT; - while ((opt = getopt_long_only(argc, argv, + while ((opt = getopt_long(argc, argv, "I:" "d:" "i:" "w:" "rsc" "C:" "m:" "V" "f:" "t:" "T:F:" "j:" "qhvl", lopts, &lidx)) != -1) { switch (opt) { @@ -1184,17 +1188,21 @@ int main(int argc, char *argv[]) break; case 'i': indent = atoi(optarg); - if (indent < 0 || indent > FYECF_INDENT_MASK) { + if (indent <= 0 || indent > FYECF_INDENT_MASK) { fprintf(stderr, "bad indent option %s\n", optarg); goto err_out_usage; } break; case 'w': - width = atoi(optarg); - if (width < 0 || width > FYECF_WIDTH_MASK) { - fprintf(stderr, "bad width option %s\n", optarg); - goto err_out_usage; + if (!strcmp(optarg, "inf")) { + width = 0; /* infinite */ + } else { + width = atoi(optarg); + if (width <= 8 || width > FYECF_WIDTH_MASK) { /* it should fit %YAML 1.3 at least */ + fprintf(stderr, "bad width option %s\n", optarg); + goto err_out_usage; + } } manual_width = true; break; @@ -1371,6 +1379,10 @@ int main(int argc, char *argv[]) break; case OPT_NULL_OUTPUT: null_output = true; + emit_xflags |= FYEXCF_NULL_OUTPUT; + break; + case OPT_NO_ENDING_NEWLINE: + emit_flags |= FYECF_NO_ENDING_NEWLINE; break; case OPT_YAML_1_1: cfg.flags &= ~(FYPCF_DEFAULT_VERSION_MASK << FYPCF_DEFAULT_VERSION_SHIFT); @@ -1563,8 +1575,10 @@ int main(int argc, char *argv[]) /* if we're dumping to a non tty stdout width is infinite */ if (tool_mode == OPT_DUMP && !isatty(fileno(stdout)) && !manual_width) emit_width_flags = FYECF_WIDTH_INF; - else + else if (width > 0) emit_width_flags = FYECF_WIDTH(width); + else + emit_width_flags = FYECF_WIDTH_INF; memset(&emit_xcfg, 0, sizeof(emit_xcfg)); emit_xcfg.cfg.flags = emit_flags | emit_width_flags | diff --git a/src/util/fy-endian.h b/src/util/fy-endian.h index a3be6b8..5778037 100644 --- a/src/util/fy-endian.h +++ b/src/util/fy-endian.h @@ -8,7 +8,7 @@ #ifndef FY_ENDIAN_H #define FY_ENDIAN_H -#if defined(__linux__) || defined(__CYGWIN__) || defined(__OpenBSD__) +#if defined(__linux__) || defined(__CYGWIN__) || defined(__OpenBSD__) || defined(__GNU__) # include #elif defined(__APPLE__) # include diff --git a/src/util/fy-utf8.h b/src/util/fy-utf8.h index 923dc06..9a40af7 100644 --- a/src/util/fy-utf8.h +++ b/src/util/fy-utf8.h @@ -15,7 +15,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include "fy-utils.h" diff --git a/src/util/fy-utils.c b/src/util/fy-utils.c index fa4cff8..40ce77b 100644 --- a/src/util/fy-utils.c +++ b/src/util/fy-utils.c @@ -675,7 +675,7 @@ again: e = iter->end; /* skip whitespace */ - while (s < e && isblank(*s)) + while (s < e && isblank((unsigned char)*s)) s++; if (s >= e) @@ -695,12 +695,12 @@ again: le -= 2; /* backtrack while there's space at the end of line */ - while (le > s && isblank(le[-1])) + while (le > s && isblank((unsigned char)le[-1])) le--; /* check if the whole line is punctuation so it's formatting */ t = s; - while (t < le && ispunct(*t)) + while (t < le && ispunct((unsigned char)*t)) t++; /* everything is punctuation? */ @@ -715,11 +715,11 @@ again: } /* something is there, skip over '// ' or '* ' */ - if ((le - s) > 3 && s[0] == '/' && s[1] == '/' && isblank(s[2])) + if ((le - s) > 3 && s[0] == '/' && s[1] == '/' && isblank((unsigned char)s[2])) s += 3; - else if ((le - s) > 2 && s[0] == '*' && isblank(s[1])) + else if ((le - s) > 2 && s[0] == '*' && isblank((unsigned char)s[1])) s += 2; - else if (iter->line == 0 && (le - s) > 3 && s[0] == '/' && s[1] == '*' && isblank(s[2])) + else if (iter->line == 0 && (le - s) > 3 && s[0] == '/' && s[1] == '*' && isblank((unsigned char)s[2])) s += 3; iter->line++; diff --git a/src/valgrind/fy-valgrind.h b/src/valgrind/fy-valgrind.h index 80176f3..36a64bd 100644 --- a/src/valgrind/fy-valgrind.h +++ b/src/valgrind/fy-valgrind.h @@ -20,7 +20,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #ifdef __linux__ #include #endif diff --git a/test/libfyaml-test-private-id.c b/test/libfyaml-test-private-id.c index 7936f87..f943868 100644 --- a/test/libfyaml-test-private-id.c +++ b/test/libfyaml-test-private-id.c @@ -17,7 +17,11 @@ #include #include #include + +#ifdef HAVE_ALLOCA_H #include +#endif + #include diff --git a/test/libfyaml-test.c b/test/libfyaml-test.c index 1ac79fb..0fbf83e 100644 --- a/test/libfyaml-test.c +++ b/test/libfyaml-test.c @@ -78,7 +78,7 @@ int main(int argc, char *argv[]) fy_valgrind_check(&argc, &argv); - while ((opt = getopt_long_only(argc, argv, "qh", lopts, &lidx)) != -1) { + while ((opt = getopt_long(argc, argv, "qh", lopts, &lidx)) != -1) { switch (opt) { case 'q': quiet = true; diff --git a/test/libfyaml.test b/test/libfyaml.test index 885f310..d77cc2f 100755 --- a/test/libfyaml.test +++ b/test/libfyaml.test @@ -1,6 +1,6 @@ #!/usr/bin/env bash -if [ "x$builddir" == "x" ]; then +if [ "x$builddir" = "x" ]; then T=`realpath ./libfyaml-test` else T=`realpath ${builddir}/libfyaml-test` diff --git a/test/testemitter.test b/test/testemitter.test index be9d4f2..cef826e 100755 --- a/test/testemitter.test +++ b/test/testemitter.test @@ -2,9 +2,9 @@ EXTRA_DUMP_ARGS="" -if [ "x$1" == "x--streaming" ]; then +if [ "x$1" = "x--streaming" ]; then EXTRA_DUMP_ARGS="$EXTRA_DUMP_ARGS --streaming" -elif [ "x$1" == "x--restreaming" ]; then +elif [ "x$1" = "x--restreaming" ]; then EXTRA_DUMP_ARGS="$EXTRA_DUMP_ARGS --streaming --recreating" fi @@ -38,7 +38,7 @@ for f in "${SRCDIR}"/emitter-examples/*.yaml; do fi # all errors test are expected to fail - if [ "$pass_parse" == "1" ]; then + if [ "$pass_parse" = "1" ]; then diff -u "$t1" "$t2" if [ $? -eq 0 ]; then res="ok" diff --git a/test/testerrors.test b/test/testerrors.test index 55f8627..bbf79c0 100755 --- a/test/testerrors.test +++ b/test/testerrors.test @@ -32,11 +32,11 @@ for dir in "${SRCDIR}"/test-errors/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do echo "$errmsg" >"$t" # all errors test are expected to fail - if [ "$pass_yaml" == "0" ]; then + if [ "$pass_yaml" = "0" ]; then res="ok" # diff is pointless under valgrind - if [ "x$USE_VALGRIND" == "x" ]; then + if [ "x$USE_VALGRIND" = "x" ]; then diff_err=0 diff -u "$dir/test.error" "$t" if [ $? -eq 0 ]; then diff --git a/test/testsuite-evstream.test b/test/testsuite-evstream.test index c60b0be..b7b5d25 100755 --- a/test/testsuite-evstream.test +++ b/test/testsuite-evstream.test @@ -56,7 +56,7 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do fi res="ok" - if [ "x$skip_reason" == "x" ]; then + if [ "x$skip_reason" = "x" ]; then res="not ok" t=`mktemp` diff --git a/test/testsuite-json.test b/test/testsuite-json.test index f5435a5..f607119 100755 --- a/test/testsuite-json.test +++ b/test/testsuite-json.test @@ -61,7 +61,7 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do fi res="ok" - if [ "x$skip_reason" == "x" ]; then + if [ "x$skip_reason" = "x" ]; then t1=`mktemp` t2=`mktemp` diff --git a/test/testsuite-resolution.test b/test/testsuite-resolution.test index d33f4a1..7856bad 100755 --- a/test/testsuite-resolution.test +++ b/test/testsuite-resolution.test @@ -72,7 +72,7 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do fi res="ok" - if [ "x$skip_reason" == "x" ]; then + if [ "x$skip_reason" = "x" ]; then res="not ok" ${TOP_BUILDDIR}/src/fy-tool --dump --resolve "$tst/in.yaml" | ${TOP_BUILDDIR}/src/fy-tool --testsuite --disable-flow-markers - >"$t1" diff --git a/test/testsuite.test b/test/testsuite.test index adee528..38cd521 100755 --- a/test/testsuite.test +++ b/test/testsuite.test @@ -42,14 +42,14 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do directive="" for skip in $skiplist; do - if [ "$test_subtest_id" == "$skip" ]; then + if [ "$test_subtest_id" = "$skip" ]; then directive=" # SKIP" break fi done res="ok" - if [ "x$directive" == "x" ]; then + if [ "x$directive" = "x" ]; then res="not ok" pass_yaml=0 @@ -60,14 +60,14 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do if [ -e "$tst/error" ]; then # test is expected to fail - if [ $pass_yaml == "0" ]; then + if [ $pass_yaml = "0" ]; then res="ok" else res="not ok" fi else # test is expected to pass - if [ $pass_yaml == "1" ]; then + if [ $pass_yaml = "1" ]; then diff_yaml=0 # diff -u "$tst/test.event" "$t" | sed -e 's/^/# /' diff -u "$tst/test.event" "$t" @@ -84,7 +84,7 @@ for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do rm -f "$t" for xfail in $xfaillist; do - if [ "$test_subtest_id" == "$xfail" ]; then + if [ "$test_subtest_id" = "$xfail" ]; then directive=" # TODO: known failure." break fi