]> dgit.raspbian.org Git - libfyaml.git/commitdiff
New upstream version 0.7.11
authorJose Luis Blanco Claraco <joseluisblancoc@gmail.com>
Fri, 14 Jan 2022 21:50:46 +0000 (22:50 +0100)
committerJose Luis Blanco Claraco <joseluisblancoc@gmail.com>
Fri, 14 Jan 2022 21:50:46 +0000 (22:50 +0100)
48 files changed:
.libtool-version [new file with mode: 0644]
.tarball-version
Makefile.in
README.md
configure
configure.ac
doc/Makefile.am
doc/Makefile.in
doc/canned-man/fy-tool.1 [new file with mode: 0644]
doc/man/fy-tool.rst
include/libfyaml.h
libfyaml.pc.in
src/Makefile.am
src/Makefile.in
src/internal/libfyaml-parser.c
src/lib/fy-atom.c
src/lib/fy-atom.h
src/lib/fy-composer.c
src/lib/fy-composer.h
src/lib/fy-diag.c
src/lib/fy-diag.h
src/lib/fy-doc.c
src/lib/fy-doc.h
src/lib/fy-docbuilder.c [new file with mode: 0644]
src/lib/fy-docbuilder.h [new file with mode: 0644]
src/lib/fy-docstate.c
src/lib/fy-docstate.h
src/lib/fy-emit.c
src/lib/fy-emit.h
src/lib/fy-event.c
src/lib/fy-event.h
src/lib/fy-input.c
src/lib/fy-input.h
src/lib/fy-parse.c
src/lib/fy-parse.h
src/lib/fy-path.c
src/lib/fy-path.h
src/lib/fy-token.c
src/lib/fy-token.h
src/lib/fy-utils.c
src/lib/fy-utils.h
src/lib/fy-walk.c
src/tool/fy-tool.c
test/Makefile.am
test/Makefile.in
test/testsuite-evstream.test [new file with mode: 0755]
test/testsuite-json.test
test/testsuite.test

diff --git a/.libtool-version b/.libtool-version
new file mode 100644 (file)
index 0000000..a759e95
--- /dev/null
@@ -0,0 +1 @@
+1:1:0
index f38fc5393ff66e64aaa5d8733ea9b44d31927dce..b4d6d12101febdd4c5792ced9aae7600069d928e 100644 (file)
@@ -1 +1 @@
-0.7.3
+0.7.11
index 239085e3fe7ab36e6379950fcdd09e1734a797f0..0b7bbc8f31c23703595f9eb957d4ec98ceeed261 100644 (file)
@@ -95,7 +95,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_enable_debug.m4 \
        $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
        $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
        $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/.libtool-version \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -276,7 +277,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEBVERSION = @DEBVERSION@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
@@ -315,6 +315,7 @@ LIBLTDL = @LIBLTDL@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIBTOOL_VERSION = @LIBTOOL_VERSION@
 LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
 LIBYAML_LIBS = @LIBYAML_LIBS@
 LIPO = @LIPO@
index 4883f162d333bcb3322080925a8600d7486f559e..72e9c9a0e0404805a1d8efd53538cc851b736b33 100644 (file)
--- a/README.md
+++ b/README.md
@@ -222,7 +222,7 @@ YAML, or an invoice file given on the command line:
 
 ```c
        if (argc == 1)
-               fyd = fy_document_build_from_string(NULL, yaml);
+               fyd = fy_document_build_from_string(NULL, yaml, FY_NT);
        else
                fyd = fy_document_build_from_file(NULL, argv[1]);
        if (!fyd) {
@@ -255,13 +255,13 @@ address.
 ```c
        rc =
                /* set increased invoice number (modify existing node) */
-               fy_document_insert_at(fyd, "/invoice",
+               fy_document_insert_at(fyd, "/invoice", FY_NT,
                        fy_node_buildf(fyd, "%u", invoice_nr + 1)) ||
                /* add spouse (create new mapping pair) */
-               fy_document_insert_at(fyd, "/bill-to",
+               fy_document_insert_at(fyd, "/bill-to", FY_NT,
                        fy_node_buildf(fyd, "spouse: %s", "Doris")) ||
                /* add a second address */
-               fy_document_insert_at(fyd, "/bill-to",
+               fy_document_insert_at(fyd, "/bill-to", FY_NT,
                        fy_node_buildf(fyd, "delivery-address:\n"
                                            "  lines: |\n"
                                            "    1226 Windward Ave.\n"));
index fa33dd7279daaa9204f4a3884c6ee7f165145219..a2abd7626818ebaec8f4e6b2ca4e06c9110753a3 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libfyaml 0.7.3.
+# Generated by GNU Autoconf 2.69 for libfyaml 0.7.11.
 #
 # Report bugs to <pantelis.antoniou@konsulko.com>.
 #
@@ -592,8 +592,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='libfyaml'
 PACKAGE_TARNAME='libfyaml'
-PACKAGE_VERSION='0.7.3'
-PACKAGE_STRING='libfyaml 0.7.3'
+PACKAGE_VERSION='0.7.11'
+PACKAGE_STRING='libfyaml 0.7.11'
 PACKAGE_BUGREPORT='pantelis.antoniou@konsulko.com'
 PACKAGE_URL=''
 
@@ -758,7 +758,7 @@ CPPFLAGS
 LDFLAGS
 CFLAGS
 CC
-DEBVERSION
+LIBTOOL_VERSION
 EXTRA
 PATCH
 MINOR
@@ -1421,7 +1421,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libfyaml 0.7.3 to adapt to many kinds of systems.
+\`configure' configures libfyaml 0.7.11 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1492,7 +1492,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libfyaml 0.7.3:";;
+     short | recursive ) echo "Configuration of libfyaml 0.7.11:";;
    esac
   cat <<\_ACEOF
 
@@ -1633,7 +1633,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libfyaml configure 0.7.3
+libfyaml configure 0.7.11
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2223,7 +2223,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libfyaml $as_me 0.7.3, which was
+It was created by libfyaml $as_me 0.7.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -3091,7 +3091,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='libfyaml'
- VERSION='0.7.3'
+ VERSION='0.7.11'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3203,10 +3203,45 @@ MINOR=`echo $VERSION | cut -d. -f2 | cut -d- -f1`
 
 PATCH=`echo $VERSION | cut -d. -f3- | cut -d- -f1`
 
-EXTRA=`echo $VERSION | cut -d- -f2-`
+EXTRA=`echo $VERSION | cut -d- -f2- -s`
 
 
-DEBVERSION="$MAJOR.$MINOR"
+# libtool version is of the following format <current>:<revision>:<age>
+# and it is the library ABI version
+#
+# - Increase current when an interface has been added removed or changed
+# - Increase revision every time a release is made
+# - Increase age when changes are backwards compatible
+#
+# examples of semantic versioning progression mapping to libtool abi versions
+#
+# v0.7.4 -> v0.7.5 - patch number changes, backwards compatible (1)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v0.7.5 -> v0.8.0 - minor number changes, backwards compatible (same as (1)) (2)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v0.8.0 -> v0.9.0 - minor number changes, but breaks backwards compatibility - should not happen (3)
+#                    with semantic versioning for major version number >= 1, allowed for major == 0
+#                    increase revision, increase current, age reset to 0
+#
+# v0.9.0 -> v1.0.0 - major number changes, first public release (4)
+#                    increase current, set revision and age to 0
+#
+# v1.0.0 -> v1.0.1 - patch number changes, _must_ be backwards compatible (same as (1)) (5)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v1.0.1 -> v1.1.0 - minor number changes, backwards compatible (same as (5)) (6)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v1.1.0 -> v1.2.0 - minor number changes, breaking backwards compatibility (7)
+#                    XXX illegal in semantic versioning and should not happen
+#
+# v1.1.0 -> v2.0.0 - major number changes, breaking backwards compatibility (same as (4)) (8)
+#                    increase current, set revision and age to 0
+
+
+LIBTOOL_VERSION=1:1:0
 
 
 
@@ -18152,7 +18187,7 @@ cat >>confdefs.h <<_ACEOF
 _ACEOF
 
 
-for flag in -Wall -Wsign-compare; do
+for flag in -Wall -Wsign-compare -Wno-stringop-overflow; do
    as_CACHEVAR=`$as_echo "ax_cv_check_cflags_-pedantic -Werror_$flag" | $as_tr_sh`
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts $flag" >&5
 $as_echo_n "checking whether C compiler accepts $flag... " >&6; }
@@ -19580,7 +19615,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libfyaml $as_me 0.7.3, which was
+This file was extended by libfyaml $as_me 0.7.11, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -19646,7 +19681,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libfyaml config.status 0.7.3
+libfyaml config.status 0.7.11
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -21759,6 +21794,7 @@ echo "
     MAJOR.MINOR:           ${MAJOR}.${MINOR}
     PATCH:                 ${PATCH}
     EXTRA:                 ${EXTRA}
+    LIBTOOL_VERSION:       ${LIBTOOL_VERSION}
     prefix:                ${prefix}
     C compiler:            ${CC}
     CFLAGS:                ${CFLAGS}
index 4d198f53bc3da17f641d6ca72b175a882ed76aa4..8a495ec018f007451877686f0d3c9929a73c4721 100644 (file)
@@ -23,14 +23,49 @@ m4_ifdef([AM_EXTRA_RECURSIVE_TARGETS],
 m4_define(fyaml_major, `echo $VERSION | cut -d. -f1 | cut -d- -f1`)
 m4_define(fyaml_minor, `echo $VERSION | cut -d. -f2 | cut -d- -f1`)
 m4_define(fyaml_patch, `echo $VERSION | cut -d. -f3- | cut -d- -f1`)
-m4_define(fyaml_extra, `echo $VERSION | cut -d- -f2-`)
+m4_define(fyaml_extra, `echo $VERSION | cut -d- -f2- -s`)
 
 AC_SUBST(MAJOR, fyaml_major)
 AC_SUBST(MINOR, fyaml_minor)
 AC_SUBST(PATCH, fyaml_patch)
 AC_SUBST(EXTRA, fyaml_extra)
 
-AC_SUBST(DEBVERSION, "$MAJOR.$MINOR")
+# libtool version is of the following format <current>:<revision>:<age>
+# and it is the library ABI version
+#
+# - Increase current when an interface has been added removed or changed
+# - Increase revision every time a release is made
+# - Increase age when changes are backwards compatible
+#
+# examples of semantic versioning progression mapping to libtool abi versions
+#
+# v0.7.4 -> v0.7.5 - patch number changes, backwards compatible (1)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v0.7.5 -> v0.8.0 - minor number changes, backwards compatible (same as (1)) (2)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v0.8.0 -> v0.9.0 - minor number changes, but breaks backwards compatibility - should not happen (3)
+#                    with semantic versioning for major version number >= 1, allowed for major == 0
+#                    increase revision, increase current, age reset to 0
+#
+# v0.9.0 -> v1.0.0 - major number changes, first public release (4)
+#                    increase current, set revision and age to 0
+#
+# v1.0.0 -> v1.0.1 - patch number changes, _must_ be backwards compatible (same as (1)) (5)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v1.0.1 -> v1.1.0 - minor number changes, backwards compatible (same as (5)) (6)
+#                    increase revision, increase age (age must be <= current), current unchanged
+#
+# v1.1.0 -> v1.2.0 - minor number changes, breaking backwards compatibility (7)
+#                    XXX illegal in semantic versioning and should not happen
+#
+# v1.1.0 -> v2.0.0 - major number changes, breaking backwards compatibility (same as (4)) (8)
+#                    increase current, set revision and age to 0
+
+m4_define(fyaml_libtool_version, m4_normalize(m4_include([.libtool-version])))
+AC_SUBST(LIBTOOL_VERSION, fyaml_libtool_version)
 
 dnl AX_* requires 2.64
 m4_version_prereq(2.64, [AX_CHECK_ENABLE_DEBUG()], [true])
@@ -84,7 +119,7 @@ AC_CHECK_DECLS(environ)
 
 dnl for old autoconf version AX_APPEND_COMPILE_FLAGS does not work
 m4_version_prereq(2.64,
-        [AX_APPEND_COMPILE_FLAGS([-Wall -Wsign-compare],
+        [AX_APPEND_COMPILE_FLAGS([-Wall -Wsign-compare -Wno-stringop-overflow],
                                  [CFLAGS], [-pedantic -Werror])],
          [CFLAGS="$CFLAGS -Wall -Wsign-compare"])
 
@@ -296,6 +331,7 @@ echo "
     MAJOR.MINOR:           ${MAJOR}.${MINOR}
     PATCH:                 ${PATCH}
     EXTRA:                 ${EXTRA}
+    LIBTOOL_VERSION:       ${LIBTOOL_VERSION}
     prefix:                ${prefix}
     C compiler:            ${CC}
     CFLAGS:                ${CFLAGS}
index d93a49151a9e027f1ef72d3edc8929b3575b4083..9902908abca5b8fe218ab338a8570242b7e1e7df 100644 (file)
@@ -7,8 +7,16 @@ MANPAGES1 = $(BUILDDIR)/man/fy-tool.1
 doc-%: 
        srctree=@top_srcdir@ @SPHINX@ -M `echo $@ | sed -s 's/^doc-//g'` "@srcdir@" "$(BUILDDIR)"
 
+# if we have sphinx generate the manpages
 $(MANPAGES1): doc-man
 
+else
+
+# otherwise, install the canned ones
+MANPAGES1 = $(srcdir)/canned-man/fy-tool.1
+
+endif
+
 install-data-hook: $(MANPAGES1)
        $(MKDIR_P) "$(DESTDIR)$(mandir)/man1"
        @for i in "$(MANPAGES1)"; do \
@@ -18,14 +26,15 @@ install-data-hook: $(MANPAGES1)
        (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-filter.1)
        (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-testsuite.1)
        (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-join.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-ypath.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-compose.1)
 
 uninstall-hook:
        @for i in "$(MANPAGES1)"; do \
          rm -f "$(DESTDIR)$(mandir)/man1/`basename $$i`"; \
        done
-       (cd "$(DESTDIR)$(mandir)/man1" && rm -f fy-dump.1 fy-filter.1 fy-testsuite.1 fy-join.1)
-
-endif
+       (cd "$(DESTDIR)$(mandir)/man1" && \
+               rm -f fy-dump.1 fy-filter.1 fy-testsuite.1 fy-join.1 fy-ypath.1 fy-compose.1)
 
 clean-local:
        @rm -rf "$(BUILDDIR)"
@@ -38,4 +47,5 @@ EXTRA_DIST = \
        index.rst \
        intro.rst \
        libfyaml.rst \
-       man/fy-tool.rst
+       man/fy-tool.rst \
+       canned-man/fy-tool.1
index ca57d4bba0fcb1b25d8ab6d421e99b23a60e1e50..de17f1f8f536a64992d8478a5c743f98e5b01b51 100644 (file)
@@ -94,7 +94,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_enable_debug.m4 \
        $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
        $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
        $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/.libtool-version \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -152,7 +153,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEBVERSION = @DEBVERSION@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
@@ -191,6 +191,7 @@ LIBLTDL = @LIBLTDL@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIBTOOL_VERSION = @LIBTOOL_VERSION@
 LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
 LIBYAML_LIBS = @LIBYAML_LIBS@
 LIPO = @LIPO@
@@ -300,13 +301,17 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 BUILDDIR = _build
+
+# otherwise, install the canned ones
+@HAVE_SPHINX_FALSE@MANPAGES1 = $(srcdir)/canned-man/fy-tool.1
 @HAVE_SPHINX_TRUE@MANPAGES1 = $(BUILDDIR)/man/fy-tool.1
 EXTRA_DIST = \
        conf.py \
        index.rst \
        intro.rst \
        libfyaml.rst \
-       man/fy-tool.rst
+       man/fy-tool.rst \
+       canned-man/fy-tool.1
 
 all: all-am
 
@@ -423,8 +428,6 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-@HAVE_SPHINX_FALSE@install-data-hook:
-@HAVE_SPHINX_FALSE@uninstall-hook:
 clean: clean-am
 
 clean-am: clean-generic clean-libtool clean-local mostlyclean-am
@@ -542,23 +545,27 @@ uninstall-am:
 @HAVE_SPHINX_TRUE@doc-%: 
 @HAVE_SPHINX_TRUE@     srctree=@top_srcdir@ @SPHINX@ -M `echo $@ | sed -s 's/^doc-//g'` "@srcdir@" "$(BUILDDIR)"
 
+# if we have sphinx generate the manpages
 @HAVE_SPHINX_TRUE@$(MANPAGES1): doc-man
 
-@HAVE_SPHINX_TRUE@install-data-hook: $(MANPAGES1)
-@HAVE_SPHINX_TRUE@     $(MKDIR_P) "$(DESTDIR)$(mandir)/man1"
-@HAVE_SPHINX_TRUE@     @for i in "$(MANPAGES1)"; do \
-@HAVE_SPHINX_TRUE@       $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/man1"; \
-@HAVE_SPHINX_TRUE@     done
-@HAVE_SPHINX_TRUE@     (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-dump.1)
-@HAVE_SPHINX_TRUE@     (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-filter.1)
-@HAVE_SPHINX_TRUE@     (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-testsuite.1)
-@HAVE_SPHINX_TRUE@     (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-join.1)
-
-@HAVE_SPHINX_TRUE@uninstall-hook:
-@HAVE_SPHINX_TRUE@     @for i in "$(MANPAGES1)"; do \
-@HAVE_SPHINX_TRUE@       rm -f "$(DESTDIR)$(mandir)/man1/`basename $$i`"; \
-@HAVE_SPHINX_TRUE@     done
-@HAVE_SPHINX_TRUE@     (cd "$(DESTDIR)$(mandir)/man1" && rm -f fy-dump.1 fy-filter.1 fy-testsuite.1 fy-join.1)
+install-data-hook: $(MANPAGES1)
+       $(MKDIR_P) "$(DESTDIR)$(mandir)/man1"
+       @for i in "$(MANPAGES1)"; do \
+         $(INSTALL_DATA) $$i "$(DESTDIR)$(mandir)/man1"; \
+       done
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-dump.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-filter.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-testsuite.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-join.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-ypath.1)
+       (cd "$(DESTDIR)$(mandir)/man1" && $(LN_S) -f fy-tool.1 fy-compose.1)
+
+uninstall-hook:
+       @for i in "$(MANPAGES1)"; do \
+         rm -f "$(DESTDIR)$(mandir)/man1/`basename $$i`"; \
+       done
+       (cd "$(DESTDIR)$(mandir)/man1" && \
+               rm -f fy-dump.1 fy-filter.1 fy-testsuite.1 fy-join.1 fy-ypath.1 fy-compose.1)
 
 clean-local:
        @rm -rf "$(BUILDDIR)"
diff --git a/doc/canned-man/fy-tool.1 b/doc/canned-man/fy-tool.1
new file mode 100644 (file)
index 0000000..d9d4b56
--- /dev/null
@@ -0,0 +1,1005 @@
+.\" Man page generated from reStructuredText.
+.
+.TH "FY-TOOL" "1" "Jan 14, 2022" "" "libfyaml"
+.SH NAME
+fy-tool \- fy-tool documentation 
+.
+.nr rst2man-indent-level 0
+.
+.de1 rstReportMargin
+\\$1 \\n[an-margin]
+level \\n[rst2man-indent-level]
+level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
+-
+\\n[rst2man-indent0]
+\\n[rst2man-indent1]
+\\n[rst2man-indent2]
+..
+.de1 INDENT
+.\" .rstReportMargin pre:
+. RS \\$1
+. nr rst2man-indent\\n[rst2man-indent-level] \\n[an-margin]
+. nr rst2man-indent-level +1
+.\" .rstReportMargin post:
+..
+.de UNINDENT
+. RE
+.\" indent \\n[an-margin]
+.\" old: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.nr rst2man-indent-level -1
+.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
+.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
+..
+.SH SYNOPSIS
+.sp
+\fBfy\-tool\fP [\fIOPTIONS\fP] [<\fIfile\fP> ...]
+.sp
+\fBfy\-dump\fP [\fIOPTIONS\fP] [<\fIfile\fP> ...]
+.sp
+\fBfy\-testsuite\fP [\fIOPTIONS\fP] <\fIfile\fP>
+.sp
+\fBfy\-filter\fP [\fIOPTIONS\fP] [\-f*FILE*] [<\fIpath\fP> ...]
+.sp
+\fBfy\-join\fP [\fIOPTIONS\fP] [\-T*PATH*] [\-F*PATH*] [\-t*PATH*] [<\fIfile\fP> ...]
+.sp
+\fBfy\-ypath\fP [\fIOPTIONS\fP] <\fIypath\-expression> [<*file\fP> ...]
+.sp
+\fBfy\-compose\fP [\fIOPTIONS\fP] [<\fIfile\fP> ...]
+.SH DESCRIPTION
+.sp
+\fBfy\-tool\fP is a general YAML/JSON manipulation tool using \fIlibfyaml\fP\&.
+Its operation is different depending on how it\(aqs called, either via aliases
+named \fIfy\-dump\fP, \fIfy\-testsuite\fP, \fIfy\-filter\fP, \fIfy\-join\fP, or via the
+\fI\-\-dump\fP, \fI\-\-testsuite\fP, \fI\-\-filter\fP, \fI\-\-join\fP, \fI\-\-ypath\fP and \fI\-\-compose\fP options.
+.INDENT 0.0
+.IP \(bu 2
+In \fIdump\fP mode it will parse YAML/JSON input files and output YAML/JSON
+according to the output format options.
+.IP \(bu 2
+In \fItestsuite\fP mode it will parse a single YAML input file and output
+yaml testsuite reference output.
+.IP \(bu 2
+In \fIfilter\fP mode it will parse YAML/JSON files and output YAML/JSON
+output filtered according to the given option.
+.IP \(bu 2
+In \fIjoin\fP mode it will parse YAML/JSON files and join them into a single
+YAML/JSON document according to the given command line options.
+.IP \(bu 2
+In \fIypath\fP mode it will parse YAML/JSON files and execute a ypath query
+which will output a document stream according to the results. This is
+an experimental mode under development, where the syntax is not yet
+decided completely.
+.IP \(bu 2
+In \fIcompose\fP mode, it operates similarly to dump, but the document tree
+is created using the built\-in composer API.
+.UNINDENT
+.SH OPTIONS
+.sp
+A number of options are common for all the different modes of operation
+and they are as follows:
+Common options.INDENT 0.0
+.TP
+.B \-q, \-\-quiet
+Quiet operation, does not output informational messages at all.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-h, \-\-help
+Display usage information.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-v, \-\-version
+Display version information.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-I DIR, \-\-include=DIR
+Add the \fIDIR\fP  directory to the search path which will be used to locate a YAML/JSON file.
+The default path is set to ""
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-d LEVEL, \-\-debug\-level=LEVEL
+Set the minimum numeric debug level value of the library to \fILEVEL\fP\&.
+The numeric value must be in the range of 0 to 4 and their meaning is as follows:
+.INDENT 7.0
+.IP \(bu 2
+\fB0\fP (\fIDEBUG\fP)
+.sp
+Internal library debugging messages. No output is produced when the
+library was compiled with \fI\-\-disable\-debug\fP
+.IP \(bu 2
+\fB1\fP (\fIINFO\fP)
+.sp
+Informational messages about the internal operation of the library.
+.IP \(bu 2
+\fB2\fP (\fINOTICE\fP)
+.sp
+Messsages that could require attention.
+.IP \(bu 2
+\fB3\fP (\fIWARNING\fP)
+.sp
+A warning message, something is wrong, but operation can continue.
+This is the default value.
+.IP \(bu 2
+\fB4\fP (\fIERROR\fP)
+.sp
+A fatal error occured, it is impossible to continue.
+.UNINDENT
+.sp
+The default level is 3 (\fIWARNING\fP), which means that messages
+with level 3 and higher will be displayed.
+.UNINDENT
+Parser Options.INDENT 0.0
+.TP
+.B \-j JSONOPT, \-\-json=JSONOPT
+Marks the input files as JSON or YAML accordingly to:
+.INDENT 7.0
+.IP \(bu 2
+\fBno\fP
+.sp
+The input files are always in YAML mode.
+.IP \(bu 2
+\fBforce\fP
+.sp
+The input files are always set to JSON mode.
+.IP \(bu 2
+\fBauto\fP
+.sp
+The input files are set to JSON mode automatically when the
+file\(aqs extension is \fI\&.json\fP\&. This is the default.
+.UNINDENT
+.sp
+JSON support is complete so all valid JSON files are parsed according
+to JSON rules, even where those differ with YAML rules.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-yaml\-1.1
+Force YAML 1.1 rules, when input does not specify a version via a directive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-yaml\-1.2
+Force YAML 1.2 rules, when input does not specify a version via a directive.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-yaml\-1.3
+Force YAML 1.3 rules, when input does not specify a version via a directive.
+This option is experimental since the 1.3 spec is not yet released.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-disable\-accel
+Disable use of acceleration features; use less memory but potentially more CPU.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-disable\-buffering
+Disable use stdio bufferring, reads will be performed via unix fd reads. This
+may reduce latency when reading from a network file descriptor, or similar.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-disable\-depth\-limit
+Disable the object depth limit, which is usually set to a value near 60.
+Using this option is is possible to process even pathological inputs when
+using the default non\-recursive build mode.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-prefer\-recursive
+Prefer recursive build methods, instead of iterative. This field is merely here
+for evaluation purposes and will be removed in a future version.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-sloppy\-flow\-indentation
+Use sloppy flow indentation, where indentation is not taken into account in flow
+mode, even when the input is invalid YAML according to the spec.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ypath\-aliases
+Process aliases using ypaths. Experimental option.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-streaming
+Only valid when in \fBdump\fP mode, enables streaming mode. This means
+that no in\-memory graph tree is constructed, so indefinite and arbitrary
+large YAML input streams can be processed.
+.sp
+Note that in streaming mode:
+.INDENT 7.0
+.IP \(bu 2
+Key duplication checks are disabled.
+.IP \(bu 2
+No reording of key order is possible when emitting (i.e. \fI\-\-sort\fP is not available).
+.IP \(bu 2
+Alias resolution is not available (i.e. \fI\-\-resolve\fP).
+.UNINDENT
+.UNINDENT
+Resolver Options.INDENT 0.0
+.TP
+.B \-r, \-\-resolve
+Perform anchor and merge key resolution. By default this option is disabled.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-l, \-\-follow
+Follow aliases when performing path traversal. By default this option is disabled.
+.UNINDENT
+Testsuite Options.INDENT 0.0
+.TP
+.B \-\-disable\-flow\-markers
+Do not output flow\-markers for the testsuite output.
+.UNINDENT
+Emitter Options.INDENT 0.0
+.TP
+.B \-i INDENT, \-\-indent=INDENT
+Sets the emitter indent (in spaces). Default is \fB2\fP\&.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-w WIDTH, \-\-width=WIDTH
+Sets the preferred output width of the emitter. It is generally impossible
+to strictly adhere to this limit so this is treated as a hint at best.
+It not valid in any oneline output modes (i.e. \fIflow\-oneline\fP or \fIjson\-oneline\fP).
+Default value is 80.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-m MODE, \-\-mode=MODE
+Sets the output mode of the YAML emitted. Possible values are:
+.INDENT 7.0
+.IP \(bu 2
+\fBoriginal\fP
+.sp
+The original formatting used in the input. This is default mode.
+.IP \(bu 2
+\fBblock\fP
+.sp
+The output is forced to be in block mode. All flow constructs will
+be converted to block mode.
+.IP \(bu 2
+\fBflow\fP
+.sp
+The output is forced to be in flow mode. All block constructs will
+be converted to flow mode.
+.IP \(bu 2
+\fBflow\-oneline\fP
+.sp
+The output is forced to be in flow mode, but no newlines will be
+emitted; the output is going to be a (potentially very) long line.
+.IP \(bu 2
+\fBjson\fP
+.sp
+The output is forced to be in JSON mode. Note that it is impossible
+to output an arbitrary YAML file as JSON, so this may fail.
+.IP \(bu 2
+\fBjson\-oneline\fP
+.sp
+The output is forced to be in JSON mode and in a single line.
+.IP \(bu 2
+\fBdejson\fP
+.sp
+Output is in block YAML mode but with special care to convert
+JSON quoted strings in as non\-idiomatic YAML as possible.
+For example \fI{ foo: "this is a test" }\fP will be emitted as
+\fIfoo: this is a test\fP\&. YAML can handle scalars without using
+excessive quoting.
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-C MODE, \-\-color=MODE
+It is possible to colorize output using ANSI color escape sequences,
+and the mode can be one of:
+.INDENT 7.0
+.IP \(bu 2
+\fBoff\fP
+.sp
+Never colorize output.
+.IP \(bu 2
+\fBon\fP
+.sp
+Always colorize output.
+.IP \(bu 2
+\fBauto\fP
+.sp
+Automatically colorize output when the output is a terminal.
+This is the default.
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-V, \-\-visible
+Make all whitespace (spaces, unicode spaces and linebreaks) visible.
+Note that this is performed using UTF8 characters so it will not work
+on non\-UTF8 terminals, or a non\-UTF8 complete font.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-s, \-\-sort
+Sort keys on output. This option is disabled by default.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-c, \-\-comment
+Experimental output comments option. Enabled output while preserving comments.
+Disabled by default.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-strip\-labels
+Strip labels on output. Disabled by default.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-strip\-tags
+Strip tags on output. Disabled by default.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-strip\-doc
+Strip document indicators on output. Disabled by default.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-null\-output
+Do not generate any output, useful for profiling the parser.
+.UNINDENT
+YPATH options.INDENT 0.0
+.TP
+.B \-\-dump\-pathexpr
+Dump the produced path expression for debugging.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-no\-exec
+Do not execute the expression. Useful when used with \fI\-\-dump\-pathexpr\fP
+.UNINDENT
+Compose options.INDENT 0.0
+.TP
+.B \-\-dump\-path
+Dump the path while composing.
+.UNINDENT
+Tool mode select options.INDENT 0.0
+.TP
+.B \-\-dump
+Select \fIdump\fP mode of operation. This is the default.
+This mode is also enabled when the called binary is aliased to
+\fIfy\-dump\fP\&.
+.sp
+In this mode, all files provided in the command line will be dumped
+in one continuous stream, to the standard output, using document start
+indicators to mark the start of end new file.
+.sp
+If the file provided is \fI\-\fP then the input is the standard input.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-testsuite
+Select \fItestsuite\fP mode of operation.
+This mode is also enabled when the called binary is aliased to \fIfy\-testsuite\fP\&.
+.sp
+In this mode, a single YAML file is read and an event stream is
+generated which is the format used for \fIyaml\-testsuite\fP compliance.
+.sp
+If the file provided is \fI\-\fP then the input is the standard input.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-filter
+Select \fIfilter\fP mode of operation.
+This mode is also enabled when the called binary is aliased to \fIfy\-filter\fP\&.
+.sp
+In this mode, a single YAML file is read from the standard input for each path
+that is provided in the command line a document will be produced to the
+standard output.
+To use file instead of standard input use the \fI\-f/\-\-file\fP option.
+.sp
+If the file provided is \fI\-\fP then the input is the standard input.
+.INDENT 7.0
+.TP
+.B \-f FILE, \-\-file=FILE
+Use the given file as input instead of standard input.
+.sp
+If  first character of \fIFILE\fP is \fB>\fP the the input is the content of the option
+that follows.
+For example \-\-file ">foo: bar" is as \-\-file file.yaml with file.yaml "foo: bar"
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-join
+Select \fIjoin\fP mode of operation.
+This mode is also enabled when the called binary is aliased to \fIfy\-join\fP\&.
+.sp
+In this mode, multiple YAML files are joined into a single document, emitted
+to the standard output.
+.sp
+If the file provided is \fI\-\fP then the input is the standard input.
+.INDENT 7.0
+.TP
+.B \-T PATH, \-\-to=PATH
+The target path of the join. By default this is the root \fB/\fP\&.
+.sp
+If  first character of \fIFILE\fP is \fB>\fP the the input is the content of the option
+that follows.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B \-F PATH, \-\-from=PATH
+The origin path of the join (for each input). By default this is the root \fB/\fP\&.
+.sp
+If  first character of \fIFILE\fP is \fB>\fP the the input is the content of the option
+that follows.
+.UNINDENT
+.INDENT 7.0
+.TP
+.B \-t PATH, \-\-trim=PATH
+Trim path of the output of the join. By default this is the root \fB/\fP\&.
+.sp
+If  first character of \fIFILE\fP is \fB>\fP the the input is the content of the option
+that follows.
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-ypath
+Process files and output query results using ypath.
+.UNINDENT
+.INDENT 0.0
+.TP
+.B \-\-compose
+Use the composer API to build the document instead of direct events.
+.UNINDENT
+.SH EXAMPLES
+Example input files
+.sp
+We\(aqre going to be using a couple of YAML files in our examples.
+.sp
+invoice.yaml
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+# invoice.yaml
+invoice: 34843
+date   : !!str 2001\-01\-23
+bill\-to: &id001
+given  : Chris
+family : Dumars
+address:
+        lines: |
+        458 Walkman Dr.
+        Suite #292
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+simple\-anchors.yaml
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+# simple\-anchors.yaml
+foo: &label { bar: frooz }
+baz: *label
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+mergekeyspec.yaml
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+\-\-\-
+\- &CENTER { x: 1, y: 2 }
+\- &LEFT { x: 0, y: 2 }
+\- &BIG { r: 10 }
+\- &SMALL { r: 1 }
+
+# All the following maps are equal:
+
+\- # Explicit keys
+  x: 1
+  y: 2
+  r: 10
+  label: center/big
+
+\- # Merge one map
+  << : *CENTER
+  r: 10
+  label: center/big
+
+\- # Merge multiple maps
+  << : [ *CENTER, *BIG ]
+  label: center/big
+
+\- # Override
+  << : [ *BIG, *LEFT, *SMALL ]
+  x: 1
+  label: center/big
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+bomb.yaml
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+a: &a ["lol","lol","lol","lol","lol","lol","lol","lol","lol"]
+b: &b [*a,*a,*a,*a,*a,*a,*a,*a,*a]
+c: &c [*b,*b,*b,*b,*b,*b,*b,*b,*b]
+d: &d [*c,*c,*c,*c,*c,*c,*c,*c,*c]
+e: &e [*d,*d,*d,*d,*d,*d,*d,*d,*d]
+f: &f [*e,*e,*e,*e,*e,*e,*e,*e,*e]
+g: &g [*f,*f,*f,*f,*f,*f,*f,*f,*f]
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+fy\-dump examples.
+.sp
+Parse and dump generated YAML document tree in the original YAML form
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump invoice.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+invoice: 34843
+date: !!str 2001\-01\-23
+bill\-to: &id001
+given: Chris
+family: Dumars
+  address:
+  lines: |
+    458 Walkman Dr.
+    Suite #292
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Parse and dump generated YAML document tree in flow YAML form
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-mflow invoice.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+{
+  invoice: 34843,
+  date: !!str 2001\-01\-23,
+  bill\-to: &id001 {
+    given: Chris,
+    family: Dumars,
+    address: {
+      lines: "458 Walkman Dr.\enSuite #292\en"
+    }
+  }
+}
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Parse and dump generated YAML document from the input string
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-mjson ">foo: bar"
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+{
+  "foo": "bar"
+}
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Using the resolve option on the \fIsimple\-anchors.yaml\fP
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-r simple\-anchor.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+foo: &label {
+    bar: frooz
+  }
+baz: {
+    bar: frooz
+  }
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Stripping the labels too:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-r \-\-strip\-label simple\-anchor.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+foo: {
+    bar: frooz
+  }
+baz: {
+    bar: frooz
+  }
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Merge key support:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-r \-\-strip\-label mergekeyspec.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+\-\-\-
+\- {
+    x: 1,
+    y: 2
+  }
+\- {
+    x: 0,
+    y: 2
+  }
+\- {
+    r: 10
+  }
+\- {
+    r: 1
+  }
+\- x: 1
+  y: 2
+  r: 10
+  label: center/big
+\- y: 2
+  x: 1
+  r: 10
+  label: center/big
+\- r: 10
+  y: 2
+  x: 1
+  label: center/big
+\- y: 2
+  r: 10
+  x: 1
+  label: center/big
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Sorting option:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-dump \-s invoice.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+bill\-to: &id001
+  address:
+    lines: |
+      458 Walkman Dr.
+      Suite #292
+  family: Dumars
+  given: Chris
+date: !!str 2001\-01\-23
+invoice: 34843
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+fy\-testsuite example.
+.sp
+An example using the testsuite mode generates the following
+event stream from \fIinvoice.yaml\fP
+.sp
+Parse and dump test\-suite event format
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-testsuite invoice.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+fy\-filter examples.
+.sp
+Filter out from the \fI/bill\-to\fP path of \fIinvoice.yaml\fP
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ cat invoice.yaml | fy\-filter /bill\-to
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+&id001
+given: Chris
+family: Dumars
+address:
+  lines: |
+    458 Walkman Dr.
+    Suite #292
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Filter example with arrays (and use the \-\-file option)
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-filter \-\-file=mergekeyspec.yaml /5
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+\-\-\-
+<<: *CENTER
+r: 10
+label: center/big
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Follow anchors example
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-filter \-\-file=simple\-anchors.yaml /baz/bar
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+frooz
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Handle YAML bombs (if you can spare the memory and cpu time)
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-filter \-\-file=bomb.yaml \-r / | wc \-l
+6726047
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+You don\(aqt have to, you can just follow links to retrieve data.
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-filter \-\-file=stuff/bomb.yaml \-l \-\-strip\-label /g/0/1/2/3/4/5/6
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+"lol"
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Following links works with merge keys too:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-filter \-\-file=mergekeyspec.yaml \-l \-\-strip\-label /5/x
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+\-\-\- 1
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+fy\-join examples.
+.sp
+Joining two YAML files that have root mappings.
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-join simple\-anchors.yaml invoice.yaml
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+foo: &label {
+    bar: frooz
+  }
+baz: *label
+invoice: 34843
+date: !!str 2001\-01\-23
+bill\-to: &id001
+  given: Chris
+  family: Dumars
+  address:
+    lines: |
+      458 Walkman Dr.
+      Suite #292
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.sp
+Join two files with sequences at root:
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+$ fy\-join \-mblock ">[ foo, bar ]" ">[ baz ]"
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.INDENT 0.0
+.INDENT 3.5
+.sp
+.nf
+.ft C
+\- foo
+\- bar
+\- baz
+.ft P
+.fi
+.UNINDENT
+.UNINDENT
+.SH AUTHOR
+.sp
+Pantelis Antoniou <\fI\%pantelis.antoniou@konsulko.com\fP>
+.SH BUGS
+.INDENT 0.0
+.IP \(bu 2
+The only supported input and output character encoding is UTF8.
+.IP \(bu 2
+Sorting does not respect language settings.
+.IP \(bu 2
+There is no way for the user to specific a different coloring scheme.
+.UNINDENT
+.SH SEE ALSO
+.sp
+\fBlibfyaml(1)\fP
+.SH COPYRIGHT
+2019, Pantelis Antoniou
+.\" Generated by docutils manpage writer.
+.
index 5da4b9ea878c376ac471d760d002c21bc6a4245f..0d482f153c7982e3e6e84d753f2bca03edb3be62 100644 (file)
@@ -14,13 +14,17 @@ Synopsis
 
 **fy-join** [*OPTIONS*] [-T*PATH*] [-F*PATH*] [-t*PATH*] [<*file*> ...]
 
+**fy-ypath** [*OPTIONS*] <*ypath-expression> [<*file*> ...]
+
+**fy-compose** [*OPTIONS*] [<*file*> ...]
+
 Description
 -----------
 
 :program:`fy-tool` is a general YAML/JSON manipulation tool using `libfyaml`.
 Its operation is different depending on how it's called, either via aliases
 named `fy-dump`, `fy-testsuite`, `fy-filter`, `fy-join`, or via the
-`--dump`, `--testsuite`, `--filter`, `--join` options.
+`--dump`, `--testsuite`, `--filter`, `--join`, `--ypath` and `--compose` options.
 
 * In `dump` mode it will parse YAML/JSON input files and output YAML/JSON
   according to the output format options.
@@ -34,6 +38,14 @@ named `fy-dump`, `fy-testsuite`, `fy-filter`, `fy-join`, or via the
 * In `join` mode it will parse YAML/JSON files and join them into a single
   YAML/JSON document according to the given command line options.
 
+* In `ypath` mode it will parse YAML/JSON files and execute a ypath query
+  which will output a document stream according to the results. This is
+  an experimental mode under development, where the syntax is not yet
+  decided completely.
+
+* In `compose` mode, it operates similarly to dump, but the document tree
+  is created using the built-in composer API.
+
 Options
 -------
 
@@ -101,7 +113,7 @@ and they are as follows:
 
      The input files are always in YAML mode.
 
-   - **yes**
+   - **force**
 
      The input files are always set to JSON mode.
 
@@ -110,10 +122,50 @@ and they are as follows:
      The input files are set to JSON mode automatically when the
      file's extension is `.json`. This is the default.
 
-   Note that although libfyaml's YAML 1.2 support is complete, that simply
-   means that a valid JSON file will parse as YAML 1.2. However there
-   are instances where one requires strict JSON spec adherence, and
-   for invalid JSON to be rejected even when it's valid YAML 1.2.
+   JSON support is complete so all valid JSON files are parsed according
+   to JSON rules, even where those differ with YAML rules.
+
+.. option:: --yaml-1.1
+
+   Force YAML 1.1 rules, when input does not specify a version via a directive.
+
+.. option:: --yaml-1.2
+
+   Force YAML 1.2 rules, when input does not specify a version via a directive.
+
+.. option:: --yaml-1.3
+
+   Force YAML 1.3 rules, when input does not specify a version via a directive.
+   This option is experimental since the 1.3 spec is not yet released.
+
+.. option:: --disable-accel
+
+   Disable use of acceleration features; use less memory but potentially more CPU.
+
+.. option:: --disable-buffering
+
+   Disable use stdio bufferring, reads will be performed via unix fd reads. This
+   may reduce latency when reading from a network file descriptor, or similar.
+
+.. option:: --disable-depth-limit
+
+   Disable the object depth limit, which is usually set to a value near 60.
+   Using this option is is possible to process even pathological inputs when
+   using the default non-recursive build mode.
+
+.. option:: --prefer-recursive
+
+   Prefer recursive build methods, instead of iterative. This field is merely here
+   for evaluation purposes and will be removed in a future version.
+
+.. option:: --sloppy-flow-indentation
+
+   Use sloppy flow indentation, where indentation is not taken into account in flow
+   mode, even when the input is invalid YAML according to the spec.
+
+.. option:: --ypath-aliases
+
+   Process aliases using ypaths. Experimental option.
 
 .. option:: --streaming
 
@@ -137,6 +189,12 @@ and they are as follows:
 
    Follow aliases when performing path traversal. By default this option is disabled.
 
+.. rubric:: Testsuite Options
+
+.. option:: --disable-flow-markers
+
+   Do not output flow-markers for the testsuite output.
+
 .. rubric:: Emitter Options
 
 .. option:: -i INDENT, --indent=INDENT
@@ -235,6 +293,26 @@ and they are as follows:
 
    Strip document indicators on output. Disabled by default.
 
+.. option:: --null-output
+
+   Do not generate any output, useful for profiling the parser.
+
+.. rubric:: YPATH options
+
+.. option:: --dump-pathexpr
+
+   Dump the produced path expression for debugging.
+
+.. option:: --no-exec
+
+   Do not execute the expression. Useful when used with `--dump-pathexpr`
+
+.. rubric:: Compose options
+
+.. option:: --dump-path
+
+   Dump the path while composing.
+
 .. rubric:: Tool mode select options
 
 .. option:: --dump
@@ -310,6 +388,14 @@ and they are as follows:
       If  first character of `FILE` is **>** the the input is the content of the option
       that follows.
 
+.. option:: --ypath
+
+   Process files and output query results using ypath.
+
+.. option:: --compose
+
+   Use the composer API to build the document instead of direct events.
+
 Examples
 --------
 
index 61ffdb256f7593ea10cda814efa70bed89d7dad9..bf01077f7457b98c06c075cfe073c301f2108bcb 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * libfyaml.h - Main header file of the public interface
  *
- * Copyright (c) 2019 Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ * Copyright (c) 2019-2021 Pantelis Antoniou <pantelis.antoniou@konsulko.com>
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -60,6 +60,7 @@ struct fy_path_expr;
 struct fy_path_exec;
 struct fy_path_component;
 struct fy_path;
+struct fy_document_iterator;
 
 
 #ifndef FY_BIT
@@ -309,6 +310,7 @@ enum fy_error_module {
  * @FYPCF_JSON_NONE: Never enable JSON input mode
  * @FYPCF_JSON_FORCE: Force JSON mode always
  * @FYPCF_YPATH_ALIASES: Enable YPATH aliases mode
+ * @FYPCF_ALLOW_DUPLICATE_KEYS: Allow duplicate keys on mappings
  */
 enum fy_parse_cfg_flags {
        FYPCF_QUIET                     = FY_BIT(0),
@@ -330,6 +332,7 @@ enum fy_parse_cfg_flags {
        FYPCF_JSON_NONE                 = FYPCF_JSON(1),
        FYPCF_JSON_FORCE                = FYPCF_JSON(2),
        FYPCF_YPATH_ALIASES             = FY_BIT(18),
+       FYPCF_ALLOW_DUPLICATE_KEYS      = FY_BIT(19),
 };
 
 #define FYPCF_DEFAULT_PARSE    (0)
@@ -460,6 +463,123 @@ enum fy_scalar_style {
        FYSS_MAX,
 };
 
+/**
+ * struct fy_event_stream_start_data - stream start event data
+ *
+ * @stream_start: The token that started the stream
+ */
+struct fy_event_stream_start_data {
+       struct fy_token *stream_start;
+};
+
+/*
+ * struct fy_event_stream_end_data - stream end event data
+ *
+ * @stream_end: The token that ended the stream
+ */
+struct fy_event_stream_end_data {
+       struct fy_token *stream_end;
+};
+
+/*
+ * struct fy_event_document_start_data - doument start event data
+ *
+ * @document_start: The token that started the document, or NULL if
+ *                 the document was implicitly started.
+ * @document_state: The state of the document (i.e. information about
+ *                 the YAML version and configured tags)
+ * @implicit: True if the document started implicitly
+ */
+struct fy_event_document_start_data {
+       struct fy_token *document_start;
+       struct fy_document_state *document_state;
+       bool implicit;
+};
+
+/*
+ * struct fy_event_document_end_data - doument end event data
+ *
+ * @document_end: The token that ended the document, or NULL if the
+ *               document was implicitly ended
+ * @implicit: True if the document ended implicitly
+ */
+struct fy_event_document_end_data {
+       struct fy_token *document_end;
+       bool implicit;
+};
+
+/*
+ * struct fy_event_alias_data - alias event data
+ *
+ * @anchor: The anchor token definining this alias.
+ */
+struct fy_event_alias_data {
+       struct fy_token *anchor;
+};
+
+/*
+ * struct fy_event_scalar_data - scalar event data
+ *
+ * @.anchor: anchor token or NULL
+ * @tag: tag token or NULL
+ * @value: scalar value token (cannot be NULL)
+ * @tag_implicit: true if the tag was implicit or explicit
+ */
+struct fy_event_scalar_data {
+       struct fy_token *anchor;
+       struct fy_token *tag;
+       struct fy_token *value;
+       bool tag_implicit;
+};
+
+/*
+ * struct fy_event_sequence_start_data - sequence start event data
+ *
+ * @anchor: anchor token or NULL
+ * @tag: tag token or NULL
+ * @sequence_start: sequence start value token or NULL if the sequence
+ *                 was started implicitly
+ */
+struct fy_event_sequence_start_data {
+       struct fy_token *anchor;
+       struct fy_token *tag;
+       struct fy_token *sequence_start;
+};
+
+/*
+ * struct fy_event_sequence_end_data - sequence end event data
+ *
+ * @sequence_end: The token that ended the sequence, or NULL if
+ *               the sequence was implicitly ended
+ */
+struct fy_event_sequence_end_data {
+       struct fy_token *sequence_end;
+};
+
+/*
+ * struct fy_event_mapping_start_data - mapping start event data
+ *
+ * @anchor: anchor token or NULL
+ * @tag: tag token or NULL
+ * @mapping_start: mapping start value token or NULL if the mapping
+ *                 was started implicitly
+ */
+struct fy_event_mapping_start_data {
+       struct fy_token *anchor;
+       struct fy_token *tag;
+       struct fy_token *mapping_start;
+};
+
+/*
+ * struct fy_event_mapping_end_data - mapping end event data
+ *
+ * @mapping_end: The token that ended the mapping, or NULL if
+ *               the mapping was implicitly ended
+ */
+struct fy_event_mapping_end_data {
+       struct fy_token *mapping_end;
+};
+
 /**
  * struct fy_event - Event generated by the parser
  *
@@ -470,115 +590,95 @@ enum fy_scalar_style {
  *
  * @stream_start: Stream start information, it is valid when
  *                &fy_event->type is &enum FYET_STREAM_START
- * @stream_start.stream_start: The token that started the stream
- * @stream_end:Stream end information, it is valid when
- *             &fy_event->type is &enum FYET_STREAM_END
- * @stream_end.stream_end: The token that ended the stream
- *
+ * @stream_end: Stream end information, it is valid when
+ *                &fy_event->type is &enum FYET_STREAM_END
  * @document_start: Document start information, it is valid when
  *                  &fy_event->type is &enum FYET_DOCUMENT_START
- * @document_start.document_start: The token that started the document, or
- *                                 NULL if the document was implicitly
- *                                 started
- * @document_start.document_state: The state of the document (i.e. information
- *                                 about the YAML version and configured tags)
- * @document_start.implicit: True if the document started implicitly
- *
  * @document_end: Document end information, it is valid when
  *                &fy_event->type is &enum FYET_DOCUMENT_END
- * @document_end.document_end: The token that ended the document, or
- *                             NULL if the document was implicitly ended
- * @document_end.implicit: True if the document ended implicitly
- *
  * @alias: Alias information, it is valid when
  *         &fy_event->type is &enum FYET_ALIAS
- * @alias.anchor: The anchor token definining this alias.
- *
  * @scalar: Scalar information, it is valid when
  *          &fy_event->type is &enum FYET_SCALAR
- * @scalar.anchor: anchor token or NULL
- * @scalar.tag: tag token or NULL
- * @scalar.value: scalar value token (cannot be NULL)
- * @scalar.tag_implicit: true if the tag was implicit or explicit
- *
  * @sequence_start: Sequence start information, it is valid when
  *                  &fy_event->type is &enum FYET_SEQUENCE_START
- * @sequence_start.anchor: anchor token or NULL
- * @sequence_start.tag: tag token or NULL
- * @sequence_start.sequence_start: sequence start value token or NULL if
- *                                 the sequence was started implicitly
  * @sequence_end: Sequence end information, it is valid when
  *                &fy_event->type is &enum FYET_SEQUENCE_END
- * @sequence_end.sequence_end: The token that ended the sequence, or
- *                             NULL if the sequence was implicitly ended
- *
  * @mapping_start: Mapping start information, it is valid when
  *                 &fy_event->type is &enum FYET_MAPPING_START
- * @mapping_start.anchor: anchor token or NULL
- * @mapping_start.tag: tag token or NULL
- * @mapping_start.mapping_start: mapping start value token or NULL if
- *                                 the mapping was started implicitly
  * @mapping_end: Mapping end information, it is valid when
  *               &fy_event->type is &enum FYET_MAPPING_END
- * @mapping_end.mapping_end: The token that ended the mapping, or
- *                             NULL if the mapping was implicitly ended
  */
 struct fy_event {
        enum fy_event_type type;
        /* anonymous union */
        union {
-               struct {
-                       struct fy_token *stream_start;
-               } stream_start;
-
-               struct {
-                       struct fy_token *stream_end;
-               } stream_end;
-
-               struct {
-                       struct fy_token *document_start;
-                       struct fy_document_state *document_state;
-                       bool implicit;
-               } document_start;
-
-               struct {
-                       struct fy_token *document_end;
-                       bool implicit;
-               } document_end;
-
-               struct {
-                       struct fy_token *anchor;
-               } alias;
-
-               struct {
-                       struct fy_token *anchor;
-                       struct fy_token *tag;
-                       struct fy_token *value;
-                       bool tag_implicit;
-               } scalar;
-
-               struct {
-                       struct fy_token *anchor;
-                       struct fy_token *tag;
-                       struct fy_token *sequence_start;
-               } sequence_start;
-
-               struct {
-                       struct fy_token *sequence_end;
-               } sequence_end;
-
-               struct {
-                       struct fy_token *anchor;
-                       struct fy_token *tag;
-                       struct fy_token *mapping_start;
-               } mapping_start;
-
-               struct {
-                       struct fy_token *mapping_end;
-               } mapping_end;
+               struct fy_event_stream_start_data stream_start;
+               struct fy_event_stream_end_data stream_end;
+               struct fy_event_document_start_data document_start;
+               struct fy_event_document_end_data document_end;
+               struct fy_event_alias_data alias;
+               struct fy_event_scalar_data scalar;
+               struct fy_event_sequence_start_data sequence_start;
+               struct fy_event_sequence_end_data sequence_end;
+               struct fy_event_mapping_start_data mapping_start;
+               struct fy_event_mapping_end_data mapping_end;
        };
 };
 
+/**
+ * fy_event_data() - Get a pointer to the event data
+ *
+ * Some languages *cough*golang*cough* really don't like
+ * unions, and anonymous unions in particular.
+ *
+ * You should not have to use this in other language bindings.
+ *
+ * @fye: The event
+ *
+ * Returns:
+ * A pointer to the event data structure, or NULL if the
+ * event is invalid
+ */
+static inline void *
+fy_event_data(struct fy_event *fye)
+{
+       if (!fye)
+               return NULL;
+
+       /* note that the unions should all be laid out
+        * at the same address, but play it straight and
+        * hope the optimizer will figure this is all
+        * the same...
+        */
+       switch (fye->type) {
+       case FYET_STREAM_START:
+               return &fye->stream_start;
+       case FYET_STREAM_END:
+               return &fye->stream_end;
+       case FYET_DOCUMENT_START:
+               return &fye->document_start;
+       case FYET_DOCUMENT_END:
+               return &fye->document_end;
+       case FYET_ALIAS:
+               return &fye->alias;
+       case FYET_SCALAR:
+               return &fye->scalar;
+       case FYET_SEQUENCE_START:
+               return &fye->sequence_start;
+       case FYET_SEQUENCE_END:
+               return &fye->sequence_end;
+       case FYET_MAPPING_START:
+               return &fye->mapping_start;
+       case FYET_MAPPING_END:
+               return &fye->mapping_end;
+       default:
+               break;
+       }
+
+       return NULL;
+}
+
 /**
  * fy_library_version() - Return the library version string
  *
@@ -832,6 +932,21 @@ int fy_parser_set_input_callback(struct fy_parser *fyp, void *user,
                ssize_t (*callback)(void *user, void *buf, size_t count))
        FY_EXPORT;
 
+/**
+ * fy_parser_set_input_db() - Set the parser to process the given file descriptor
+ *
+ * Point the parser to use @fd for processing.
+ *
+ * @fyp: The parser
+ * @fd: The file descriptor to use
+ *
+ * Returns:
+ * zero on success, -1 on error
+ */
+int
+fy_parser_set_input_fd(struct fy_parser *fyp, int fd)
+       FY_EXPORT;
+
 /**
  * fy_parser_parse() - Parse and return the next event.
  *
@@ -987,6 +1102,9 @@ enum fy_comment_placement {
  * fy_token_get_comment() - Get zero terminated comment of a token
  *
  * @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:
  * A pointer to a zero terminated text representation of the token comment.
@@ -1435,6 +1553,7 @@ enum fy_emitter_write_type {
  * @FYECF_STRIP_TAGS: Strip tags when emitting
  * @FYECF_STRIP_DOC: Strip document tags and markers when emitting
  * @FYECF_NO_ENDING_NEWLINE: Do not output ending new line (useful for single line mode)
+ * @FYECF_STRIP_EMPTY_KV: Remove all keys with empty values from the output (not available in streaming mode)
  * @FYECF_INDENT_DEFAULT: Default emit output indent
  * @FYECF_INDENT_1: Output indent is 1
  * @FYECF_INDENT_2: Output indent is 2
@@ -1457,6 +1576,7 @@ enum fy_emitter_write_type {
  * @FYECF_MODE_JSON_TP: Emit using JSON mode (type preserving)
  * @FYECF_MODE_JSON_ONELINE: Emit using JSON mode (non type preserving, one line)
  * @FYECF_MODE_DEJSON: Emit YAML trying to pretify JSON
+ * @FYECF_MODE_PRETTY: Emit YAML that tries to look good
  * @FYECF_DOC_START_MARK_AUTO: Automatically generate document start markers if required
  * @FYECF_DOC_START_MARK_OFF: Do not generate document start markers
  * @FYECF_DOC_START_MARK_ON: Always generate document start markers
@@ -1478,6 +1598,7 @@ enum fy_emitter_cfg_flags {
        FYECF_STRIP_TAGS                = FY_BIT(3),
        FYECF_STRIP_DOC                 = FY_BIT(4),
        FYECF_NO_ENDING_NEWLINE         = FY_BIT(5),
+       FYECF_STRIP_EMPTY_KV            = FY_BIT(6),
        FYECF_INDENT_DEFAULT            = FYECF_INDENT(0),
        FYECF_INDENT_1                  = FYECF_INDENT(1),
        FYECF_INDENT_2                  = FYECF_INDENT(2),
@@ -1500,6 +1621,7 @@ enum fy_emitter_cfg_flags {
        FYECF_MODE_JSON_TP              = FYECF_MODE(5),
        FYECF_MODE_JSON_ONELINE         = FYECF_MODE(6),
        FYECF_MODE_DEJSON               = FYECF_MODE(7),
+       FYECF_MODE_PRETTY               = FYECF_MODE(8),
        FYECF_DOC_START_MARK_AUTO       = FYECF_DOC_START_MARK(0),
        FYECF_DOC_START_MARK_OFF        = FYECF_DOC_START_MARK(1),
        FYECF_DOC_START_MARK_ON         = FYECF_DOC_START_MARK(2),
@@ -1609,6 +1731,21 @@ int
 fy_emitter_set_diag(struct fy_emitter *emit, struct fy_diag *diag)
        FY_EXPORT;
 
+/**
+ * fy_emitter_set_finalizer() - Set emitter finalizer
+ *
+ * Set a method callback to be called when the emitter
+ * is disposed of. If finalizer is NULL, then the method
+ * is removed.
+ *
+ * @emit: The emitter to replace the diagnostic object
+ * @finalizer: The finalizer callback
+ */
+void
+fy_emitter_set_finalizer(struct fy_emitter *emit,
+               void (*finalizer)(struct fy_emitter *emit))
+       FY_EXPORT;
+
 /**
  * struct fy_emitter_default_output_data - emitter default output configuration
  *
@@ -1826,6 +1963,23 @@ fy_emit_document_to_file(struct fy_document *fyd,
                         const char *filename)
        FY_EXPORT;
 
+/**
+ * fy_emit_document_to_fd() - Emit a document to a file descriptor
+ *
+ * Emits a document from the root to the given file descriptor
+ *
+ * @fyd: The document to emit
+ * @flags: The emitter flags to use
+ * @fd: The file descriptor to output to
+ *
+ * Returns:
+ * 0 on success, -1 on error
+ */
+int
+fy_emit_document_to_fd(struct fy_document *fyd,
+                      enum fy_emitter_cfg_flags flags, int fd)
+       FY_EXPORT;
+
 /**
  * fy_emit_document_to_buffer() - Emit a document to a buffer
  *
@@ -1844,7 +1998,7 @@ fy_emit_document_to_file(struct fy_document *fyd,
 int
 fy_emit_document_to_buffer(struct fy_document *fyd,
                           enum fy_emitter_cfg_flags flags,
-                          char *buf, int size)
+                          char *buf, size_t size)
        FY_EXPORT;
 
 /**
@@ -1884,7 +2038,7 @@ fy_emit_document_to_string(struct fy_document *fyd,
  */
 int
 fy_emit_node_to_buffer(struct fy_node *fyn, enum fy_emitter_cfg_flags flags,
-                      char *buf, int size)
+                      char *buf, size_t size)
        FY_EXPORT;
 
 /**
@@ -1906,6 +2060,80 @@ fy_emit_node_to_string(struct fy_node *fyn, enum fy_emitter_cfg_flags flags)
 #define fy_emit_node_to_string_alloca(_fyn, _flags) \
        FY_ALLOCA_COPY_FREE(fy_emit_node_to_string((_fyn), (_flags)), FY_NT)
 
+/**
+ * fy_emit_to_buffer() - Create an emitter for buffer output.
+ *
+ * Creates a special purpose emitter for buffer output.
+ * Calls to fy_emit_event() populate the buffer.
+ * The contents are retreived by a call to fy_emit_to_buffer_collect()
+ *
+ * @flags: The emitter flags to use
+ * @buf: Pointer to the buffer area to fill
+ * @size: Size of the buffer
+ *
+ * Returns:
+ * The newly created emitter or NULL on error.
+ */
+struct fy_emitter *
+fy_emit_to_buffer(enum fy_emitter_cfg_flags flags, char *buf, size_t size)
+       FY_EXPORT;
+
+/**
+ * fy_emit_to_buffer_collect() - Collect the buffer emitter output
+ *
+ * Collects the output of the emitter which was created by
+ * fy_emit_to_buffer() and populated using fy_emit_event() calls.
+ * The NULL terminated returned buffer is the same as the one used in the
+ * fy_emit_to_buffer() call and the sizep argument will be filled with
+ * the size of the buffer.
+ *
+ * @emit: The emitter
+ * @sizep: Pointer to the size to be filled
+ *
+ * Returns:
+ * The buffer or NULL in case of an error.
+ */
+char *
+fy_emit_to_buffer_collect(struct fy_emitter *emit, size_t *sizep)
+       FY_EXPORT;
+
+/**
+ * fy_emit_to_string() - Create an emitter to create a dynamically
+ *                       allocated string.
+ *
+ * Creates a special purpose emitter for output to a dynamically
+ * allocated string.
+ * Calls to fy_emit_event() populate the buffer.
+ * The contents are retreived by a call to fy_emit_to_string_collect()
+ *
+ * @flags: The emitter flags to use
+ *
+ * Returns:
+ * The newly created emitter or NULL on error.
+ */
+struct fy_emitter *
+fy_emit_to_string(enum fy_emitter_cfg_flags flags)
+       FY_EXPORT;
+
+/**
+ * fy_emit_to_string_collect() - Collect the string emitter output
+ *
+ * Collects the output of the emitter which was created by
+ * fy_emit_to_string() and populated using fy_emit_event() calls.
+ * The NULL terminated returned buffer is dynamically allocated
+ * and must be freed via a call to free().
+ * The sizep argument will be filled with the size of the buffer.
+ *
+ * @emit: The emitter
+ * @sizep: Pointer to the size to be filled
+ *
+ * Returns:
+ * The dynamically allocated string or NULL in case of an error.
+ */
+char *
+fy_emit_to_string_collect(struct fy_emitter *emit, size_t *sizep)
+       FY_EXPORT;
+
 /**
  * fy_node_copy() - Copy a node, associating the new node with the given document
  *
@@ -2964,10 +3192,10 @@ fy_node_get_path_relative_to(struct fy_node *fyn_parent, struct fy_node *fyn)
  * If no such parent is found then returns the absolute path
  * from the start of the document.
  *
- * --- &foo
- * foo: &bar
- *     bar
- * baz
+ *   --- &foo
+ *   foo: &bar
+ *       bar
+ *   baz
  *
  * - The short path of /foo is \*foo
  * - The short path of /foo/bar is \*bar
@@ -4701,6 +4929,30 @@ struct fy_diag_cfg {
        int module_width;
 };
 
+/**
+ * struct fy_diag_error - A collected diagnostic error
+ *
+ * @type: Error type
+ * @module: The module
+ * @fyt: The token (may be NULL)
+ * @msg: The message to be output alongside
+ * @file: The file which contained the input
+ * @line: The line at the error
+ * @column: The column at the error
+ *
+ * This structure contains information about an error
+ * being collected by the diagnostic object.
+ */
+struct fy_diag_error {
+       enum fy_error_type type;
+       enum fy_error_module module;
+       struct fy_token *fyt;
+       const char *msg;
+       const char *file;
+       int line;
+       int column;
+};
+
 /**
  * fy_diag_create() - Create a diagnostic object
  *
@@ -4829,6 +5081,20 @@ void
 fy_diag_reset_error(struct fy_diag *diag)
        FY_EXPORT;
 
+/**
+ * fy_diag_set_collect_errors() - Collect errors instead of outputting
+ *
+ * Set the collect errors mode. When true instead of outputting to
+ * the diagnostic interface, errors are collected for later
+ * retrieval.
+ *
+ * @diag: The diagnostic object
+ * @collect_errors: The collect errors mode
+ */
+void
+fy_diag_set_collect_errors(struct fy_diag *diag, bool collect_errors)
+       FY_EXPORT;
+
 /**
  * fy_diag_cfg_default() - Fill in the configuration structure
  *                        with defaults
@@ -5097,6 +5363,22 @@ fy_diag_node_override_report(struct fy_diag *diag, struct fy_node *fyn,
        __attribute__((format(printf, 7, 8)))
        FY_EXPORT;
 
+/**
+ * fy_diag_errors_iterate() - Iterate over the errors of a diagnostic object
+ *
+ * This method iterates over all the errors collected on the diagnostic object.
+ * The start of the iteration is signalled by a NULL in \*prevp.
+ *
+ * @diag: The diagnostic object
+ * @prevp: The previous result iterator
+ *
+ * Returns:
+ * The next errors or NULL when there are not any more.
+ */
+struct fy_diag_error *
+fy_diag_errors_iterate(struct fy_diag *diag, void **prevp)
+       FY_EXPORT;
+
 /**
  * enum fy_path_parse_cfg_flags - Path parse configuration flags
  *
@@ -5422,10 +5704,10 @@ fy_path_exec_results_iterate(struct fy_path_exec *fypx, void **prevp)
  * @FYTT_PE_GT: Greater than operator
  * @FYTT_PE_LTE: Less or equal than operator
  * @FYTT_PE_GTE: Greater or equal than operator
- * @FYTT_PE_PLUS: Plus operator
- * @FYTT_PE_MINUS: Minus operator
- * @FYTT_PE_MULT: Multiply operator
- * @FYTT_PE_DIV: Divide operator
+ * @FYTT_SE_PLUS: Plus operator
+ * @FYTT_SE_MINUS: Minus operator
+ * @FYTT_SE_MULT: Multiply operator
+ * @FYTT_SE_DIV: Divide operator
  * @FYTT_PE_METHOD: Path expression method (chained)
  * @FYTT_SE_METHOD: Scalar expression method (non chained)
  */
@@ -6056,6 +6338,22 @@ bool
 fy_document_state_end_implicit(struct fy_document_state *fyds)
        FY_EXPORT;
 
+/**
+ * fy_document_state_json_mode() - Input was JSON?
+ *
+ * Find out if a document state object's document was
+ * created by a JSON input.
+ * Note that for synthetic documents this method returns false.
+ *
+ * @fyds: The document state object
+ *
+ * Returns:
+ * true if document was created in JSON mode, false otherwise
+ */
+bool
+fy_document_state_json_mode(struct fy_document_state *fyds)
+       FY_EXPORT;
+
 /**
  * fy_document_state_tag_directive_iterate() - Iterate over the tag
  *                                            directives of a document state
@@ -6537,6 +6835,19 @@ struct fy_token *
 fy_path_component_mapping_get_scalar_key(struct fy_path_component *fypc)
        FY_EXPORT;
 
+/**
+ * fy_path_component_mapping_get_scalar_key_tag() - Get the scalar key's tag of a mapping
+ *
+ * @fypc: The mapping path component to return it's scalar key's tag
+ *
+ * Returns:
+ * a non NULL tag token if the mapping contains a scalar key with a tag or
+ * NULL in case of an error, or if the component has a complex key
+ */
+struct fy_token *
+fy_path_component_mapping_get_scalar_key_tag(struct fy_path_component *fypc)
+       FY_EXPORT;
+
 /**
  * fy_path_component_mapping_get_complex_key() - Get the complex key of a mapping
  *
@@ -6550,6 +6861,29 @@ struct fy_document *
 fy_path_component_mapping_get_complex_key(struct fy_path_component *fypc)
        FY_EXPORT;
 
+/**
+ * fy_path_component_get_text() - Get the textual representation of a path component
+ *
+ * Given a path component, return a malloc'ed string which contains
+ * the textual representation of it.
+ *
+ * Note that this method will only return fully completed components and not
+ * ones that are in the building process.
+ *
+ * @fypc: The path component to get it's textual representation
+ *
+ * Returns:
+ * The textual representation of the path component, NULL on error, or
+ * if the component has not been completely built during the composition
+ * of a complex key.
+ * The string must be free'ed using free.
+ */
+char *
+fy_path_component_get_text(struct fy_path_component *fypc)
+       FY_EXPORT;
+
+#define fy_path_component_get_text_alloca(_fypc) \
+       FY_ALLOCA_COPY_FREE(fy_path_component_get_text((_fypc)), FY_NT)
 /**
  * fy_path_depth() - Get the depth of a path
  *
@@ -6648,7 +6982,7 @@ fy_path_in_mapping_key(struct fy_path *fypp)
        FY_EXPORT;
 
 /**
- * fy_path_in_mapping_key() - Check if the path is in a mapping value state
+ * fy_path_in_mapping_value() - Check if the path is in a mapping value state
  *
  * @fypp: The path
  *
@@ -6673,7 +7007,31 @@ fy_path_in_mapping_value(struct fy_path *fypp)
  * true if the path is located within a collectin root state
  */
 bool
-fy_path_is_collection_root(struct fy_path *fypp)
+fy_path_in_collection_root(struct fy_path *fypp)
+       FY_EXPORT;
+
+/**
+ * fy_path_get_root_user_data() - Return the userdata associated with the path root
+ *
+ * @fypp: The path
+ *
+ * Returns:
+ * The user data associated with the root of the path, or NULL if no path
+ */
+void *
+fy_path_get_root_user_data(struct fy_path *fypp)
+       FY_EXPORT;
+
+/**
+ * fy_path_set_root_user_data() - Set the user data associated with the root
+ *
+ * Note, no error condition if not a path
+ *
+ * @fypp: The path
+ * @data: The data to set as root data
+ */
+void
+fy_path_set_root_user_data(struct fy_path *fypp, void *data)
        FY_EXPORT;
 
 /**
@@ -6701,7 +7059,7 @@ fy_path_component_get_mapping_key_user_data(struct fy_path_component *fypc)
        FY_EXPORT;
 
 /**
- * fy_path_component_get_sequence_data() - Return the userdata associated with the sequence
+ * fy_path_component_get_sequence_user_data() - Return the userdata associated with the sequence
  *
  * @fypc: The path component
  *
@@ -6781,6 +7139,173 @@ struct fy_path_component *
 fy_path_last_not_collection_root_component(struct fy_path *fypp)
        FY_EXPORT;
 
+/**
+ * fy_document_iterator_create() - Create a document iterator
+ *
+ * Creates a document iterator, that can trawl through a document
+ * without using recursion.
+ *
+ * Returns:
+ * The newly created document iterator or NULL on error
+ */
+struct fy_document_iterator *
+fy_document_iterator_create(void)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_destroy() - Destroy the given document iterator
+ *
+ * Destroy a document iterator created earlier via fy_document_iterator_create().
+ *
+ * @fydi: The document iterator to destroy
+ */
+void
+fy_document_iterator_destroy(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_event_free() - Free an event that was created by a document iterator
+ *
+ * Free (possibly recycling) an event that was created by a document iterator.
+ *
+ * @fydi: The document iterator that created the event
+ * @fye: The event
+ */
+void
+fy_document_iterator_event_free(struct fy_document_iterator *fydi, struct fy_event *fye)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_stream_start() - Create a stream start event using the iterator
+ *
+ * Creates a stream start event on the document iterator and advances the internal state
+ * of it accordingly.
+ *
+ * @fydi: The document iterator to create the event
+ *
+ * Returns:
+ * The newly created stream start event, or NULL on error.
+ */
+struct fy_event *
+fy_document_iterator_stream_start(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_stream_end() - Create a stream end event using the iterator
+ *
+ * Creates a stream end event on the document iterator and advances the internal state
+ * of it accordingly.
+ *
+ * @fydi: The document iterator to create the event
+ *
+ * Returns:
+ * The newly created stream end event, or NULL on error.
+ */
+struct fy_event *
+fy_document_iterator_stream_end(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_document_start() - Create a document start event using the iterator
+ *
+ * Creates a document start event on the document iterator and advances the internal state
+ * of it accordingly. The document must not be released until an error, cleanup or a call
+ * to fy_document_iterator_document_end().
+ *
+ * @fydi: The document iterator to create the event
+ * @fyd: The document containing the document state that is used in the event
+ *
+ * Returns:
+ * The newly created document start event, or NULL on error.
+ */
+struct fy_event *
+fy_document_iterator_document_start(struct fy_document_iterator *fydi, struct fy_document *fyd)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_document_end() - Create a document end event using the iterator
+ *
+ * Creates a document end event on the document iterator and advances the internal state
+ * of it accordingly. The document that was used earlier in the call of
+ * fy_document_iterator_document_start() can now be released.
+ *
+ * @fydi: The document iterator to create the event
+ *
+ * Returns:
+ * The newly created document end event, or NULL on error.
+ */
+struct fy_event *
+fy_document_iterator_document_end(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_body_next() - Create document body events until the end
+ *
+ * Creates the next document body, depth first until the end of the document.
+ * The events are created depth first and are in same exact sequence that the
+ * original events that created the document.
+ *
+ * That means that the finite event stream that generated the document is losslesly
+ * preserved in such a way that the document tree representation is functionally
+ * equivalent.
+ *
+ * Repeated calls to this function will generate a stream of SCALAR, ALIAS, SEQUENCE
+ * START, SEQUENCE END, MAPPING START and MAPPING END events, returning NULL at the
+ * end of the body event stream.
+ *
+ * @fydi: The document iterator to create the event
+ *
+ * Returns:
+ * The newly created document body event or NULL at an error, or an end of the
+ * event stream. Use fy_document_iterator_get_error() to check if an error occured.
+ */
+struct fy_event *
+fy_document_iterator_body_next(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_node_start() - Start a document node iteration run using a starting point
+ *
+ * Starts an iteration run starting at the given node.
+ *
+ * @fydi: The document iterator to run with
+ * @fyn: The iterator root for the iteration
+ */
+void
+fy_document_iterator_node_start(struct fy_document_iterator *fydi, struct fy_node *fyn)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_node_next() - Return the next node in the iteration sequence
+ *
+ * Returns a pointer to the next node iterating using as a start the node given
+ * at fy_document_iterator_node_start(). The first node returned will be that,
+ * followed by all the remaing nodes in the subtree.
+ *
+ * @fydi: The document iterator to use for the iteration
+ *
+ * Returns:
+ * The next node in the iteration sequence or NULL at the end, or if an error occured.
+ */
+struct fy_node *
+fy_document_iterator_node_next(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
+/**
+ * fy_document_iterator_get_error() - Get the error state of the document iterator
+ *
+ * Returns the error state of the iterator. If it's in error state, return true
+ * and reset the iterator to the state just after creation.
+ *
+ * @fydi: The document iterator to use for checking it's error state.
+ *
+ * Returns:
+ * true if it was in an error state, false otherwise.
+ */
+bool
+fy_document_iterator_get_error(struct fy_document_iterator *fydi)
+       FY_EXPORT;
+
 #ifdef __cplusplus
 }
 #endif
index bf9d8d50fa6849f6f41f82e0a18cd4e7bbd53707..cde577a68e4ed86b48ddac55f9088146f24b959d 100644 (file)
@@ -6,5 +6,5 @@ includedir=@includedir@
 Name: libfyaml
 Description: Fancy YAML 1.3 parser library
 Version: @PACKAGE_VERSION@
-Libs: -L${libdir} -lfyaml-@MAJOR@.@MINOR@ @PTHREAD_LIBS@
+Libs: -L${libdir} -lfyaml @PTHREAD_LIBS@
 Cflags: -I${includedir} @PTHREAD_CFLAGS@
index 67688a9b7c247296042a13609e630280d84ef18c..9c06116e9902f4ed637e3648d9144db5e75f70e9 100644 (file)
@@ -3,8 +3,8 @@ AM_CPPFLAGS = \
         -I$(top_srcdir)/include
 AM_CFLAGS =
 
-lib_LTLIBRARIES = libfyaml-@MAJOR@.@MINOR@.la
-libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
+lib_LTLIBRARIES = libfyaml.la
+libfyaml_la_SOURCES = \
         lib/fy-parse.c lib/fy-parse.h \
        lib/fy-utf8.c lib/fy-utf8.h \
        lib/fy-types.c lib/fy-types.h \
@@ -18,6 +18,7 @@ libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
        lib/fy-input.c lib/fy-input.h \
        lib/fy-docstate.c lib/fy-docstate.h \
        lib/fy-doc.c lib/fy-doc.h \
+       lib/fy-docbuilder.c lib/fy-docbuilder.h \
        lib/fy-emit.c lib/fy-emit.h lib/fy-emit-accum.h \
        lib/fy-utils.c lib/fy-utils.h \
        lib/fy-event.h lib/fy-event.c \
@@ -27,13 +28,12 @@ libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
        lib/fy-path.c lib/fy-path.h \
        lib/fy-composer.c lib/fy-composer.h
 
-libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS = $(AM_CPPFLAGS) \
+libfyaml_la_CPPFLAGS = $(AM_CPPFLAGS) \
                                       -I$(top_srcdir)/src/lib \
                                       -I$(top_srcdir)/src/xxhash
-libfyaml_@MAJOR@_@MINOR@_la_CFLAGS = $(AM_CFLAGS)
-libfyaml_@MAJOR@_@MINOR@_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) \
-                     $(VERSIONING_LDFLAGS) \
-                     -version-info 0:0:0
+libfyaml_la_CFLAGS = $(AM_CFLAGS)
+libfyaml_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) \
+                     -version $(LIBTOOL_VERSION)
 
 bin_PROGRAMS =
 noinst_PROGRAMS =
@@ -50,7 +50,7 @@ libfyaml_parser_CPPFLAGS = $(AM_CPPFLAGS) \
                           -I$(top_srcdir)/src/valgrind \
                           -I$(top_srcdir)/src/lib \
                           -I$(top_srcdir)/src/xxhash
-libfyaml_parser_LDADD = $(AM_LDADD) $(LIBYAML_LIBS) libfyaml-@MAJOR@.@MINOR@.la
+libfyaml_parser_LDADD = $(AM_LDADD) $(LIBYAML_LIBS) libfyaml.la
 libfyaml_parser_CFLAGS = $(AM_CFLAGS) $(LIBYAML_CFLAGS)
 
 libfyaml_parser_LDFLAGS = $(AM_LDFLAGS)
@@ -63,7 +63,7 @@ fy_tool_SOURCES = \
        valgrind/fy-valgrind.h
 
 fy_tool_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/valgrind
-fy_tool_LDADD = $(AM_LDADD) libfyaml-@MAJOR@.@MINOR@.la
+fy_tool_LDADD = $(AM_LDADD) libfyaml.la
 fy_tool_CFLAGS = $(AM_CFLAGS)
 fy_tool_LDFLAGS = $(AM_LDFLAGS)
 
index 65e9b362d094685391bdc7799e98911d1af2b143..fd57f093384e16e0a2aa9169e915ab84cdede906 100644 (file)
@@ -100,7 +100,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_enable_debug.m4 \
        $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
        $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
        $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/.libtool-version \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \
@@ -139,43 +140,32 @@ am__uninstall_files_from_dir = { \
 am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(bindir)" \
        "$(DESTDIR)$(includedir)"
 LTLIBRARIES = $(lib_LTLIBRARIES)
-libfyaml_@MAJOR@_@MINOR@_la_LIBADD =
+libfyaml_la_LIBADD =
 am__dirstamp = $(am__leading_dot)dirstamp
-am_libfyaml_@MAJOR@_@MINOR@_la_OBJECTS =  \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo \
-       xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo \
-       lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo
-libfyaml_@MAJOR@_@MINOR@_la_OBJECTS =  \
-       $(am_libfyaml_@MAJOR@_@MINOR@_la_OBJECTS)
+am_libfyaml_la_OBJECTS = lib/libfyaml_la-fy-parse.lo \
+       lib/libfyaml_la-fy-utf8.lo lib/libfyaml_la-fy-types.lo \
+       lib/libfyaml_la-fy-diag.lo lib/libfyaml_la-fy-dump.lo \
+       lib/libfyaml_la-fy-atom.lo lib/libfyaml_la-fy-ctype.lo \
+       lib/libfyaml_la-fy-token.lo lib/libfyaml_la-fy-input.lo \
+       lib/libfyaml_la-fy-docstate.lo lib/libfyaml_la-fy-doc.lo \
+       lib/libfyaml_la-fy-docbuilder.lo lib/libfyaml_la-fy-emit.lo \
+       lib/libfyaml_la-fy-utils.lo lib/libfyaml_la-fy-event.lo \
+       xxhash/libfyaml_la-xxhash.lo lib/libfyaml_la-fy-accel.lo \
+       lib/libfyaml_la-fy-walk.lo lib/libfyaml_la-fy-path.lo \
+       lib/libfyaml_la-fy-composer.lo
+libfyaml_la_OBJECTS = $(am_libfyaml_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
 am__v_lt_1 = 
-libfyaml_@MAJOR@_@MINOR@_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
-       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
-       $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) \
-       $(libfyaml_@MAJOR@_@MINOR@_la_LDFLAGS) $(LDFLAGS) -o $@
+libfyaml_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libfyaml_la_CFLAGS) \
+       $(CFLAGS) $(libfyaml_la_LDFLAGS) $(LDFLAGS) -o $@
 @HAVE_LIBYAML_TRUE@am__EXEEXT_1 = libfyaml-parser$(EXEEXT)
 PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
 am_fy_tool_OBJECTS = tool/fy_tool-fy-tool.$(OBJEXT)
 fy_tool_OBJECTS = $(am_fy_tool_OBJECTS)
-fy_tool_DEPENDENCIES = libfyaml-@MAJOR@.@MINOR@.la
+fy_tool_DEPENDENCIES = libfyaml.la
 fy_tool_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(fy_tool_CFLAGS) \
        $(CFLAGS) $(fy_tool_LDFLAGS) $(LDFLAGS) -o $@
@@ -185,8 +175,7 @@ am__libfyaml_parser_SOURCES_DIST = internal/libfyaml-parser.c \
 libfyaml_parser_OBJECTS = $(am_libfyaml_parser_OBJECTS)
 am__DEPENDENCIES_1 =
 @HAVE_LIBYAML_TRUE@libfyaml_parser_DEPENDENCIES =  \
-@HAVE_LIBYAML_TRUE@    $(am__DEPENDENCIES_1) \
-@HAVE_LIBYAML_TRUE@    libfyaml-@MAJOR@.@MINOR@.la
+@HAVE_LIBYAML_TRUE@    $(am__DEPENDENCIES_1) libfyaml.la
 libfyaml_parser_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
        $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
        $(libfyaml_parser_CFLAGS) $(CFLAGS) $(libfyaml_parser_LDFLAGS) \
@@ -225,10 +214,10 @@ AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(libfyaml_@MAJOR@_@MINOR@_la_SOURCES) $(fy_tool_SOURCES) \
+SOURCES = $(libfyaml_la_SOURCES) $(fy_tool_SOURCES) \
        $(libfyaml_parser_SOURCES)
-DIST_SOURCES = $(libfyaml_@MAJOR@_@MINOR@_la_SOURCES) \
-       $(fy_tool_SOURCES) $(am__libfyaml_parser_SOURCES_DIST)
+DIST_SOURCES = $(libfyaml_la_SOURCES) $(fy_tool_SOURCES) \
+       $(am__libfyaml_parser_SOURCES_DIST)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -285,7 +274,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEBVERSION = @DEBVERSION@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
@@ -324,6 +312,7 @@ LIBLTDL = @LIBLTDL@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIBTOOL_VERSION = @LIBTOOL_VERSION@
 LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
 LIBYAML_LIBS = @LIBYAML_LIBS@
 LIPO = @LIPO@
@@ -437,8 +426,8 @@ AM_CPPFLAGS = \
         -I$(top_srcdir)/include
 
 AM_CFLAGS = 
-lib_LTLIBRARIES = libfyaml-@MAJOR@.@MINOR@.la
-libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
+lib_LTLIBRARIES = libfyaml.la
+libfyaml_la_SOURCES = \
         lib/fy-parse.c lib/fy-parse.h \
        lib/fy-utf8.c lib/fy-utf8.h \
        lib/fy-types.c lib/fy-types.h \
@@ -452,6 +441,7 @@ libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
        lib/fy-input.c lib/fy-input.h \
        lib/fy-docstate.c lib/fy-docstate.h \
        lib/fy-doc.c lib/fy-doc.h \
+       lib/fy-docbuilder.c lib/fy-docbuilder.h \
        lib/fy-emit.c lib/fy-emit.h lib/fy-emit-accum.h \
        lib/fy-utils.c lib/fy-utils.h \
        lib/fy-event.h lib/fy-event.c \
@@ -461,14 +451,13 @@ libfyaml_@MAJOR@_@MINOR@_la_SOURCES = \
        lib/fy-path.c lib/fy-path.h \
        lib/fy-composer.c lib/fy-composer.h
 
-libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS = $(AM_CPPFLAGS) \
+libfyaml_la_CPPFLAGS = $(AM_CPPFLAGS) \
                                       -I$(top_srcdir)/src/lib \
                                       -I$(top_srcdir)/src/xxhash
 
-libfyaml_@MAJOR@_@MINOR@_la_CFLAGS = $(AM_CFLAGS)
-libfyaml_@MAJOR@_@MINOR@_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) \
-                     $(VERSIONING_LDFLAGS) \
-                     -version-info 0:0:0
+libfyaml_la_CFLAGS = $(AM_CFLAGS)
+libfyaml_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) \
+                     -version $(LIBTOOL_VERSION)
 
 @HAVE_LIBYAML_TRUE@libfyaml_parser_SOURCES = \
 @HAVE_LIBYAML_TRUE@    internal/libfyaml-parser.c \
@@ -479,7 +468,7 @@ libfyaml_@MAJOR@_@MINOR@_la_LDFLAGS = $(AM_LDFLAGS) $(AM_LIBLDFLAGS) \
 @HAVE_LIBYAML_TRUE@                       -I$(top_srcdir)/src/lib \
 @HAVE_LIBYAML_TRUE@                       -I$(top_srcdir)/src/xxhash
 
-@HAVE_LIBYAML_TRUE@libfyaml_parser_LDADD = $(AM_LDADD) $(LIBYAML_LIBS) libfyaml-@MAJOR@.@MINOR@.la
+@HAVE_LIBYAML_TRUE@libfyaml_parser_LDADD = $(AM_LDADD) $(LIBYAML_LIBS) libfyaml.la
 @HAVE_LIBYAML_TRUE@libfyaml_parser_CFLAGS = $(AM_CFLAGS) $(LIBYAML_CFLAGS)
 @HAVE_LIBYAML_TRUE@libfyaml_parser_LDFLAGS = $(AM_LDFLAGS)
 fy_tool_SOURCES = \
@@ -487,7 +476,7 @@ fy_tool_SOURCES = \
        valgrind/fy-valgrind.h
 
 fy_tool_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/valgrind
-fy_tool_LDADD = $(AM_LDADD) libfyaml-@MAJOR@.@MINOR@.la
+fy_tool_LDADD = $(AM_LDADD) libfyaml.la
 fy_tool_CFLAGS = $(AM_CFLAGS)
 fy_tool_LDFLAGS = $(AM_LDFLAGS)
 include_HEADERS = \
@@ -567,33 +556,35 @@ lib/$(am__dirstamp):
 lib/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) lib/$(DEPDIR)
        @: > lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-parse.lo: lib/$(am__dirstamp) \
+       lib/$(DEPDIR)/$(am__dirstamp)
+lib/libfyaml_la-fy-utf8.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-types.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-diag.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-dump.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-atom.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-ctype.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-token.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-input.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-docstate.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-doc.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-docbuilder.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-emit.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-utils.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-event.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
 xxhash/$(am__dirstamp):
        @$(MKDIR_P) xxhash
@@ -601,19 +592,19 @@ xxhash/$(am__dirstamp):
 xxhash/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) xxhash/$(DEPDIR)
        @: > xxhash/$(DEPDIR)/$(am__dirstamp)
-xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo: xxhash/$(am__dirstamp) \
+xxhash/libfyaml_la-xxhash.lo: xxhash/$(am__dirstamp) \
        xxhash/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-accel.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-walk.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-path.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo: lib/$(am__dirstamp) \
+lib/libfyaml_la-fy-composer.lo: lib/$(am__dirstamp) \
        lib/$(DEPDIR)/$(am__dirstamp)
 
-libfyaml-@MAJOR@.@MINOR@.la: $(libfyaml_@MAJOR@_@MINOR@_la_OBJECTS) $(libfyaml_@MAJOR@_@MINOR@_la_DEPENDENCIES) $(EXTRA_libfyaml_@MAJOR@_@MINOR@_la_DEPENDENCIES) 
-       $(AM_V_CCLD)$(libfyaml_@MAJOR@_@MINOR@_la_LINK) -rpath $(libdir) $(libfyaml_@MAJOR@_@MINOR@_la_OBJECTS) $(libfyaml_@MAJOR@_@MINOR@_la_LIBADD) $(LIBS)
+libfyaml.la: $(libfyaml_la_OBJECTS) $(libfyaml_la_DEPENDENCIES) $(EXTRA_libfyaml_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(libfyaml_la_LINK) -rpath $(libdir) $(libfyaml_la_OBJECTS) $(libfyaml_la_LIBADD) $(LIBS)
 install-binPROGRAMS: $(bin_PROGRAMS)
        @$(NORMAL_INSTALL)
        @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
@@ -710,26 +701,27 @@ distclean-compile:
        -rm -f *.tab.c
 
 @AMDEP_TRUE@@am__include@ @am__quote@internal/$(DEPDIR)/libfyaml_parser-libfyaml-parser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-event.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-input.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-path.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-token.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-types.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-accel.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-atom.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-composer.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-ctype.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-diag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-doc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-docbuilder.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-docstate.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-dump.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-emit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-event.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-input.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-parse.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-path.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-token.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-types.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-utf8.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-utils.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/libfyaml_la-fy-walk.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tool/$(DEPDIR)/fy_tool-fy-tool.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@xxhash/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-xxhash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@xxhash/$(DEPDIR)/libfyaml_la-xxhash.Plo@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -755,138 +747,145 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo: lib/fy-parse.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo `test -f 'lib/fy-parse.c' || echo '$(srcdir)/'`lib/fy-parse.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-parse.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-parse.lo: lib/fy-parse.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-parse.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-parse.Tpo -c -o lib/libfyaml_la-fy-parse.lo `test -f 'lib/fy-parse.c' || echo '$(srcdir)/'`lib/fy-parse.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-parse.Tpo lib/$(DEPDIR)/libfyaml_la-fy-parse.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-parse.c' object='lib/libfyaml_la-fy-parse.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-parse.lo `test -f 'lib/fy-parse.c' || echo '$(srcdir)/'`lib/fy-parse.c
+
+lib/libfyaml_la-fy-utf8.lo: lib/fy-utf8.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-utf8.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-utf8.Tpo -c -o lib/libfyaml_la-fy-utf8.lo `test -f 'lib/fy-utf8.c' || echo '$(srcdir)/'`lib/fy-utf8.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-utf8.Tpo lib/$(DEPDIR)/libfyaml_la-fy-utf8.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-utf8.c' object='lib/libfyaml_la-fy-utf8.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-parse.lo `test -f 'lib/fy-parse.c' || echo '$(srcdir)/'`lib/fy-parse.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-utf8.lo `test -f 'lib/fy-utf8.c' || echo '$(srcdir)/'`lib/fy-utf8.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo: lib/fy-utf8.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo `test -f 'lib/fy-utf8.c' || echo '$(srcdir)/'`lib/fy-utf8.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-utf8.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-types.lo: lib/fy-types.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-types.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-types.Tpo -c -o lib/libfyaml_la-fy-types.lo `test -f 'lib/fy-types.c' || echo '$(srcdir)/'`lib/fy-types.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-types.Tpo lib/$(DEPDIR)/libfyaml_la-fy-types.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-types.c' object='lib/libfyaml_la-fy-types.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utf8.lo `test -f 'lib/fy-utf8.c' || echo '$(srcdir)/'`lib/fy-utf8.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-types.lo `test -f 'lib/fy-types.c' || echo '$(srcdir)/'`lib/fy-types.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo: lib/fy-types.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-types.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo `test -f 'lib/fy-types.c' || echo '$(srcdir)/'`lib/fy-types.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-types.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-types.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-types.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-diag.lo: lib/fy-diag.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-diag.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-diag.Tpo -c -o lib/libfyaml_la-fy-diag.lo `test -f 'lib/fy-diag.c' || echo '$(srcdir)/'`lib/fy-diag.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-diag.Tpo lib/$(DEPDIR)/libfyaml_la-fy-diag.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-diag.c' object='lib/libfyaml_la-fy-diag.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-types.lo `test -f 'lib/fy-types.c' || echo '$(srcdir)/'`lib/fy-types.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-diag.lo `test -f 'lib/fy-diag.c' || echo '$(srcdir)/'`lib/fy-diag.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo: lib/fy-diag.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo `test -f 'lib/fy-diag.c' || echo '$(srcdir)/'`lib/fy-diag.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-diag.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-dump.lo: lib/fy-dump.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-dump.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-dump.Tpo -c -o lib/libfyaml_la-fy-dump.lo `test -f 'lib/fy-dump.c' || echo '$(srcdir)/'`lib/fy-dump.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-dump.Tpo lib/$(DEPDIR)/libfyaml_la-fy-dump.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-dump.c' object='lib/libfyaml_la-fy-dump.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-diag.lo `test -f 'lib/fy-diag.c' || echo '$(srcdir)/'`lib/fy-diag.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-dump.lo `test -f 'lib/fy-dump.c' || echo '$(srcdir)/'`lib/fy-dump.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo: lib/fy-dump.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo `test -f 'lib/fy-dump.c' || echo '$(srcdir)/'`lib/fy-dump.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-dump.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-atom.lo: lib/fy-atom.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-atom.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-atom.Tpo -c -o lib/libfyaml_la-fy-atom.lo `test -f 'lib/fy-atom.c' || echo '$(srcdir)/'`lib/fy-atom.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-atom.Tpo lib/$(DEPDIR)/libfyaml_la-fy-atom.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-atom.c' object='lib/libfyaml_la-fy-atom.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-dump.lo `test -f 'lib/fy-dump.c' || echo '$(srcdir)/'`lib/fy-dump.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-atom.lo `test -f 'lib/fy-atom.c' || echo '$(srcdir)/'`lib/fy-atom.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo: lib/fy-atom.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo `test -f 'lib/fy-atom.c' || echo '$(srcdir)/'`lib/fy-atom.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-atom.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-ctype.lo: lib/fy-ctype.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-ctype.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-ctype.Tpo -c -o lib/libfyaml_la-fy-ctype.lo `test -f 'lib/fy-ctype.c' || echo '$(srcdir)/'`lib/fy-ctype.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-ctype.Tpo lib/$(DEPDIR)/libfyaml_la-fy-ctype.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-ctype.c' object='lib/libfyaml_la-fy-ctype.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-atom.lo `test -f 'lib/fy-atom.c' || echo '$(srcdir)/'`lib/fy-atom.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-ctype.lo `test -f 'lib/fy-ctype.c' || echo '$(srcdir)/'`lib/fy-ctype.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo: lib/fy-ctype.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo `test -f 'lib/fy-ctype.c' || echo '$(srcdir)/'`lib/fy-ctype.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-ctype.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-token.lo: lib/fy-token.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-token.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-token.Tpo -c -o lib/libfyaml_la-fy-token.lo `test -f 'lib/fy-token.c' || echo '$(srcdir)/'`lib/fy-token.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-token.Tpo lib/$(DEPDIR)/libfyaml_la-fy-token.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-token.c' object='lib/libfyaml_la-fy-token.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-ctype.lo `test -f 'lib/fy-ctype.c' || echo '$(srcdir)/'`lib/fy-ctype.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-token.lo `test -f 'lib/fy-token.c' || echo '$(srcdir)/'`lib/fy-token.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo: lib/fy-token.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-token.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo `test -f 'lib/fy-token.c' || echo '$(srcdir)/'`lib/fy-token.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-token.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-token.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-token.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-input.lo: lib/fy-input.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-input.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-input.Tpo -c -o lib/libfyaml_la-fy-input.lo `test -f 'lib/fy-input.c' || echo '$(srcdir)/'`lib/fy-input.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-input.Tpo lib/$(DEPDIR)/libfyaml_la-fy-input.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-input.c' object='lib/libfyaml_la-fy-input.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-token.lo `test -f 'lib/fy-token.c' || echo '$(srcdir)/'`lib/fy-token.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-input.lo `test -f 'lib/fy-input.c' || echo '$(srcdir)/'`lib/fy-input.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo: lib/fy-input.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-input.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo `test -f 'lib/fy-input.c' || echo '$(srcdir)/'`lib/fy-input.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-input.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-input.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-input.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-docstate.lo: lib/fy-docstate.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-docstate.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-docstate.Tpo -c -o lib/libfyaml_la-fy-docstate.lo `test -f 'lib/fy-docstate.c' || echo '$(srcdir)/'`lib/fy-docstate.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-docstate.Tpo lib/$(DEPDIR)/libfyaml_la-fy-docstate.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-docstate.c' object='lib/libfyaml_la-fy-docstate.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-input.lo `test -f 'lib/fy-input.c' || echo '$(srcdir)/'`lib/fy-input.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-docstate.lo `test -f 'lib/fy-docstate.c' || echo '$(srcdir)/'`lib/fy-docstate.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo: lib/fy-docstate.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo `test -f 'lib/fy-docstate.c' || echo '$(srcdir)/'`lib/fy-docstate.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-docstate.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-doc.lo: lib/fy-doc.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-doc.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-doc.Tpo -c -o lib/libfyaml_la-fy-doc.lo `test -f 'lib/fy-doc.c' || echo '$(srcdir)/'`lib/fy-doc.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-doc.Tpo lib/$(DEPDIR)/libfyaml_la-fy-doc.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-doc.c' object='lib/libfyaml_la-fy-doc.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-docstate.lo `test -f 'lib/fy-docstate.c' || echo '$(srcdir)/'`lib/fy-docstate.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-doc.lo `test -f 'lib/fy-doc.c' || echo '$(srcdir)/'`lib/fy-doc.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo: lib/fy-doc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo `test -f 'lib/fy-doc.c' || echo '$(srcdir)/'`lib/fy-doc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-doc.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-docbuilder.lo: lib/fy-docbuilder.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-docbuilder.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-docbuilder.Tpo -c -o lib/libfyaml_la-fy-docbuilder.lo `test -f 'lib/fy-docbuilder.c' || echo '$(srcdir)/'`lib/fy-docbuilder.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-docbuilder.Tpo lib/$(DEPDIR)/libfyaml_la-fy-docbuilder.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-docbuilder.c' object='lib/libfyaml_la-fy-docbuilder.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-doc.lo `test -f 'lib/fy-doc.c' || echo '$(srcdir)/'`lib/fy-doc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-docbuilder.lo `test -f 'lib/fy-docbuilder.c' || echo '$(srcdir)/'`lib/fy-docbuilder.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo: lib/fy-emit.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo `test -f 'lib/fy-emit.c' || echo '$(srcdir)/'`lib/fy-emit.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-emit.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-emit.lo: lib/fy-emit.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-emit.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-emit.Tpo -c -o lib/libfyaml_la-fy-emit.lo `test -f 'lib/fy-emit.c' || echo '$(srcdir)/'`lib/fy-emit.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-emit.Tpo lib/$(DEPDIR)/libfyaml_la-fy-emit.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-emit.c' object='lib/libfyaml_la-fy-emit.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-emit.lo `test -f 'lib/fy-emit.c' || echo '$(srcdir)/'`lib/fy-emit.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-emit.lo `test -f 'lib/fy-emit.c' || echo '$(srcdir)/'`lib/fy-emit.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo: lib/fy-utils.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo `test -f 'lib/fy-utils.c' || echo '$(srcdir)/'`lib/fy-utils.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-utils.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-utils.lo: lib/fy-utils.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-utils.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-utils.Tpo -c -o lib/libfyaml_la-fy-utils.lo `test -f 'lib/fy-utils.c' || echo '$(srcdir)/'`lib/fy-utils.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-utils.Tpo lib/$(DEPDIR)/libfyaml_la-fy-utils.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-utils.c' object='lib/libfyaml_la-fy-utils.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-utils.lo `test -f 'lib/fy-utils.c' || echo '$(srcdir)/'`lib/fy-utils.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-utils.lo `test -f 'lib/fy-utils.c' || echo '$(srcdir)/'`lib/fy-utils.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo: lib/fy-event.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-event.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo `test -f 'lib/fy-event.c' || echo '$(srcdir)/'`lib/fy-event.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-event.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-event.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-event.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-event.lo: lib/fy-event.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-event.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-event.Tpo -c -o lib/libfyaml_la-fy-event.lo `test -f 'lib/fy-event.c' || echo '$(srcdir)/'`lib/fy-event.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-event.Tpo lib/$(DEPDIR)/libfyaml_la-fy-event.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-event.c' object='lib/libfyaml_la-fy-event.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-event.lo `test -f 'lib/fy-event.c' || echo '$(srcdir)/'`lib/fy-event.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-event.lo `test -f 'lib/fy-event.c' || echo '$(srcdir)/'`lib/fy-event.c
 
-xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo: xxhash/xxhash.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo -MD -MP -MF xxhash/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-xxhash.Tpo -c -o xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo `test -f 'xxhash/xxhash.c' || echo '$(srcdir)/'`xxhash/xxhash.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) xxhash/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-xxhash.Tpo xxhash/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-xxhash.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='xxhash/xxhash.c' object='xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo' libtool=yes @AMDEPBACKSLASH@
+xxhash/libfyaml_la-xxhash.lo: xxhash/xxhash.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT xxhash/libfyaml_la-xxhash.lo -MD -MP -MF xxhash/$(DEPDIR)/libfyaml_la-xxhash.Tpo -c -o xxhash/libfyaml_la-xxhash.lo `test -f 'xxhash/xxhash.c' || echo '$(srcdir)/'`xxhash/xxhash.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) xxhash/$(DEPDIR)/libfyaml_la-xxhash.Tpo xxhash/$(DEPDIR)/libfyaml_la-xxhash.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='xxhash/xxhash.c' object='xxhash/libfyaml_la-xxhash.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o xxhash/libfyaml_@MAJOR@_@MINOR@_la-xxhash.lo `test -f 'xxhash/xxhash.c' || echo '$(srcdir)/'`xxhash/xxhash.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o xxhash/libfyaml_la-xxhash.lo `test -f 'xxhash/xxhash.c' || echo '$(srcdir)/'`xxhash/xxhash.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo: lib/fy-accel.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo `test -f 'lib/fy-accel.c' || echo '$(srcdir)/'`lib/fy-accel.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-accel.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-accel.lo: lib/fy-accel.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-accel.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-accel.Tpo -c -o lib/libfyaml_la-fy-accel.lo `test -f 'lib/fy-accel.c' || echo '$(srcdir)/'`lib/fy-accel.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-accel.Tpo lib/$(DEPDIR)/libfyaml_la-fy-accel.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-accel.c' object='lib/libfyaml_la-fy-accel.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-accel.lo `test -f 'lib/fy-accel.c' || echo '$(srcdir)/'`lib/fy-accel.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-accel.lo `test -f 'lib/fy-accel.c' || echo '$(srcdir)/'`lib/fy-accel.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo: lib/fy-walk.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo `test -f 'lib/fy-walk.c' || echo '$(srcdir)/'`lib/fy-walk.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-walk.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-walk.lo: lib/fy-walk.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-walk.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-walk.Tpo -c -o lib/libfyaml_la-fy-walk.lo `test -f 'lib/fy-walk.c' || echo '$(srcdir)/'`lib/fy-walk.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-walk.Tpo lib/$(DEPDIR)/libfyaml_la-fy-walk.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-walk.c' object='lib/libfyaml_la-fy-walk.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-walk.lo `test -f 'lib/fy-walk.c' || echo '$(srcdir)/'`lib/fy-walk.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-walk.lo `test -f 'lib/fy-walk.c' || echo '$(srcdir)/'`lib/fy-walk.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo: lib/fy-path.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-path.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo `test -f 'lib/fy-path.c' || echo '$(srcdir)/'`lib/fy-path.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-path.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-path.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-path.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-path.lo: lib/fy-path.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-path.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-path.Tpo -c -o lib/libfyaml_la-fy-path.lo `test -f 'lib/fy-path.c' || echo '$(srcdir)/'`lib/fy-path.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-path.Tpo lib/$(DEPDIR)/libfyaml_la-fy-path.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-path.c' object='lib/libfyaml_la-fy-path.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-path.lo `test -f 'lib/fy-path.c' || echo '$(srcdir)/'`lib/fy-path.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-path.lo `test -f 'lib/fy-path.c' || echo '$(srcdir)/'`lib/fy-path.c
 
-lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo: lib/fy-composer.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.Tpo -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo `test -f 'lib/fy-composer.c' || echo '$(srcdir)/'`lib/fy-composer.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.Tpo lib/$(DEPDIR)/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-composer.c' object='lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo' libtool=yes @AMDEPBACKSLASH@
+lib/libfyaml_la-fy-composer.lo: lib/fy-composer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -MT lib/libfyaml_la-fy-composer.lo -MD -MP -MF lib/$(DEPDIR)/libfyaml_la-fy-composer.Tpo -c -o lib/libfyaml_la-fy-composer.lo `test -f 'lib/fy-composer.c' || echo '$(srcdir)/'`lib/fy-composer.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) lib/$(DEPDIR)/libfyaml_la-fy-composer.Tpo lib/$(DEPDIR)/libfyaml_la-fy-composer.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='lib/fy-composer.c' object='lib/libfyaml_la-fy-composer.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_@MAJOR@_@MINOR@_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_@MAJOR@_@MINOR@_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_@MAJOR@_@MINOR@_la-fy-composer.lo `test -f 'lib/fy-composer.c' || echo '$(srcdir)/'`lib/fy-composer.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfyaml_la_CPPFLAGS) $(CPPFLAGS) $(libfyaml_la_CFLAGS) $(CFLAGS) -c -o lib/libfyaml_la-fy-composer.lo `test -f 'lib/fy-composer.c' || echo '$(srcdir)/'`lib/fy-composer.c
 
 tool/fy_tool-fy-tool.o: tool/fy-tool.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fy_tool_CPPFLAGS) $(CPPFLAGS) $(fy_tool_CFLAGS) $(CFLAGS) -MT tool/fy_tool-fy-tool.o -MD -MP -MF tool/$(DEPDIR)/fy_tool-fy-tool.Tpo -c -o tool/fy_tool-fy-tool.o `test -f 'tool/fy-tool.c' || echo '$(srcdir)/'`tool/fy-tool.c
index 3f8a5c3ca93bbda45906e6399d7dae11194676cd..a59c071dc153d9f892ade31f0d7c8165e07a8c82 100644 (file)
@@ -695,6 +695,7 @@ int do_dump2(struct fy_parser *fyp, int indent, int width, bool resolve, bool so
 {
        struct fy_document *fyd;
        struct fy_document_builder *fydb;
+       struct fy_document_builder_cfg cfg;
        unsigned int flags;
        int rc, count;
 
@@ -703,7 +704,11 @@ int do_dump2(struct fy_parser *fyp, int indent, int width, bool resolve, bool so
                flags |= FYECF_SORT_KEYS;
        flags |= FYECF_INDENT(indent) | FYECF_WIDTH(width);
 
-       fydb = fy_document_builder_create(&fyp->cfg);
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.parse_cfg = fyp->cfg;
+       cfg.diag = fy_diag_ref(fyp->diag);
+
+       fydb = fy_document_builder_create(&cfg);
        assert(fydb);
 
        count = 0;
@@ -756,7 +761,7 @@ process_event(struct fy_parser *fyp, struct fy_event *fye, struct fy_path *path,
                        fy_path_in_mapping(path) ? 'M' : '-',
                        fy_path_in_mapping_key(path) ? 'K' :
                                fy_path_in_mapping_value(path) ? 'V' : '-',
-                       fy_path_is_collection_root(path) ? '/' : '-',
+                       fy_path_in_collection_root(path) ? '/' : '-',
                        fy_path_depth(path),
                        fy_path_get_text_alloca(path),
                        fy_token_dump_format(fy_event_get_token(fye), tbuf, sizeof(tbuf)));
@@ -925,14 +930,8 @@ err_out:
 int do_compose(struct fy_parser *fyp, int indent, int width, bool resolve, bool sort, bool null_output)
 {
        struct composer_data cd;
-       unsigned int flags;
        int rc;
 
-       flags = 0;
-       if (sort)
-               flags |= FYECF_SORT_KEYS;
-       flags |= FYECF_INDENT(indent) | FYECF_WIDTH(width);
-
        memset(&cd, 0, sizeof(cd));
        cd.null_output = null_output;
        cd.single_document = true;
@@ -964,30 +963,27 @@ fy_node_belongs_to_key(struct fy_document *fyd, struct fy_node *fyn)
 
 int do_iterate(struct fy_parser *fyp)
 {
-       enum fy_node_iterator_flags flags;
        struct fy_document *fyd;
+       struct fy_document_iterator *fydi;
        int count;
        struct fy_node *fyn;
-       struct fy_node_iterator ni;
-       enum fy_node_iterator_result res;
        char *path;
        size_t len;
        const char *text;
        char textbuf[16];
        bool belongs_to_key;
 
-       memset(&ni, 0, sizeof(ni));
-
-       flags = FYNIF_DEPTH_FIRST;
-       fy_node_iterator_setup(&ni, flags | FYNIF_FOLLOW_KEYS | FYNIF_FOLLOW_LINKS);
+       fydi = fy_document_iterator_create();
+       assert(fydi);
 
        count = 0;
        while ((fyd = fy_parse_load_document(fyp)) != NULL) {
 
                fprintf(stderr, "> Start\n");
-               fy_node_iterator_start(&ni, fy_document_root(fyd));
+               fy_document_iterator_node_start(fydi, fy_document_root(fyd));
+
                fyn = NULL;
-               while ((fyn = fy_node_iterator_next(&ni, fyn)) != NULL) {
+               while ((fyn = fy_document_iterator_node_next(fydi)) != NULL) {
 
                        belongs_to_key = fy_node_belongs_to_key(fyd, fyn);
                        path = fy_node_get_path(fyn);
@@ -1008,33 +1004,24 @@ int do_iterate(struct fy_parser *fyp)
                        free(path);
                }
 
-               res = fy_node_iterator_end(&ni);
-
                fprintf(stderr, "> End\n");
 
                fy_parse_document_destroy(fyp, fyd);
 
-               if (res != FYNIR_OK) {
-                       fprintf(stderr, "> Iterator error %d\n", (int)res);
-                       break;
-               }
-
                count++;
        }
 
-       fy_node_iterator_cleanup(&ni);
+       fy_document_iterator_destroy(fydi);
 
        return count > 0 ? 0 : -1;
 }
 
 int do_comment(struct fy_parser *fyp)
 {
-       enum fy_node_iterator_flags flags;
        struct fy_document *fyd;
        int count;
        struct fy_node *fyn;
-       struct fy_node_iterator ni;
-       enum fy_node_iterator_result res;
+       struct fy_document_iterator *fydi;
        char *path;
        struct fy_token *fyt;
        struct fy_atom *handle;
@@ -1042,17 +1029,15 @@ int do_comment(struct fy_parser *fyp)
        static const char *placement_txt[] =  { "top", "right", "bottom" };
        char buf[1024];
 
-       memset(&ni, 0, sizeof(ni));
-
-       flags = FYNIF_DEPTH_FIRST;
-       fy_node_iterator_setup(&ni, flags | FYNIF_FOLLOW_KEYS | FYNIF_FOLLOW_LINKS);
+       fydi = fy_document_iterator_create();
+       assert(fydi);
 
        count = 0;
        while ((fyd = fy_parse_load_document(fyp)) != NULL) {
 
-               fy_node_iterator_start(&ni, fy_document_root(fyd));
+               fy_document_iterator_node_start(fydi, fy_document_root(fyd));
                fyn = NULL;
-               while ((fyn = fy_node_iterator_next(&ni, fyn)) != NULL) {
+               while ((fyn = fy_document_iterator_node_next(fydi)) != NULL) {
 
                        if (!fy_node_is_scalar(fyn))
                                continue;
@@ -1078,18 +1063,12 @@ int do_comment(struct fy_parser *fyp)
                        free(path);
                }
 
-               res = fy_node_iterator_end(&ni);
-
                fy_parse_document_destroy(fyp, fyd);
 
-               if (res != FYNIR_OK) {
-                       break;
-               }
-
                count++;
        }
 
-       fy_node_iterator_cleanup(&ni);
+       fy_document_iterator_destroy(fydi);
 
        return count > 0 ? 0 : -1;
 }
@@ -1643,6 +1622,19 @@ static void do_accel_kv(const struct fy_parse_cfg *cfg, int argc, char *argv[])
        char keybuf[16], valbuf[16];
        const char *key;
 
+       /* supress warnings about unused functions */
+       (void)fy_kv_list_push;
+       (void)fy_kv_list_push_tail;
+       (void)fy_kv_list_is_singular;
+       (void)fy_kv_list_insert_after;
+       (void)fy_kv_list_insert_before;
+       (void)fy_kv_list_last;
+       (void)fy_kv_list_pop_tail;
+       (void)fy_kv_prev;
+       (void)fy_kv_lists_splice;
+       (void)fy_kv_list_splice_after;
+       (void)fy_kv_list_splice_before;
+
        seed = 0;       /* we don't care much about seed practices right now */
        rc = fy_kv_store_setup(&kvs, 8);
        assert(!rc);
@@ -3500,14 +3492,14 @@ int do_bypath(struct fy_parser *fyp, const char *pathstr, const char *start)
                if (!fyn) {
                        fprintf(stderr, "exec: did not find node for %s\n", pathstr);
                } else {
-                       fprintf(stderr, "exec: path %s - return %s\n", pathstr, fy_node_get_path_a(fyn));
+                       fprintf(stderr, "exec: path %s - return %s\n", pathstr, fy_node_get_path_alloca(fyn));
                }
 
                fyn = node_find(fyd, fy_document_root(fyd), &path);
                if (!fyn) {
                        fprintf(stderr, "norm: did not find node for %s\n", pathstr);
                } else {
-                       fprintf(stderr, "norm: path %s - return %s\n", pathstr, fy_node_get_path_a(fyn));
+                       fprintf(stderr, "norm: path %s - return %s\n", pathstr, fy_node_get_path_alloca(fyn));
                }
 
                fy_parse_document_destroy(fyp, fyd);
@@ -4087,7 +4079,7 @@ int main(int argc, char *argv[])
                                fyic->type = fyit_stream;
                                fyic->stream.name = "stdin";
                                fyic->stream.fp = stdin;
-                               fyic->stream.chunk = chunk;
+                               fyic->chunk = chunk;
                        } else {
                                fyic->type = fyit_callback;
                                fyic->userdata = stdin;
@@ -4113,7 +4105,7 @@ int main(int argc, char *argv[])
                        fyic->type = fyit_stream;
                        fyic->stream.name = "stdin";
                        fyic->stream.fp = stdin;
-                       fyic->stream.chunk = chunk;
+                       fyic->chunk = chunk;
                } else {
                        fyic->type = fyit_callback;
                        fyic->userdata = stdin;
index 9ce4a0d01ec4980d39a348a44f2b1993f7087cf7..d6e608655ba2c208c528dcf85c39e7f72c287ada 100644 (file)
 #include "fy-parse.h"
 #include "fy-doc.h"
 
-void fy_reader_fill_atom_start(struct fy_reader *fyr, struct fy_atom *handle)
-{
-       memset(handle, 0, sizeof(*handle));
-
-       /* start mark */
-       fy_reader_get_mark(fyr, &handle->start_mark);
-       handle->end_mark = handle->start_mark;
-       handle->fyi = fy_reader_current_input(fyr);
-       handle->fyi_generation = fy_reader_current_input_generation(fyr);
-
-       /* note that handle->data may be zero for empty input */
-}
-
-void fy_reader_fill_atom_end_at(struct fy_reader *fyr, struct fy_atom *handle,
-                               struct fy_mark *end_mark)
-{
-       if (end_mark)
-               handle->end_mark = *end_mark;
-       else
-               fy_reader_get_mark(fyr, &handle->end_mark);
-
-       /* default is plain, modify at return */
-       handle->style = FYAS_PLAIN;
-       handle->chomp = FYAC_CLIP;
-       /* by default we don't do storage hints, it's the job of the caller */
-       handle->storage_hint = 0;
-       handle->storage_hint_valid = false;
-       handle->tabsize = fy_reader_tabsize(fyr);
-       handle->json_mode = fy_reader_json_mode(fyr);
-       handle->lb_mode = fy_reader_lb_mode(fyr);
-       handle->fws_mode = fy_reader_flow_ws_mode(fyr);
-}
-
-void fy_reader_fill_atom_end(struct fy_reader *fyr, struct fy_atom *handle)
-{
-       fy_reader_fill_atom_end_at(fyr, handle, NULL);
-}
-
 struct fy_atom *fy_reader_fill_atom(struct fy_reader *fyr, int advance, struct fy_atom *handle)
 {
        /* start mark */
@@ -362,6 +324,7 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
        const char *s, *e, *ss;
        int col, c, w, ts, cws, advws;
        bool last_was_ws, is_block;
+       int lastc;
 
        s = line_start;
        e = line_start + len;
@@ -415,9 +378,12 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
        /* consecutive whitespace */
        cws = 0;
 
+       lastc = -1;
        li->s_tb = s;
        for (col = 0, ss = s; (c = fy_utf8_get(ss, (e - ss), &w)) >= 0; ss += w) {
 
+               lastc = c;
+
                /* mark start of chomp */
                if (is_block && !li->chomp_start && (unsigned int)col >= iter->chomp) {
                        li->chomp_start = ss;
@@ -426,6 +392,11 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
                         * then we're indented
                         */
                        li->indented = fy_is_ws(c);
+
+#if defined(DEBUG_CHUNK)
+                       fprintf(stderr, "%s:%d chomp_start=%d\n", __FILE__, __LINE__, (int)(li->chomp_start - li->start));
+#endif
+
                }
 
                if (fy_is_lb_m(c, atom->lb_mode)) {
@@ -450,8 +421,13 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
                        }
 
                        /* no chomp point hit, use whatever we have here */
-                       if (is_block && !li->chomp_start)
+                       if (is_block && !li->chomp_start) {
                                li->chomp_start = ss;
+#if defined(DEBUG_CHUNK)
+                               fprintf(stderr, "%s:%d chomp_start=%d\n", __FILE__, __LINE__, (int)(li->chomp_start - li->start));
+#endif
+
+                       }
 
                        if (!last_was_ws) {
                                cws = 0;
@@ -459,18 +435,53 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
                                last_was_ws = true;
                        }
 
-               } else if (fy_is_ws(c)) {
+               } else if (fy_is_space(c)) {
 
-                       advws = fy_is_space(c) ? 1 : (ts - (col % ts));
+                       col++;
+                       cws++;
+
+                       if (!last_was_ws) {
+                               li->nws_end = ss;
+                               last_was_ws = true;
+                       }
+
+               } else if (fy_is_tab(c)) {
+
+                       bool can_be_nws_end;
+
+                       advws = ts - (col % ts);
                        col += advws;
+
+#if defined(DEBUG_CHUNK)
+                       fprintf(stderr, "%s:%d tab col=%d chomp=%d\n", __FILE__, __LINE__, col, (int)(li->chomp_start - li->start));
+#endif
+
+                       if (fy_atom_style_is_block(atom->style) && col >= (int)(li->chomp_start - li->start)) {
+#if defined(DEBUG_CHUNK)
+                               fprintf(stderr, "%s:%d tab col=%d chomp=%d\n", __FILE__, __LINE__, col, (int)(li->chomp_start - li->start));
+#endif
+                               goto do_nws;
+                       }
+
                        cws += advws;
 
-                       if (!last_was_ws) {
+                       can_be_nws_end = true;
+                       if (atom->style == FYAS_DOUBLE_QUOTED && ss > li->start && ss[-1] == '\\') {
+                               can_be_nws_end = false;
+#ifdef DEBUG_CHUNK
+                               fprintf(stderr, "%s:%d backslashed tab\n", __FILE__, __LINE__);
+#endif
+                       }
+
+                       if (can_be_nws_end && !last_was_ws) {
                                li->nws_end = ss;
                                last_was_ws = true;
                        }
 
                } else {
+
+                       col++;
+do_nws:
                        /* mark start of non whitespace */
                        if (!li->nws_start)
                                li->nws_start = ss;
@@ -483,8 +494,6 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
 
                        last_was_ws = false;
                        cws = 0;
-
-                       col++;
                }
 
                /* if we got both break */
@@ -493,7 +502,58 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
        }
        li->e_tb = ss;
 
-       li->final = c == -1;
+       li->final = c < 0;
+
+       if (li->final && atom->ends_with_eof) {
+
+               /* mark start of chomp */
+               if (is_block && !li->chomp_start && (unsigned int)col >= iter->chomp) {
+                       li->chomp_start = ss;
+
+                       /* if the character at the chomp point is whitespace
+                        * then we're indented
+                        */
+                       li->indented = fy_is_ws(lastc);
+#ifdef DEBUG_CHUNK
+                       fprintf(stderr, "%s:%d is_block && !li->chomp_start && (unsigned int)col >= iter->chomp\n", __FILE__, __LINE__);
+#endif
+#if defined(DEBUG_CHUNK)
+                       fprintf(stderr, "%s:%d chomp_start=%d\n", __FILE__, __LINE__, (int)(li->chomp_start - li->start));
+#endif
+
+               }
+
+               if (!li->end) {
+                       li->end = ss;
+                       li->end_ws = cws;
+                       li->lb_end = true;
+
+#ifdef DEBUG_CHUNK
+                       fprintf(stderr, "%s:%d li->final && atom->ends_with_eof && !li->end\n", __FILE__, __LINE__);
+#endif
+                       cws = 0;
+               }
+
+               /* no chomp point hit, use whatever we have here */
+               if (is_block && !li->chomp_start) {
+                       li->chomp_start = ss;
+#ifdef DEBUG_CHUNK
+                       fprintf(stderr, "%s:%d li->final && atom->ends_with_eof && !li->chomp_start\n", __FILE__, __LINE__);
+#endif
+#if defined(DEBUG_CHUNK)
+                       fprintf(stderr, "%s:%d chomp_start=%d\n", __FILE__, __LINE__, (int)(li->chomp_start - li->start));
+#endif
+               }
+
+               if (!last_was_ws) {
+                       cws = 0;
+                       li->nws_end = ss;
+                       last_was_ws = true;
+#ifdef DEBUG_CHUNK
+                       fprintf(stderr, "%s:%d li->final && atom->ends_with_eof && !last_was_ws\n", __FILE__, __LINE__);
+#endif
+               }
+       }
 
        if (!last_was_ws)
                li->nws_end = ss;
@@ -505,8 +565,12 @@ fy_atom_iter_line_analyze(struct fy_atom_iter *iter, struct fy_atom_iter_line_in
                li->nws_end = ss;
 
        /* if we haven't hit the chomp, point use whatever we're now */
-       if (is_block && !li->chomp_start)
+       if (is_block && !li->chomp_start) {
                li->chomp_start = ss;
+#if defined(DEBUG_CHUNK)
+               fprintf(stderr, "%s:%d chomp_start=%d\n", __FILE__, __LINE__, (int)(li->chomp_start - li->start));
+#endif
+       }
 
        if (li->start_ws == (size_t)-1)
                li->start_ws = 0;
@@ -592,7 +656,10 @@ void fy_atom_iter_start(const struct fy_atom *atom, struct fy_atom_iter *iter)
        iter->empty = atom->empty;
        iter->last_ends_with_backslash = li->ends_with_backslash;
 #ifdef DEBUG_CHUNK
-       fprintf(stderr, "%s:%d ends_with_backslash=%s\n", __FILE__, __LINE__, li->ends_with_backslash ? "true" : "false");
+       fprintf(stderr, "%s:%d single_line=%s empty=%s last_ends_with_backslash=%s\n", __FILE__, __LINE__,
+                       iter->single_line ? "true" : "false",
+                       iter->empty ? "true" : "false",
+                       iter->last_ends_with_backslash ? "true" : "false");
 #endif
 
        /* current is 0, next is 1 */
@@ -665,7 +732,7 @@ fy_atom_iter_line(struct fy_atom_iter *iter)
        } else if (atom->style == FYAS_LITERAL || atom->style == FYAS_FOLDED) {
                li->s = li->chomp_start;
                li->e = li->end;
-               if (li->empty && li->first && li->last && !iter->single_line)
+               if (li->empty && li->first && li->last)
                        li->s = li->e;
        } else {
                li->s = li->nws_start;
@@ -930,18 +997,24 @@ fy_atom_iter_format(struct fy_atom_iter *iter)
                                                pending_nl++;
                                        }
                                }
-                               if (atom->chomp == FYAC_CLIP && pending_nl) {
+
+                               if (atom->chomp == FYAC_CLIP && (pending_nl || atom->ends_with_eof)) {
                                        ret = fy_atom_iter_add_lb(iter, pending_lb[0]);
                                        if (ret)
                                                goto out;
                                }
                                break;
                        case FYAC_KEEP:
-                               if (li->lb_end) {
+                               if (li->lb_end || atom->ends_with_eof) {
                                        ret = fy_atom_iter_add_lb(iter, li->actual_lb > 0 ? li->actual_lb : '\n');
                                        if (ret)
                                                goto out;
                                }
+
+                               /* nothing more if it's an EOF */
+                               if (atom->ends_with_eof && atom->empty)
+                                       break;
+
                                while ((li = fy_atom_iter_line(iter)) != NULL) {
                                        if (!iter->empty && li->chomp_start < li->end) {
                                                ret = fy_atom_iter_add_chunk(iter, li->chomp_start, li->end - li->chomp_start);
index 188f2005922e1fa586ca9680ecda2aaec35c2b4a..9041f21e9bab9e06b5304bc8004d5fcc8f935c7d 100644 (file)
@@ -62,25 +62,31 @@ struct fy_atom {
        struct fy_input *fyi;   /* input on which atom is on */
        uint64_t fyi_generation;        /* to detect reallocs */
        unsigned int increment;
-       /* save a little bit of space with bitfields */
-       enum fy_atom_style style;
-       enum fy_lb_mode lb_mode;        /* atom linebreak mode */
-       enum fy_flow_ws_mode fws_mode;  /* atom flow whitespace mode */
-       enum fy_atom_chomp chomp : 4;
-       bool direct_output : 1;         /* can directly output */
-       bool storage_hint_valid : 1;
-       bool empty : 1;                 /* atom contains whitespace and linebreaks only if length > 0 */
-       bool has_lb : 1;                /* atom contains at least one linebreak */
-       bool has_ws : 1;                /* atom contains at least one whitespace */
-       bool starts_with_ws : 1;        /* atom starts with whitespace */
-       bool starts_with_lb : 1;        /* atom starts with linebreak */
-       bool ends_with_ws : 1;          /* atom ends with whitespace */
-       bool ends_with_lb : 1;          /* atom ends with linebreak */
-       bool trailing_lb : 1;           /* atom ends with trailing linebreaks > 1 */
-       bool size0 : 1;                 /* atom contains absolutely nothing */
-       bool valid_anchor : 1;          /* atom is a valid anchor */
-       bool json_mode : 1;             /* atom was read in json mode */
-       unsigned int tabsize : 4;
+       union {
+               uint64_t tozero;                        /* fast way to zero everything here */
+               struct {
+                       /* save a little bit of space with bitfields */
+                       enum fy_atom_style style : 8;   /* note that it's a big perf win for bytes */
+                       enum fy_atom_chomp chomp : 8;
+                       unsigned int tabsize : 8;
+                       enum fy_lb_mode lb_mode : 1;
+                       enum fy_flow_ws_mode fws_mode : 1;
+                       bool direct_output : 1;         /* can directly output */
+                       bool storage_hint_valid : 1;
+                       bool empty : 1;                 /* atom contains whitespace and linebreaks only if length > 0 */
+                       bool has_lb : 1;                /* atom contains at least one linebreak */
+                       bool has_ws : 1;                /* atom contains at least one whitespace */
+                       bool starts_with_ws : 1;        /* atom starts with whitespace */
+                       bool starts_with_lb : 1;        /* atom starts with linebreak */
+                       bool ends_with_ws : 1;          /* atom ends with whitespace */
+                       bool ends_with_lb : 1;          /* atom ends with linebreak */
+                       bool trailing_lb : 1;           /* atom ends with trailing linebreaks > 1 */
+                       bool size0 : 1;                 /* atom contains absolutely nothing */
+                       bool valid_anchor : 1;          /* atom is a valid anchor */
+                       bool json_mode : 1;             /* atom was read in json mode */
+                       bool ends_with_eof : 1;         /* atom ends at EOF of input */
+               };
+       };
 };
 
 static inline bool fy_atom_is_set(const struct fy_atom *atom)
@@ -134,11 +140,47 @@ 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);
 
-void fy_reader_fill_atom_start(struct fy_reader *fyr, struct fy_atom *handle);
-void fy_reader_fill_atom_end_at(struct fy_reader *fyr, struct fy_atom *handle, struct fy_mark *end_mark);
-void fy_reader_fill_atom_end(struct fy_reader *fyr, struct fy_atom *handle);
-struct fy_atom *fy_reader_fill_atom(struct fy_reader *fyr, int advance, struct fy_atom *handle);
+static inline void
+fy_reader_fill_atom_start(struct fy_reader *fyr, struct fy_atom *handle)
+{
+       /* start mark */
+       fy_reader_get_mark(fyr, &handle->start_mark);
+       handle->fyi = fy_reader_current_input(fyr);
+       handle->fyi_generation = fy_reader_current_input_generation(fyr);
+
+       handle->increment = 0;
+       handle->tozero = 0;
+
+       /* note that handle->data may be zero for empty input */
+}
+
+static inline void
+fy_reader_fill_atom_end_at(struct fy_reader *fyr, struct fy_atom *handle, struct fy_mark *end_mark)
+{
+       if (end_mark)
+               handle->end_mark = *end_mark;
+       else
+               fy_reader_get_mark(fyr, &handle->end_mark);
+
+       /* default is plain, modify at return */
+       handle->style = FYAS_PLAIN;
+       handle->chomp = FYAC_CLIP;
+       /* by default we don't do storage hints, it's the job of the caller */
+       handle->storage_hint = 0;
+       handle->storage_hint_valid = false;
+       handle->tabsize = fy_reader_tabsize(fyr);
+       handle->json_mode = fy_reader_json_mode(fyr);
+       handle->lb_mode = fy_reader_lb_mode(fyr);
+       handle->fws_mode = fy_reader_flow_ws_mode(fyr);
+}
+
+static inline void
+fy_reader_fill_atom_end(struct fy_reader *fyr, struct fy_atom *handle)
+{
+       fy_reader_fill_atom_end_at(fyr, handle, NULL);
+}
 
+struct fy_atom *fy_reader_fill_atom(struct fy_reader *fyr, int advance, struct fy_atom *handle);
 struct fy_atom *fy_reader_fill_atom_mark(struct fy_reader *fyr, const struct fy_mark *start_mark,
                                         const struct fy_mark *end_mark, struct fy_atom *handle);
 struct fy_atom *fy_reader_fill_atom_at(struct fy_reader *fyr, int advance, int count, struct fy_atom *handle);
index f44db634ce38a947d0c0f8b3330997b1b1605280..3e19017958958b1a94907c21566b682815c45a35 100644 (file)
 
 #include "fy-utils.h"
 
-#undef DBG
-// #define DBG fyp_notice
-#define DBG fyp_scan_debug
-
 struct fy_composer *
 fy_composer_create(struct fy_composer_cfg *cfg)
 {
@@ -55,7 +51,6 @@ fy_composer_create(struct fy_composer_cfg *cfg)
 err_no_path:
        free(fyc);
        return NULL;
-
 }
 
 void fy_composer_destroy(struct fy_composer *fyc)
@@ -72,8 +67,7 @@ void fy_composer_destroy(struct fy_composer *fyc)
 }
 
 static enum fy_composer_return
-fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp,
-                                 struct fy_event *fye, struct fy_path *fypp)
+fy_composer_process_event_private(struct fy_composer *fyc, struct fy_event *fye, struct fy_path *fypp)
 {
        const struct fy_composer_ops *ops;
        struct fy_eventp *fyep;
@@ -81,13 +75,11 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
        struct fy_path *fyppt;
        struct fy_document *fyd;
        bool is_collection, is_map, is_start, is_end;
-       char tbuf[80] __attribute__((__unused__));
        int rc = 0;
        enum fy_composer_return ret;
        bool stop_req = false;
 
        assert(fyc);
-       assert(fyp);
        assert(fye);
        assert(fypp);
 
@@ -145,24 +137,16 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
        case FYET_STREAM_END:
        case FYET_DOCUMENT_START:
        case FYET_DOCUMENT_END:
-               // fprintf(stderr, "%s:%d process_event\n", __FILE__, __LINE__);
-               return ops->process_event(fyc, fypp, fyp, fye);
+               return ops->process_event(fyc, fypp, fye);
 
        default:
-               // DBG(fyp, "ignoring\n");
                return FYCR_OK_CONTINUE;
        }
 
        fypc_last = fy_path_component_list_tail(&fypp->components);
 
-       // DBG(fyp, "%s: start - %s\n", fy_path_get_text0(fypp), fy_token_dump_format(fyt, tbuf, sizeof(tbuf)));
-
        if (fy_path_component_is_mapping(fypc_last) && fypc_last->map.accumulating_complex_key) {
 
-               // DBG(fyp, "accumulating for complex key\n");
-               // fprintf(stderr, "accumulating for complex key %s\n",
-               //              fy_token_dump_format(fy_event_get_token(fye), tbuf, sizeof(tbuf)));
-
                /* get the next one */
                fyppt = fy_path_next(&fyc->paths, fypp);
                assert(fyppt);
@@ -170,7 +154,7 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
                assert(fyppt->parent == fypp);
 
                /* and pass along */
-               ret = fy_composer_process_event_private(fyc, fyp, fye, fyppt);
+               ret = fy_composer_process_event_private(fyc, fye, fyppt);
                if (!fy_composer_return_is_ok(ret)) {
                        /* XXX TODO handle skip */
                        return ret;
@@ -178,21 +162,12 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
                if (!stop_req)
                        stop_req = ret == FYCR_OK_STOP;
 
-               rc = fy_document_builder_process_event(fypp->fydb, fyp, fyep);
-               if (rc == 0) {
-                       // DBG(fyp, "accumulating still\n");
-                       // fprintf(stderr, "accumulating still %s\n",
-                       //              fy_token_dump_format(fy_event_get_token(fye), tbuf, sizeof(tbuf)));
+               rc = fy_document_builder_process_event(fypp->fydb, fyep);
+               if (rc == 0)
                        return FYCR_OK_CONTINUE;
-               }
                fyc_error_check(fyc, rc > 0, err_out,
                                "fy_document_builder_process_event() failed\n");
 
-               // fprintf(stderr, "accumulating complete %s\n",
-               //              fy_token_dump_format(fy_event_get_token(fye), tbuf, sizeof(tbuf)));
-
-               // DBG(fyp, "accumulation complete\n");
-
                /* get the document */
                fyd = fy_document_builder_take_document(fypp->fydb);
                fyc_error_check(fyc, fyd, err_out,
@@ -204,14 +179,13 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
                fypc_last->map.has_key = true;
                fypc_last->map.await_key = false;
                fypc_last->map.complex_key_complete = true;
+               fypc_last->map.root = false;
 
                fyppt = fy_path_list_pop_tail(&fyc->paths);
                assert(fyppt);
 
                fy_path_destroy(fyppt);
 
-               // DBG(fyp, "%s: %s complex KEY\n", __func__, fy_path_get_text0(fypp));
-
                fyc_error_check(fyc, rc >= 0, err_out,
                                "fy_path_component_build_text() failed\n");
 
@@ -221,24 +195,18 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
        /* start of something on a mapping */
        if (is_start && fy_path_component_is_mapping(fypc_last) && fypc_last->map.await_key && is_collection) {
 
-               /* non scalar key case */
-               // DBG(fyp, "Non scalar key - using document builder\n");
-               if (!fypp->fydb) {
-                       fypp->fydb = fy_document_builder_create(&fyp->cfg);
-                       fyc_error_check(fyc, fypp->fydb, err_out,
-                                       "fy_document_builder_create() failed\n");
-               }
-
-               /* start with this document state */
-               rc = fy_document_builder_set_in_document(fypp->fydb, fy_parser_get_document_state(fyp), true);
-               fyc_error_check(fyc, !rc, err_out,
-                               "fy_document_builder_set_in_document() failed\n");
+               /* the configuration must support a document builder for complex keys */
+               FYC_TOKEN_ERROR_CHECK(fyc, fy_event_get_token(fye), FYEM_DOC,
+                               ops->create_document_builder, err_out,
+                               "composer configuration does not support complex keys");
 
-               // fprintf(stderr, "initial complex key %s\n",
-               //              fy_token_dump_format(fy_event_get_token(fye), tbuf, sizeof(tbuf)));
+               /* call out for creating the document builder */
+               fypp->fydb = ops->create_document_builder(fyc);
+               fyc_error_check(fyc, fypp->fydb, err_out,
+                               "ops->create_document_builder() failed\n");
 
                /* and pass the current event; must return 0 since we know it's a collection start */
-               rc = fy_document_builder_process_event(fypp->fydb, fyp, fyep);
+               rc = fy_document_builder_process_event(fypp->fydb, fyep);
                fyc_error_check(fyc, !rc, err_out,
                                "fy_document_builder_process_event() failed\n");
 
@@ -257,7 +225,7 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
                fy_path_list_add_tail(&fyc->paths, fyppt);
 
                /* and pass along */
-               ret = fy_composer_process_event_private(fyc, fyp, fye, fyppt);
+               ret = fy_composer_process_event_private(fyc, fye, fyppt);
                if (!fy_composer_return_is_ok(ret)) {
                        /* XXX TODO handle skip */
                        return ret;
@@ -300,15 +268,16 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
 
        } else if (!is_collection && fy_path_component_is_mapping(fypc_last) && fypc_last->map.await_key) {
 
-               // DBG(fyp, "scalar key: %s\n", fy_token_dump_format(fyt, tbuf, sizeof(tbuf)));
                fypc_last->map.is_complex_key = false;
-               fypc_last->map.scalar_key = fy_token_ref(fy_event_get_token(fye));
+               fypc_last->map.scalar.tag = fy_token_ref(fy_event_get_tag_token(fye));
+               fypc_last->map.scalar.key = fy_token_ref(fy_event_get_token(fye));
                fypc_last->map.has_key = true;
+               fypc_last->map.root = false;
 
        }
 
        /* process the event */
-       ret = ops->process_event(fyc, fypp, fyp, fye);
+       ret = ops->process_event(fyc, fypp, fye);
        if (!fy_composer_return_is_ok(ret)) {
                /* XXX TODO handle skip */
                return ret;
@@ -331,20 +300,13 @@ fy_composer_process_event_private(struct fy_composer *fyc, struct fy_parser *fyp
 
        /* at the end of something */
        if (is_end && fy_path_component_is_mapping(fypc_last)) {
-
                if (!fypc_last->map.await_key) {
-
                        fy_path_component_clear_state(fypc_last);
-
-                       // DBG(fyp, "%s: set await_key %p\n", fy_path_get_text0(fypp), fypc_last);
                        fypc_last->map.await_key = true;
-
-               } else {
+               } else
                        fypc_last->map.await_key = false;
-               }
        }
 
-       // DBG(fyp, "%s: exit\n", fy_path_get_text0(fypp));
        return !stop_req ? FYCR_OK_CONTINUE : FYCR_OK_STOP;
 
 err_out:
@@ -352,12 +314,12 @@ err_out:
 }
 
 enum fy_composer_return
-fy_composer_process_event(struct fy_composer *fyc, struct fy_parser *fyp, struct fy_event *fye)
+fy_composer_process_event(struct fy_composer *fyc, struct fy_event *fye)
 {
        struct fy_path *fypp;
        int rc;
 
-       if (!fyc || !fyp || !fye)
+       if (!fyc || !fye)
                return -1;
 
        /* start at the head */
@@ -367,7 +329,7 @@ fy_composer_process_event(struct fy_composer *fyc, struct fy_parser *fyp, struct
        if (!fypp)
                return -1;
 
-       rc = fy_composer_process_event_private(fyc, fyp, fye, fypp);
+       rc = fy_composer_process_event_private(fyc, fye, fypp);
 
        return rc;
 }
@@ -392,23 +354,3 @@ struct fy_diag *fy_composer_get_diag(struct fy_composer *fyc)
                return NULL;
        return fyc->cfg.diag;
 }
-
-enum fy_composer_return
-fy_composer_parse(struct fy_composer *fyc, struct fy_parser *fyp)
-{
-       struct fy_event *fye;
-       enum fy_composer_return ret;
-
-       if (!fyp || !fyc)
-               return FYCR_ERROR;
-
-       ret = FYCR_OK_CONTINUE;
-       while ((fye = fy_parser_parse(fyp)) != NULL) {
-               ret = fy_composer_process_event(fyc, fyp, fye);
-               fy_parser_event_free(fyp, fye);
-               if (ret != FYCR_OK_CONTINUE)
-                       break;
-       }
-
-       return ret;
-}
index 4cfea8d167416483450b7de6d161a316e3274fdb..d690f22622f674d6bfa1e0781d050df1bd0d3dec 100644 (file)
 #include "fy-path.h"
 
 struct fy_composer;
-struct fy_parser;
 struct fy_token;
-struct fy_document_state;
 struct fy_diag;
 struct fy_event;
 struct fy_eventp;
+struct fy_document_builder;
 
 struct fy_composer_ops {
        /* single process event callback */
-       enum fy_composer_return (*process_event)(struct fy_composer *fyc, struct fy_path *path, struct fy_parser *fyp, struct fy_event *fye);
+       enum fy_composer_return (*process_event)(struct fy_composer *fyc, struct fy_path *path, struct fy_event *fye);
+       struct fy_document_builder *(*create_document_builder)(struct fy_composer *fyc);
 };
 
 struct fy_composer_cfg {
@@ -48,12 +48,10 @@ struct fy_composer {
 
 struct fy_composer *fy_composer_create(struct fy_composer_cfg *cfg);
 void fy_composer_destroy(struct fy_composer *fyc);
-int fy_composer_process_event(struct fy_composer *fyc, struct fy_parser *fyp, struct fy_event *fye);
+int fy_composer_process_event(struct fy_composer *fyc, struct fy_event *fye);
 
 struct fy_composer_cfg *fy_composer_get_cfg(struct fy_composer *fyc);
 void *fy_composer_get_cfg_userdata(struct fy_composer *fyc);
 struct fy_diag *fy_composer_get_diag(struct fy_composer *fyc);
 
-int fy_composer_parse(struct fy_composer *fyc, struct fy_parser *fyp);
-
 #endif
index 4820226c86154790dcf3a4908d401039119dd021..a8fc935e792d4cac6a1a8472287eb6dabd43005e 100644 (file)
@@ -130,6 +130,12 @@ static const char *fy_error_module_str(enum fy_error_module module)
        return txt[module];
 }
 
+/* really concervative options */
+static const struct fy_diag_term_info default_diag_term_info_template = {
+       .rows           = 25,
+       .columns        = 80
+};
+
 static const struct fy_diag_cfg default_diag_cfg_template = {
        .fp             = NULL, /* must be overriden */
        .level          = FYET_INFO,
@@ -160,6 +166,45 @@ void fy_diag_cfg_from_parser_flags(struct fy_diag_cfg *cfg, enum fy_parse_cfg_fl
        /* nothing */
 }
 
+static bool fy_diag_isatty(struct fy_diag *diag)
+{
+       return diag && diag->cfg.fp && isatty(fileno(diag->cfg.fp));
+}
+
+static void fy_diag_update_term_info(struct fy_diag *diag)
+{
+       int fd, rows, columns, ret;
+
+       /* start by setting things to the default */
+       diag->term_info = default_diag_term_info_template;
+
+       fd = diag->cfg.fp && isatty(fileno(diag->cfg.fp)) ?
+               fileno(diag->cfg.fp) : -1;
+
+       if (fd == -1)
+               goto out;
+
+       rows = columns = 0;
+       ret = fy_term_query_size(fd, &rows, &columns);
+       if (ret != 0)
+               goto out;
+
+       if (rows > 0 && columns > 0) {
+               diag->term_info.rows = rows;
+               diag->term_info.columns = columns;
+       }
+out:
+       diag->terminal_probed = true;
+}
+
+void fy_diag_errorp_free(struct fy_diag_errorp *errp)
+{
+       if (errp->space)
+               free(errp->space);
+       fy_token_unref(errp->e.fyt);
+       free(errp);
+}
+
 struct fy_diag *fy_diag_create(const struct fy_diag_cfg *cfg)
 {
        struct fy_diag *diag;
@@ -176,16 +221,28 @@ struct fy_diag *fy_diag_create(const struct fy_diag_cfg *cfg)
        diag->on_error = false;
        diag->refs = 1;
 
+       diag->terminal_probed = false;
+       if (!fy_diag_isatty(diag))
+               fy_diag_update_term_info(diag);
+
+       fy_diag_errorp_list_init(&diag->errors);
+
        return diag;
 }
 
 void fy_diag_destroy(struct fy_diag *diag)
 {
+       struct fy_diag_errorp *errp;
+
        if (!diag)
                return;
 
        diag->destroyed = true;
 
+       /* free everything */
+       while ((errp = fy_diag_errorp_list_pop(&diag->errors)) != NULL)
+               fy_diag_errorp_free(errp);
+
        return fy_diag_unref(diag);
 }
 
@@ -196,24 +253,52 @@ bool fy_diag_got_error(struct fy_diag *diag)
 
 void fy_diag_reset_error(struct fy_diag *diag)
 {
+       struct fy_diag_errorp *errp;
+
        if (!diag)
                return;
 
        diag->on_error = false;
+
+       while ((errp = fy_diag_errorp_list_pop(&diag->errors)) != NULL)
+               fy_diag_errorp_free(errp);
 }
 
-/**
- * fy_diag_reset_error() - Reset the error flag of
- *                        the diagnostic object
- *
- * Clears the error flag which was set by an output
- * of an error level diagnostic
- *
- * @diag: The diagnostic object
- */
-void
-fy_diag_reset_error(struct fy_diag *diag)
-       FY_EXPORT;
+void fy_diag_set_collect_errors(struct fy_diag *diag, bool collect_errors)
+{
+       struct fy_diag_errorp *errp;
+
+       if (!diag || diag->destroyed)
+               return;
+
+       diag->collect_errors = collect_errors;
+
+       /* clear collected errors on disable */
+       if (!diag->collect_errors) {
+               while ((errp = fy_diag_errorp_list_pop(&diag->errors)) != NULL)
+                       fy_diag_errorp_free(errp);
+       }
+}
+
+struct fy_diag_error *fy_diag_errors_iterate(struct fy_diag *diag, void **prevp)
+{
+       struct fy_diag_errorp *errp;
+
+       if (!diag || !prevp)
+               return NULL;
+
+       if (!*prevp)
+               errp = fy_diag_errorp_list_head(&diag->errors);
+       else {
+               errp = *prevp;
+               errp = fy_diag_errorp_next(&diag->errors, errp);
+       }
+
+       if (!errp)
+               return NULL;
+       *prevp = errp;
+       return &errp->e;
+}
 
 void fy_diag_free(struct fy_diag *diag)
 {
@@ -234,12 +319,12 @@ void fy_diag_set_cfg(struct fy_diag *diag, const struct fy_diag_cfg *cfg)
        if (!diag)
                return;
 
-       if (!cfg) {
+       if (!cfg)
                fy_diag_cfg_default(&diag->cfg);
-               return;
-       }
+       else
+               diag->cfg = *cfg;
 
-       diag->cfg = *cfg;
+       fy_diag_update_term_info(diag);
 }
 
 void fy_diag_set_level(struct fy_diag *diag, enum fy_error_type level)
@@ -280,6 +365,28 @@ void fy_diag_unref(struct fy_diag *diag)
                diag->refs--;
 }
 
+ssize_t fy_diag_write(struct fy_diag *diag, const void *buf, size_t count)
+{
+       size_t ret;
+
+       if (!diag || !buf)
+               return -1;
+
+       /* no more output */
+       if (diag->destroyed)
+               return 0;
+
+       ret = 0;
+       if (diag->cfg.fp) {
+               ret = fwrite(buf, 1, count, diag->cfg.fp);
+       } else if (diag->cfg.output_fn) {
+               diag->cfg.output_fn(diag, diag->cfg.user, buf, count);
+               ret = count;
+       }
+
+       return ret == count ? (ssize_t)count : -1;
+}
+
 int fy_diag_vprintf(struct fy_diag *diag, const char *fmt, va_list ap)
 {
        char *buf;
@@ -334,9 +441,9 @@ int fy_vdiag(struct fy_diag *diag, const struct fy_diag_ctx *fydc,
 
        level = fydc->level;
 
-       /* turn errors into notices while not reset */
+       /* turn errors into debugs while not reset */
        if (level >= FYET_ERROR && diag->on_error)
-               level = FYET_NOTICE;
+               level = FYET_DEBUG;
 
        if (level < diag->cfg.level) {
                rc = 0;
@@ -436,6 +543,270 @@ int fy_diagf(struct fy_diag *diag, const struct fy_diag_ctx *fydc,
        return rc;
 }
 
+static void fy_diag_get_error_colors(struct fy_diag *diag, enum fy_error_type type,
+                                    const char **start, const char **end, const char **white)
+{
+       if (!diag->cfg.colorize) {
+               *start = *end = *white = "";
+               return;
+       }
+
+       switch (type) {
+       case FYET_DEBUG:
+               *start = "\x1b[37m";    /* normal white */
+               break;
+       case FYET_INFO:
+               *start = "\x1b[37;1m";  /* bright white */
+               break;
+       case FYET_NOTICE:
+               *start = "\x1b[34;1m";  /* bright blue */
+               break;
+       case FYET_WARNING:
+               *start = "\x1b[33;1m";  /* bright yellow */
+               break;
+       case FYET_ERROR:
+               *start = "\x1b[31;1m";  /* bright red */
+               break;
+       default:
+               *start = "\x1b[0m";     /* catch-all reset */
+               break;
+       }
+       *end = "\x1b[0m";
+       *white = "\x1b[37;1m";
+}
+
+void fy_diag_error_atom_display(struct fy_diag *diag, enum fy_error_type type, struct fy_atom *atom)
+{
+       const struct fy_raw_line *l, *ln;
+       struct fy_raw_line l_tmp;
+       struct fy_atom_raw_line_iter iter;
+       int content_start_col, content_end_col, content_width;
+       int pass, cols, min_col, max_col, total_lines, max_line_count, max_line_col8, max_width;
+       int start_col, end_col;
+       const char *color_start, *color_end, *white;
+       bool first_line, last_line;
+       const char *display;
+       int display_len, line_shift;
+       char qc, first_mark;
+       char *rowbuf = NULL, *rbs = NULL, *rbe = NULL;
+       const char *s, *e;
+       int col8, c, w;
+       int tab8_len, tilde_start, tilde_width, tilde_width_m1;
+       size_t rowbufsz;
+
+       (void)end_col;
+
+       if (!diag || !atom)
+               return;
+
+       fy_diag_get_error_colors(diag, type, &color_start, &color_end, &white);
+
+       /* two passes, first one collects extents */
+
+       start_col = -1;
+       end_col = -1;
+       min_col = -1;
+       max_col = -1;
+       max_line_count = -1;
+       max_line_col8 = -1;
+       total_lines = 0;
+       line_shift = -1;
+       for (pass = 0; pass < 2; pass++) {
+
+               /* on the start of the second pass */
+               if (pass > 0) {
+
+                       cols = 0;
+
+                       /* if it's probed, use what's there */
+                       if (diag->terminal_probed && diag->term_info.columns > 0)
+                               cols = diag->term_info.columns;
+
+                       /* heuristic, avoid probing terminal size if maximum column is less than 80
+                        * columns. This is faster and avoid problems with terminals...
+                        */
+                       if (!cols && max_line_col8 < 80)
+                               cols = 80;
+
+                       /* no choice but to probe */
+                       if (!cols) {
+                               /* only need the terminal width when outputting an error */
+                               if (!diag->terminal_probed && fy_diag_isatty(diag))
+                                       fy_diag_update_term_info(diag);
+
+                               cols = diag->term_info.columns;
+                       }
+
+                       /* worse case utf8 + 2 color sequences + zero terminated */
+                       rowbufsz = cols * 4 + 2 * 16 + 1;
+                       rowbuf = alloca(rowbufsz);
+                       rbe = rowbuf + rowbufsz;
+
+                       /* if the maximum column number is less than the terminal
+                        * width everything fits, and we're fine */ 
+                       if (max_line_col8 < cols) {
+                               line_shift = 0;
+                       } else {
+                               max_width = max_col - min_col;
+
+                               /* try to center */
+                               line_shift = min_col + (max_width - cols) / 2;
+
+                               /* the start of the content must always be included */
+                               if (start_col < line_shift)
+                                       line_shift = start_col;
+                       }
+               }
+
+               fy_atom_raw_line_iter_start(atom, &iter);
+               l = fy_atom_raw_line_iter_next(&iter);
+               for (; l != NULL; l = ln) {
+
+                       /* save it */
+                       l_tmp = *l;
+                       l = &l_tmp;
+
+                       /* get the next too */
+                       ln = fy_atom_raw_line_iter_next(&iter);
+
+                       first_line = l->lineno <= 1;
+                       last_line = ln == NULL;
+
+                       content_start_col = l->content_start_col8;
+                       content_end_col = l->content_end_col8;
+
+                       /* adjust for single and double quoted to include the quote marks (usually works) */
+                       if (fy_atom_style_is_quoted(atom->style)) {
+                               qc = atom->style == FYAS_SINGLE_QUOTED ? '\'' : '"';
+                               if (first_line && l->content_start > l->line_start &&
+                                               l->content_start[-1] == qc)
+                                       content_start_col--;
+                               if (last_line && (l->content_start + l->content_len) < (l->line_start + l->line_len) &&
+                                               l->content_start[l->content_len] == qc)
+                                       content_end_col++;
+                       }
+
+                       content_width = content_end_col - content_start_col;
+
+                       if (pass == 0) {
+
+                               total_lines++;
+
+                               if (min_col < 0 || content_start_col < min_col)
+                                       min_col = content_start_col;
+                               if (max_col < 0 || content_end_col > max_col)
+                                       max_col = content_end_col;
+                               if (max_line_count < 0 || (int)l->line_count > max_line_count)
+                                       max_line_count = (int)l->line_count;
+                               if (first_line)
+                                       start_col = content_start_col;
+                               if (last_line)
+                                       end_col = content_end_col;
+
+                               /* optimize by using the content end as a starting point */
+                               s = l->content_start + l->content_len;
+                               e = l->line_start + l->line_count;
+                               col8 = l->content_end_col8;
+                               while ((c = fy_utf8_get(s, (e - s), &w)) >= 0) {
+                                       s += w;
+                                       if (fy_is_tab(c))
+                                               col8 += 8 - (col8 % 8);
+                                       else
+                                               col8++;
+                               }
+                               /* update the max column number of the lines */
+                               if (max_line_col8 < 0 || col8 > max_line_col8)
+                                       max_line_col8 = col8;
+
+                               continue;
+                       }
+
+                       /* output pass */
+
+                       /* the defaults if everything fits */
+                       first_mark = first_line ? '^' : '~';
+
+                       tab8_len = 0;
+
+                       /* find the starting point */
+                       s = l->line_start;
+                       e = s + l->line_len;
+                       col8 = 0;
+                       while (col8 < line_shift && (c = fy_utf8_get(s, (e - s), &w)) >= 0) {
+                               if (fy_is_tab(c))
+                                       col8 += 8 - (col8 % 8);
+                               else
+                                       col8++;
+                               s += w;
+                       }
+                       if (col8 > line_shift)
+                               tab8_len = col8 - line_shift;   /* the remaining of the tab */
+                       else
+                               tab8_len = 0;
+
+                       /* start filling the row buffer */
+                       assert(rowbuf);
+                       rbs = rowbuf;
+                       rbe = rowbuf + rowbufsz;
+
+                       /* remaining tabs */
+                       while (tab8_len > 0) {
+                               *rbs++ = ' ';
+                               tab8_len--;
+                       }
+
+                       /* go forward until end of line or cols */
+                       while (col8 < (line_shift + cols) && (c = fy_utf8_get(s, (e - s), &w)) >= 0 && rbs < rbe) {
+                               if (fy_is_tab(c)) {
+                                       s++;
+                                       tab8_len = 8 - (col8 % 8);
+                                       col8 += tab8_len;
+                                       while (tab8_len > 0 && rbs < rbe) {
+                                               *rbs++ = ' ';
+                                               tab8_len--;
+                                       }
+                               } else {
+                                       while (w > 0 && rbs < rbe) {
+                                               *rbs++ = *s++;
+                                               w--;
+                                       }
+                                       col8++;
+                               }
+                       }
+                       display = rowbuf;
+                       display_len = rbs - rowbuf;
+
+                       tilde_start = content_start_col - line_shift;
+                       tilde_width = content_width;
+                       if (tilde_start + tilde_width > cols)
+                               tilde_width = cols - tilde_start;
+                       tilde_width_m1 = tilde_width > 0 ? (tilde_width - 1) : 0;
+
+                       /* output the line */
+                       fy_diag_write(diag, display, display_len);
+
+                       /* set the tildes */
+                       assert((int)rowbufsz > tilde_width_m1 + 1);
+                       memset(rowbuf, '~', tilde_width_m1);
+                       rowbuf[tilde_width_m1] = '\0';
+
+                       fy_diag_printf(diag, "\n%*s%s%c%.*s%s\n",
+                                      tilde_start, "",
+                                      color_start, first_mark, tilde_width_m1, rowbuf, color_end);
+
+               }
+               fy_atom_raw_line_iter_finish(&iter);
+       }
+}
+
+void fy_diag_error_token_display(struct fy_diag *diag, enum fy_error_type type, struct fy_token *fyt)
+{
+       if (!diag || !fyt)
+               return;
+
+       fy_diag_error_atom_display(diag, type, fy_token_atom(fyt));
+}
+
 void fy_diag_vreport(struct fy_diag *diag,
                     const struct fy_diag_report_ctx *fydrc,
                     const char *fmt, va_list ap)
@@ -443,10 +814,11 @@ void fy_diag_vreport(struct fy_diag *diag,
        const char *name, *color_start = NULL, *color_end = NULL, *white = NULL;
        char *msg_str = NULL, *name_str = NULL;
        const struct fy_mark *start_mark;
-       struct fy_atom_raw_line_iter iter;
-       const struct fy_raw_line *l;
-       char *tildes = "";
-       int j, k, tildesz = 0, line, column;
+       int line, column;
+       struct fy_diag_errorp *errp;
+       struct fy_diag_error *err;
+       size_t spacesz, msgsz, filesz;
+       char *s;
 
        if (!diag || !fydrc || !fmt || !fydrc->fyt)
                return;
@@ -466,65 +838,54 @@ void fy_diag_vreport(struct fy_diag *diag,
        /* it will strip trailing newlines */
        msg_str = alloca_vsprintf(fmt, ap);
 
-       if (diag->cfg.colorize) {
-               switch (fydrc->type) {
-               case FYET_DEBUG:
-                       color_start = "\x1b[37m";       /* normal white */
-                       break;
-               case FYET_INFO:
-                       color_start = "\x1b[37;1m";     /* bright white */
-                       break;
-               case FYET_NOTICE:
-                       color_start = "\x1b[34;1m";     /* bright blue */
-                       break;
-               case FYET_WARNING:
-                       color_start = "\x1b[33;1m";     /* bright yellow */
-                       break;
-               case FYET_ERROR:
-                       color_start = "\x1b[31;1m";     /* bright red */
-                       break;
-               default:
-                       break;
-               }
-               color_end = "\x1b[0m";
-               white = "\x1b[37;1m";
-       } else
-               color_start = color_end = white = "";
+       /* get the colors */
+       fy_diag_get_error_colors(diag, fydrc->type, &color_start, &color_end, &white);
 
        if (name || (line > 0 && column > 0))
                name_str = (line > 0 && column > 0) ?
                        alloca_sprintf("%s%s:%d:%d: ", white, name, line, column) :
                        alloca_sprintf("%s%s: ", white, name);
 
-       fy_diag_printf(diag, "%s" "%s%s: %s" "%s\n",
-               name_str ? : "",
-               color_start, fy_error_type_to_string(fydrc->type), color_end,
-               msg_str);
-
-       fy_atom_raw_line_iter_start(fy_token_atom(fydrc->fyt), &iter);
-       while ((l = fy_atom_raw_line_iter_next(&iter)) != NULL) {
-               fy_diag_printf(diag, "%.*s\n",
-                              (int)l->line_len, l->line_start);
-               j = l->content_start_col8;
-               k = (l->content_end_col8 - l->content_start_col8) - 1;
-               if (k > tildesz) {
-                       if (!tildesz)
-                               tildesz = 32;
-                       while (tildesz < k)
-                               tildesz *= 2;
-                       tildes = alloca(tildesz + 1);
-                       memset(tildes, '~', tildesz);
-                       tildes[tildesz] = '\0';
-               }
-               fy_diag_printf(diag, "%*s%s%c%.*s%s\n",
-                              j, "", color_start,
-                              l->lineno == 1 ? '^' : '~',
-                              k > 0 ? k : 0, tildes, color_end);
-       }
-       fy_atom_raw_line_iter_finish(&iter);
+       if (!diag->collect_errors) {
+               fy_diag_printf(diag, "%s" "%s%s: %s" "%s\n",
+                       name_str ? : "",
+                       color_start, fy_error_type_to_string(fydrc->type), color_end,
+                       msg_str);
+
+               fy_diag_error_token_display(diag, fydrc->type, fydrc->fyt);
 
-       fy_token_unref(fydrc->fyt);
+               fy_token_unref(fydrc->fyt);
 
+       } else if ((errp = malloc(sizeof(*errp))) != NULL) {
+
+               msgsz = strlen(msg_str) + 1;
+               filesz = strlen(name) + 1;
+               spacesz = msgsz + filesz;
+
+               errp->space = malloc(spacesz);
+               if (!errp->space) {
+                       free(errp);
+                       goto out;
+               }
+               s = errp->space;
+
+               err = &errp->e;
+               memset(err, 0, sizeof(*err));
+               err->type = fydrc->type;
+               err->module = fydrc->module;
+               err->fyt = fydrc->fyt;
+               err->msg = s;
+               memcpy(s, msg_str, msgsz);
+               s += msgsz;
+               err->file = s;
+               memcpy(s, name, filesz);
+               s += filesz;
+               err->line = line;
+               err->column = column;
+
+               fy_diag_errorp_list_add_tail(&diag->errors, errp);
+       }
+out:
        if (!diag->on_error && fydrc->type == FYET_ERROR)
                diag->on_error = true;
 }
@@ -685,7 +1046,6 @@ void fy_document_diag_report(struct fy_document *fyd,
 }
 
 /* composer */
-
 int fy_composer_vdiag(struct fy_composer *fyc, unsigned int flags,
                      const char *file, int line, const char *func,
                      const char *fmt, va_list ap)
@@ -751,6 +1111,72 @@ void fy_composer_diag_report(struct fy_composer *fyc,
        va_end(ap);
 }
 
+/* document_builder */
+int fy_document_builder_vdiag(struct fy_document_builder *fydb, unsigned int flags,
+                     const char *file, int line, const char *func,
+                     const char *fmt, va_list ap)
+{
+       struct fy_diag_ctx fydc;
+       int rc;
+
+       if (!fydb || !fmt || !fydb->cfg.diag)
+               return -1;
+
+       /* perform the enable tests early to avoid the overhead */
+       if (((flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT) < fydb->cfg.diag->cfg.level)
+               return 0;
+
+       /* fill in fy_diag_ctx */
+       memset(&fydc, 0, sizeof(fydc));
+
+       fydc.level = (flags & FYDF_LEVEL_MASK) >> FYDF_LEVEL_SHIFT;
+       fydc.module = (flags & FYDF_MODULE_MASK) >> FYDF_MODULE_SHIFT;
+       fydc.source_file = file;
+       fydc.source_line = line;
+       fydc.source_func = func;
+       fydc.line = -1;
+       fydc.column = -1;
+
+       rc = fy_vdiag(fydb->cfg.diag, &fydc, fmt, ap);
+
+       return rc;
+}
+
+int fy_document_builder_diag(struct fy_document_builder *fydb, unsigned int flags,
+                    const char *file, int line, const char *func,
+                    const char *fmt, ...)
+{
+       va_list ap;
+       int rc;
+
+       va_start(ap, fmt);
+       rc = fy_document_builder_vdiag(fydb, flags, file, line, func, fmt, ap);
+       va_end(ap);
+
+       return rc;
+}
+
+void fy_document_builder_diag_vreport(struct fy_document_builder *fydb,
+                             const struct fy_diag_report_ctx *fydrc,
+                             const char *fmt, va_list ap)
+{
+       if (!fydb || !fydb->cfg.diag || !fydrc || !fmt)
+               return;
+
+       fy_diag_vreport(fydb->cfg.diag, fydrc, fmt, ap);
+}
+
+void fy_document_builder_diag_report(struct fy_document_builder *fydb,
+                            const struct fy_diag_report_ctx *fydrc,
+                            const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       fy_document_builder_diag_vreport(fydb, fydrc, fmt, ap);
+       va_end(ap);
+}
+
 /* reader */
 
 int fy_reader_vdiag(struct fy_reader *fyr, unsigned int flags,
index 38dd257e9430034c02978e2ed712ea984d034d2e..2653db52b303650dee552a880a983943052d5a59 100644 (file)
 #define FYDF_MODULE_USER_MASK  7
 #define FYDF_MODULE_USER(x)    FYDF_MODULE(8 + ((x) & FYDF_MODULE_USER_MASK))
 
-struct fy_diag {
-       struct fy_diag_cfg cfg;
-       int refs;
-       bool on_error : 1;
-       bool destroyed : 1;
+struct fy_diag_term_info {
+       int rows;
+       int columns;
 };
 
-void fy_diag_free(struct fy_diag *diag);
-
 struct fy_diag_report_ctx {
        enum fy_error_type type;
        enum fy_error_module module;
@@ -69,6 +65,27 @@ struct fy_diag_report_ctx {
        int override_column;
 };
 
+FY_TYPE_FWD_DECL_LIST(diag_errorp);
+struct fy_diag_errorp {
+       struct list_head node;
+       char *space;
+       struct fy_diag_error e;
+};
+FY_TYPE_DECL_LIST(diag_errorp);
+
+struct fy_diag {
+       struct fy_diag_cfg cfg;
+       int refs;
+       bool on_error : 1;
+       bool destroyed : 1;
+       bool collect_errors : 1;
+       bool terminal_probed : 1;
+       struct fy_diag_term_info term_info;
+       struct fy_diag_errorp_list errors;
+};
+
+void fy_diag_free(struct fy_diag *diag);
+
 void fy_diag_vreport(struct fy_diag *diag,
                     const struct fy_diag_report_ctx *fydrc,
                     const char *fmt, va_list ap);
@@ -98,6 +115,11 @@ int fy_parser_diag(struct fy_parser *fyp, unsigned int flags,
                   const char *fmt, ...)
                        __attribute__((format(printf, 6, 7)));
 
+void fy_diag_error_atom_display(struct fy_diag *diag, enum fy_error_type type,
+                                struct fy_atom *atom);
+void fy_diag_error_token_display(struct fy_diag *diag, enum fy_error_type type,
+                                struct fy_token *fyt);
+
 void fy_parser_diag_vreport(struct fy_parser *fyp,
                            const struct fy_diag_report_ctx *fydrc,
                            const char *fmt, va_list ap);
@@ -561,6 +583,102 @@ void fy_composer_diag_report(struct fy_composer *fyc,
 #define FYC_TOKEN_WARNING(_fyc, _fyt, _module, _fmt, ...) \
        FYC_TOKEN_DIAG(_fyc, _fyt, FYET_WARNING, _module, _fmt, ## __VA_ARGS__)
 
+/* document builder */
+struct fy_document_builder;
+
+int fy_document_builder_vdiag(struct fy_document_builder *fydb, unsigned int flags,
+                             const char *file, int line, const char *func,
+                             const char *fmt, va_list ap);
+
+int fy_document_builder_diag(struct fy_document_builder *fydb, unsigned int flags,
+                            const char *file, int line, const char *func,
+                            const char *fmt, ...)
+                       __attribute__((format(printf, 6, 7)));
+
+void fy_document_builder_diag_vreport(struct fy_document_builder *fydb,
+                                     const struct fy_diag_report_ctx *fydrc,
+                                     const char *fmt, va_list ap);
+void fy_document_builder_diag_report(struct fy_document_builder *fydb,
+                                    const struct fy_diag_report_ctx *fydrc,
+                                    const char *fmt, ...)
+                               __attribute__((format(printf, 3, 4)));
+
+#ifndef NDEBUG
+
+#define fydb_debug(_fydb, _module, _fmt, ...) \
+       fy_document_builder_diag((_fydb), FYET_DEBUG | FYDF_MODULE(_module), \
+                       __FILE__, __LINE__, __func__, \
+                       (_fmt) , ## __VA_ARGS__)
+
+#else
+
+#define fydb_debug(_fydb, _module, _fmt, ...) \
+       do { } while(0)
+
+#endif
+
+#define fydb_info(_fydb, _fmt, ...) \
+       fy_document_builder_diag((_fydb), FYET_INFO, __FILE__, __LINE__, __func__, \
+                       (_fmt) , ## __VA_ARGS__)
+#define fydb_notice(_fydb, _fmt, ...) \
+       fy_document_builder_diag((_fydb), FYET_NOTICE, __FILE__, __LINE__, __func__, \
+                       (_fmt) , ## __VA_ARGS__)
+#define fydb_warning(_fydb, _fmt, ...) \
+       fy_document_builder_diag((_fydb), FYET_WARNING, __FILE__, __LINE__, __func__, \
+                       (_fmt) , ## __VA_ARGS__)
+#define fydb_error(_fydb, _fmt, ...) \
+       fy_document_builder_diag((_fydb), FYET_ERROR, __FILE__, __LINE__, __func__, \
+                       (_fmt) , ## __VA_ARGS__)
+
+#define fydb_error_check(_fydb, _cond, _label, _fmt, ...) \
+       do { \
+               if (!(_cond)) { \
+                       fydb_error((_fydb), _fmt, ## __VA_ARGS__); \
+                       goto _label ; \
+               } \
+       } while(0)
+
+#define _FYDB_TOKEN_DIAG(_fydb, _fyt, _type, _module, _fmt, ...) \
+       do { \
+               struct fy_diag_report_ctx _drc; \
+               memset(&_drc, 0, sizeof(_drc)); \
+               _drc.type = (_type); \
+               _drc.module = (_module); \
+               _drc.fyt = (_fyt); \
+               fy_document_builder_diag_report((_fydb), &_drc, (_fmt) , ## __VA_ARGS__); \
+       } while(0)
+
+#define FYDB_TOKEN_DIAG(_fydb, _fyt, _type, _module, _fmt, ...) \
+       _FYDB_TOKEN_DIAG(_fydb, fy_token_ref(_fyt), _type, _module, _fmt, ## __VA_ARGS__)
+
+#define FYDB_NODE_DIAG(_fydb, _fyn, _type, _module, _fmt, ...) \
+       _FYDB_TOKEN_DIAG(_fydb, fy_node_token(_fyn), _type, _module, _fmt, ## __VA_ARGS__)
+
+#define FYDB_TOKEN_ERROR(_fydb, _fyt, _module, _fmt, ...) \
+       FYDB_TOKEN_DIAG(_fydb, _fyt, FYET_ERROR, _module, _fmt, ## __VA_ARGS__)
+
+#define FYDB_NODE_ERROR(_fydb, _fyn, _module, _fmt, ...) \
+       FYDB_NODE_DIAG(_fydb, _fyn, FYET_ERROR, _module, _fmt, ## __VA_ARGS__)
+
+#define FYDB_TOKEN_ERROR_CHECK(_fydb, _fyt, _module, _cond, _label, _fmt, ...) \
+       do { \
+               if (!(_cond)) { \
+                       FYDB_TOKEN_ERROR(_fydb, _fyt, _module, _fmt, ## __VA_ARGS__); \
+                       goto _label; \
+               } \
+       } while(0)
+
+#define FYDB_NODE_ERROR_CHECK(_fydb, _fyn, _module, _cond, _label, _fmt, ...) \
+       do { \
+               if (!(_cond)) { \
+                       FYDB_NODE_ERROR(_fydb, _fyn, _module, _fmt, ## __VA_ARGS__); \
+                       goto _label; \
+               } \
+       } while(0)
+
+#define FYDB_TOKEN_WARNING(_fydb, _fyt, _module, _fmt, ...) \
+       FYDB_TOKEN_DIAG(_fydb, _fyt, FYET_WARNING, _module, _fmt, ## __VA_ARGS__)
+
 /* alloca formatted print methods */
 #define alloca_vsprintf(_fmt, _ap) \
        ({ \
index a61d95f91e529653dd1dae3a95aea9c7fb63fce2..359ea92dff70c3abf672975de692760684541f9b 100644 (file)
@@ -1265,9 +1265,11 @@ bool fy_node_compare_user(struct fy_node *fyn1, struct fy_node *fyn2,
                }
 
                fynpp1 = alloca(sizeof(*fynpp1) * (count1 + 1));
-               fynpp2 = alloca(sizeof(*fynpp2) * (count2 + 1));
-
+               fy_node_mapping_fill_array(fyn1, fynpp1, count1);
                fy_node_mapping_perform_sort(fyn1, sort_fn, sort_fn_arg, fynpp1, count1);
+
+               fynpp2 = alloca(sizeof(*fynpp2) * (count2 + 1));
+               fy_node_mapping_fill_array(fyn2, fynpp2, count2);
                fy_node_mapping_perform_sort(fyn2, sort_fn, sort_fn_arg, fynpp2, count2);
 
                for (i = 0; i < count1; i++) {
@@ -1663,12 +1665,16 @@ fy_parse_document_load_mapping(struct fy_parser *fyp, struct fy_document *fyd,
                fyp_error_check(fyp, !rc, err_out_rc,
                                "fy_parse_document_load_node() failed");
 
-               /* make sure we don't add an already existing key */
-               duplicate = fy_node_mapping_key_is_duplicate(fyn, fyn_key);
+               /* if we don't allow duplicate keys */
+               if (!(fyd->parse_cfg.flags & FYPCF_ALLOW_DUPLICATE_KEYS)) {
+
+                       /* make sure we don't add an already existing key */
+                       duplicate = fy_node_mapping_key_is_duplicate(fyn, fyn_key);
 
-               FYP_NODE_ERROR_CHECK(fyp, fyn_key, FYEM_DOC,
-                               !duplicate, err_out,
-                               "duplicate key");
+                       FYP_NODE_ERROR_CHECK(fyp, fyn_key, FYEM_DOC,
+                                       !duplicate, err_out,
+                                       "duplicate key");
+               }
 
                fyep = fy_parse_private(fyp);
 
@@ -1735,12 +1741,6 @@ err_out_rc:
        return rc;
 }
 
-/* TODO vary according to platfom */
-static inline int fy_depth_limit(void)
-{
-       return FYPCF_GUARANTEED_MINIMUM_DEPTH_LIMIT;
-}
-
 static int
 fy_parse_document_load_node(struct fy_parser *fyp, struct fy_document *fyd,
                            struct fy_eventp *fyep, struct fy_node **fynp,
@@ -1919,6 +1919,7 @@ err_out:
 
 struct fy_document *fy_parse_load_document_with_builder(struct fy_parser *fyp)
 {
+       struct fy_document_builder_cfg cfg;
        struct fy_document *fyd;
        int rc;
 
@@ -1926,7 +1927,12 @@ struct fy_document *fy_parse_load_document_with_builder(struct fy_parser *fyp)
                return NULL;
 
        if (!fyp->fydb) {
-               fyp->fydb = fy_document_builder_create(&fyp->cfg);
+               memset(&cfg, 0, sizeof(cfg));
+               cfg.parse_cfg = fyp->cfg;
+               cfg.userdata = fyp;
+               cfg.diag = fy_diag_ref(fyp->diag);
+
+               fyp->fydb = fy_document_builder_create(&cfg);
                if (!fyp->fydb)
                        return NULL;
        }
@@ -2722,9 +2728,13 @@ static int fy_resolve_merge_key_populate(struct fy_document *fyd, struct fy_node
        for (fynpi = fy_node_pair_list_head(&fynm->mapping); fynpi;
                fynpi = fy_node_pair_next(&fynm->mapping, fynpi)) {
 
-               /* make sure we don't override an already existing key */
-               if (fy_node_mapping_key_is_duplicate(fyn, fynpi->key))
-                       continue;
+               /* if we don't allow duplicate keys */
+               if (!(fyd->parse_cfg.flags & FYPCF_ALLOW_DUPLICATE_KEYS)) {
+
+                       /* make sure we don't override an already existing key */
+                       if (fy_node_mapping_key_is_duplicate(fyn, fynpi->key))
+                               continue;
+               }
 
                fynpn = fy_node_pair_alloc(fyd);
                fyd_error_check(fyd, fynpn, err_out,
@@ -3107,6 +3117,10 @@ struct fy_document *fy_document_create(const struct fy_parse_cfg *cfg)
        fyd_error_check(fyd, fyd->fyds, err_out,
                        "fy_document_state_default() failed");
 
+       /* turn on JSON mode if it's forced */
+       fyd->fyds->json_mode = (cfg->flags &
+                       (FYPCF_JSON_MASK << FYPCF_JSON_SHIFT)) == FYPCF_JSON_FORCE;
+
        fy_document_list_init(&fyd->children);
 
        return fyd;
@@ -3814,6 +3828,40 @@ fy_node_mapping_lookup_key_by_string(struct fy_node *fyn,
        return fynp ? fynp->key : NULL;
 }
 
+bool fy_node_is_empty(struct fy_node *fyn)
+{
+       struct fy_node *fyni;
+       struct fy_node_pair *fynp;
+       struct fy_atom *atom;
+
+       /* skip if no value node or token */
+       if (!fyn)
+               return true;
+
+       switch (fyn->type) {
+       case FYNT_SCALAR:
+               atom = fy_token_atom(fyn->scalar);
+               if (atom && !atom->size0 && !atom->empty)
+                       return false;
+               break;
+       case FYNT_SEQUENCE:
+               for (fyni = fy_node_list_head(&fyn->sequence); fyni;
+                               fyni = fy_node_next(&fyn->sequence, fyni)) {
+                       if (!fy_node_is_empty(fyni))
+                               return false;
+               }
+               break;
+       case FYNT_MAPPING:
+               for (fynp = fy_node_pair_list_head(&fyn->mapping); fynp;
+                               fynp = fy_node_pair_next(&fyn->mapping, fynp)) {
+                       if (!fy_node_is_empty(fynp->value))
+                               return false;
+               }
+               break;
+       }
+       return true;
+}
+
 #define fy_node_walk_ctx_create_a(_max_depth, _mark) \
        ({ \
                unsigned int __max_depth = (_max_depth); \
@@ -5424,8 +5472,12 @@ fy_node_mapping_pair_insert_prepare(struct fy_node *fyn_map,
            (fyn_value && fyn_value->attached))
                return NULL;
 
-        if (fy_node_mapping_key_is_duplicate(fyn_map, fyn_key))
-               return NULL;
+       /* if we don't allow duplicate keys */
+       if (!(fyd->parse_cfg.flags & FYPCF_ALLOW_DUPLICATE_KEYS)) {
+
+                if (fy_node_mapping_key_is_duplicate(fyn_map, fyn_key))
+                       return NULL;
+       }
 
        fynp = fy_node_pair_alloc(fyd);
        if (!fynp)
@@ -5675,14 +5727,11 @@ static int fy_node_mapping_sort_cmp_default(const struct fy_node_pair *fynp_a,
        return idx_a > idx_b ? 1 : (idx_a < idx_b ? -1 : 0);
 }
 
-void fy_node_mapping_perform_sort(struct fy_node *fyn_map,
-               fy_node_mapping_sort_fn key_cmp, void *arg,
+void fy_node_mapping_fill_array(struct fy_node *fyn_map,
                struct fy_node_pair **fynpp, int count)
 {
-       int i;
        struct fy_node_pair *fynpi;
-       struct fy_node_mapping_sort_ctx ctx;
-       struct fy_node_cmp_arg def_arg;
+       int i;
 
        for (i = 0, fynpi = fy_node_pair_list_head(&fyn_map->mapping); i < count && fynpi;
                fynpi = fy_node_pair_next(&fyn_map->mapping, fynpi), i++)
@@ -5693,6 +5742,15 @@ void fy_node_mapping_perform_sort(struct fy_node *fyn_map,
                fynpp[i++] = NULL;
        assert(i == count);
 
+}
+
+void fy_node_mapping_perform_sort(struct fy_node *fyn_map,
+               fy_node_mapping_sort_fn key_cmp, void *arg,
+               struct fy_node_pair **fynpp, int count)
+{
+       struct fy_node_mapping_sort_ctx ctx;
+       struct fy_node_cmp_arg def_arg;
+
        if (!key_cmp) {
                def_arg.cmp_fn = fy_node_scalar_cmp_default;
                def_arg.arg = arg;
@@ -5734,6 +5792,7 @@ struct fy_node_pair **fy_node_mapping_sort_array(struct fy_node *fyn_map,
 
        memset(fynpp, 0, (count + 1) * sizeof(*fynpp));
 
+       fy_node_mapping_fill_array(fyn_map, fynpp, count);
        fy_node_mapping_perform_sort(fyn_map, key_cmp, arg, fynpp, count);
 
        if (countp)
@@ -5742,7 +5801,7 @@ struct fy_node_pair **fy_node_mapping_sort_array(struct fy_node *fyn_map,
        return fynpp;
 }
 
-void fy_node_mapping_sort_release_array(struct fy_node *fyn_map, struct fy_node_pair **fynpp)
+void fy_node_mapping_release_array(struct fy_node *fyn_map, struct fy_node_pair **fynpp)
 {
        if (!fyn_map || !fynpp)
                return;
@@ -5767,7 +5826,7 @@ int fy_node_mapping_sort(struct fy_node *fyn_map,
                fy_node_pair_list_add_tail(&fyn_map->mapping, fynpi);
        }
 
-       fy_node_mapping_sort_release_array(fyn_map, fynpp);
+       fy_node_mapping_release_array(fyn_map, fynpp);
 
        return 0;
 }
@@ -6387,6 +6446,8 @@ fy_node_hash_internal(struct fy_node *fyn, fy_hash_update_fn update_fn, void *st
                count = fy_node_mapping_item_count(fyn);
 
                fynpp = alloca(sizeof(*fynpp) * (count + 1));
+
+               fy_node_mapping_fill_array(fyn, fynpp, count);
                fy_node_mapping_perform_sort(fyn, NULL, NULL, fynpp, count);
 
                /* MAPPING */
@@ -6472,1149 +6533,152 @@ int fy_document_set_document_state(struct fy_document *fyd, struct fy_document_s
        return 0;
 }
 
-const char *fy_document_builder_state_txt[] = {
-       [FYDBS_NODE]    = "node",
-       [FYDBS_MAP_KEY] = "map-key",
-       [FYDBS_MAP_VAL] = "map-val",
-       [FYDBS_SEQ]     = "seq",
-};
-
-void
-fy_document_builder_reset(struct fy_document_builder *fydb)
-{
-       struct fy_document_builder_ctx *c;
-       unsigned int i;
-
-       if (!fydb)
-               return;
-
-       for (i = 0, c = fydb->stack; i < fydb->next; i++, c++) {
-               fy_node_free(c->fyn);
-               c->fyn = NULL;
-               fy_node_pair_free(c->fynp);
-               c->fynp = NULL;
-       }
-       fydb->next = 0;
-
-       if (fydb->fyd) {
-               fy_document_destroy(fydb->fyd);
-               fydb->fyd = NULL;
-       }
-       fydb->in_stream = false;
-       fydb->doc_done = false;
-}
-
-struct fy_document_builder *
-fy_document_builder_create(const struct fy_parse_cfg *cfg)
-{
-       struct fy_document_builder *fydb = NULL;
-
-       if (!cfg)
-               cfg = &doc_parse_default_cfg;
-
-       fydb = malloc(sizeof(*fydb));
-       if (!fydb)
-               goto err_out;
-
-       memset(fydb, 0, sizeof(*fydb));
-       fydb->cfg = *cfg;
-       fydb->next = 0;
-       fydb->in_stream = false;
-       fydb->doc_done = false;
-       fydb->alloc = fy_depth_limit(); /* always start with this */
-       fydb->max_depth = (cfg->flags & FYPCF_DISABLE_DEPTH_LIMIT) ? 0 : fy_depth_limit();
-
-       fydb->stack = malloc(fydb->alloc * sizeof(*fydb->stack));
-       if (!fydb->stack)
-               goto err_out;
-
-       return fydb;
-
-err_out:
-       if (fydb) {
-               if (fydb->stack)
-                       free(fydb->stack);
-               free(fydb);
-       }
-
-       return NULL;
-}
-
-void
-fy_document_builder_destroy(struct fy_document_builder *fydb)
+struct fy_ptr_node *fy_ptr_node_create(struct fy_node *fyn)
 {
-       if (!fydb)
-               return;
-
-       fy_document_builder_reset(fydb);
+       struct fy_ptr_node *fypn;
 
-       if (fydb->stack)
-               free(fydb->stack);
-       free(fydb);
-}
+       if (!fyn)
+               return NULL;
 
-struct fy_document *
-fy_document_builder_get_document(struct fy_document_builder *fydb)
-{
-       return fydb ? fydb->fyd : NULL;
+       fypn = malloc(sizeof(*fypn));
+       if (!fypn)
+               return NULL;
+       memset(&fypn->node, 0, sizeof(fypn->node));
+       fypn->fyn = fyn;
+       return fypn;
 }
 
-bool
-fy_document_builder_is_in_stream(struct fy_document_builder *fydb)
+void fy_ptr_node_destroy(struct fy_ptr_node *fypn)
 {
-       return fydb && fydb->in_stream;
+       free(fypn);
 }
 
-bool
-fy_document_builder_is_in_document(struct fy_document_builder *fydb)
+void fy_ptr_node_list_free_all(struct fy_ptr_node_list *fypnl)
 {
-       return fydb && fydb->fyd != NULL && !fydb->doc_done;
-}
+       struct fy_ptr_node *fypn;
 
-bool
-fy_document_builder_is_document_complete(struct fy_document_builder *fydb)
-{
-       return fydb && fydb->fyd != NULL && fydb->doc_done;
+       while ((fypn = fy_ptr_node_list_pop(fypnl)) != NULL)
+               fy_ptr_node_destroy(fypn);
 }
 
-struct fy_document *
-fy_document_builder_take_document(struct fy_document_builder *fydb)
+bool fy_ptr_node_list_contains(struct fy_ptr_node_list *fypnl, struct fy_node *fyn)
 {
-       struct fy_document *fyd;
+       struct fy_ptr_node *fypn;
 
-       if (!fy_document_builder_is_document_complete(fydb))
-               return NULL;
-       fyd = fydb->fyd;
-       fydb->fyd = NULL;
-       fydb->doc_done = false;
-       return fyd;
+       if (!fypnl || !fyn)
+               return false;
+       for (fypn = fy_ptr_node_list_head(fypnl); fypn; fypn = fy_ptr_node_next(fypnl, fypn)) {
+               if (fypn->fyn == fyn)
+                       return true;
+       }
+       return false;
 }
 
 struct fy_document *
-fy_document_builder_peek_document(struct fy_document_builder *fydb)
+fy_document_create_from_event(struct fy_parser *fyp, struct fy_event *fye)
 {
        struct fy_document *fyd;
-       struct fy_document_builder_ctx *c;
+       int rc;
 
-       if (!fydb)
+       if (!fyp || !fye || fye->type != FYET_DOCUMENT_START)
                return NULL;
 
-       /* just peek; may be incomplete */
-       fyd = fydb->fyd;
-
-       assert(fydb->next > 0);
-       c = &fydb->stack[0];
+       /* TODO update document end */
+       fyd = fy_document_create(&fyp->cfg);
+       fyp_error_check(fyp, fyd, err_out,
+               "fy_document_create() failed");
 
-       /* wire the root */
-       if (!fyd->root)
-               fyd->root = c->fyn;
+       rc = fy_document_set_document_state(fyd, fye->document_start.document_state);
+       fyp_error_check(fyp, !rc, err_out,
+               "fy_document_set_document_state() failed");
 
        return fyd;
-}
 
-
-void
-fy_document_builder_set_in_stream(struct fy_document_builder *fydb)
-{
-       if (!fydb)
-               return;
-       /* reset */
-       fy_document_builder_reset(fydb);
-
-       fydb->in_stream = true;
+err_out:
+       fy_document_destroy(fyd);
+       return NULL;
 }
 
 int
-fy_document_builder_set_in_document(struct fy_document_builder *fydb, struct fy_document_state *fyds, bool single)
+fy_document_update_from_event(struct fy_document *fyd, struct fy_parser *fyp, struct fy_event *fye)
 {
-       struct fy_document_builder_ctx *c;
-       int rc;
-
-       if (!fydb)
-               return -1;
-
-       /* reset */
-       fy_document_builder_reset(fydb);
-
-       fydb->in_stream = true;
-
-       fydb->fyd = fy_document_create(&fydb->cfg);
-       if (!fydb->fyd)
+       if (!fyd || !fyp || !fye || fye->type != FYET_DOCUMENT_END)
                return -1;
 
-       if (fyds) {
-               rc = fy_document_set_document_state(fydb->fyd, fyds);
-               if (rc)
-                       return rc;
-       }
-
-       fydb->doc_done = false;
-       fydb->single_mode = single;
-
-       /* be paranoid */
-       assert(fydb->next < fydb->alloc);
-
-       c = &fydb->stack[++fydb->next - 1];
-       memset(c, 0, sizeof(*c));
-       c->s = FYDBS_NODE;
-
+       /* nothing besides checks */
        return 0;
 }
 
-#undef DBG
-// #define DBG fyp_info
-#define DBG fyp_doc_debug
-
-int
-fy_document_builder_process_event(struct fy_document_builder *fydb,
-               struct fy_parser *fyp, struct fy_eventp *fyep)
+struct fy_node *
+fy_node_create_from_event(struct fy_document *fyd, struct fy_parser *fyp, struct fy_event *fye)
 {
-       struct fy_event *fye;
-       enum fy_event_type etype;
-       struct fy_document *fyd;
-       struct fy_document_builder_ctx *c, *cp;
-       struct fy_node *fyn, *fyn_parent;
-       struct fy_node_pair *fynp;
-       struct fy_document_builder_ctx *newc;
-       struct fy_token *fyt;
+       struct fy_node *fyn = NULL;
+       struct fy_token *value = NULL, *anchor = NULL;
        int rc;
 
-       fye = fyep ? &fyep->e : NULL;
-       etype = fye ? fye->type : FYET_NONE;
-       fyt = fye ? fy_event_get_token(fye) : NULL;
-
-       /* not in document */
-       if (!fydb->next) {
-               switch (etype) {
-               case FYET_STREAM_START:
-                       FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC,
-                                       !fydb->in_stream, err_out,
-                                       "STREAM_START while in stream error");
-                       fydb->in_stream = true;
-                       break;
-
-               case FYET_STREAM_END:
-                       FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC,
-                                       fydb->in_stream, err_out,
-                                       "STREAM_END while not in stream error");
-                       fydb->in_stream = false;
-                       return 1;
-
-               case FYET_DOCUMENT_START:
-                       FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC,
-                                       fydb->in_stream, err_out,
-                                       "DOCUMENT_START while not in stream error");
-
-                       /* no-one cares, destroy the document */
-                       if (!fydb->fyd)
-                               fy_document_destroy(fydb->fyd);
-
-                       fydb->fyd = fy_document_create(&fydb->cfg);
-                       fyp_error_check(fyp, fydb->fyd, err_out,
-                                       "fy_document_create() failed");
-
-                       rc = fy_document_set_document_state(fydb->fyd, fyep->e.document_start.document_state);
-                       fyp_error_check(fyp, !rc, err_out,
-                                       "fy_document_set_document_state() failed");
-
-                       fydb->doc_done = false;
-                       goto push;
-
-               case FYET_DOCUMENT_END:
-                       FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC,
-                                       fydb->in_stream, err_out,
-                                       "DOCUMENT_END while not in stream error");
-
-                       FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC,
-                                       fydb->fyd, err_out,
-                                       "DOCUMENT_END without a document");
-
-                       fydb->doc_done = true;
-                       break;
-
-               default:
-                       /* unexpected event */
-                       FYP_TOKEN_ERROR(fyp, fyt, FYEM_DOC,
-                                       "Unexpected event %s in non-build mode\n",
-                                               fy_event_type_txt[etype]);
-                       goto err_out;
-               }
+       if (!fyd || !fye)
+               return NULL;
 
-               return 0;
-       }
+       switch (fye->type) {
+       default:
+               break;
 
-       fyd = fydb->fyd;
+       case FYET_SCALAR:
+               fyn = fy_node_alloc(fyd, FYNT_SCALAR);
+               fyp_error_check(fyp, fyn, err_out,
+                       "fy_node_alloc() scalar failed");
 
-       c = &fydb->stack[fydb->next - 1];
-       fyn = NULL;
+               value = fye->scalar.value;
 
-       /* verify that we have a document */
-       assert(fydb->fyd);
-       /* the top state must always be NODE for processing the event */
-       assert(c->s == FYDBS_NODE);
+               if (value)      /* NULL scalar */
+                       fyn->style = fy_node_style_from_scalar_style(value->scalar.style);
+               else
+                       fyn->style = FYNS_PLAIN;
 
-       // DBG(fyp, "%d: %s <- %s (%s)\n", fydb->next - 1, fy_document_builder_state_txt[c->s], fy_event_type_txt[etype], fy_token_debug_text_a(fyt));
+               /* NULLs are OK */
+               fyn->tag = fy_token_ref(fye->scalar.tag);
+               fyn->scalar = fy_token_ref(value);
+               anchor = fye->scalar.anchor;
+               break;
 
-       switch (etype) {
-       case FYET_SCALAR:
        case FYET_ALIAS:
                fyn = fy_node_alloc(fyd, FYNT_SCALAR);
                fyp_error_check(fyp, fyn, err_out,
-                               "fy_node_alloc() SCALAR failed");
+                       "fy_node_alloc() alias failed");
 
-               if (etype == FYET_SCALAR) {
-                       if (fye->scalar.value)
-                               fyn->style = fy_node_style_from_scalar_style(fye->scalar.value->scalar.style);
-                       else
-                               fyn->style = FYNS_PLAIN;
-                       fyn->tag = fy_token_ref(fye->scalar.tag);
-                       if (fye->scalar.anchor) {
-                               rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->scalar.anchor));
-                               fyp_error_check(fyp, !rc, err_out,
-                                               "fy_document_register_anchor() failed");
-                       }
-                       fyn->scalar = fy_token_ref(fye->scalar.value);
-               } else {
-                       fyn->style = FYNS_ALIAS;
-                       fyn->scalar = fy_token_ref(fye->alias.anchor);
-               }
-               goto complete;
+               value = fye->alias.anchor;
+               fyn->style = FYNS_ALIAS;
+               fyn->scalar = fy_token_ref(value);
+               anchor = NULL;
+               break;
 
        case FYET_MAPPING_START:
-               // DBG(fyp, "%d: %s -> %s\n", fydb->next - 1, fy_document_builder_state_txt[c->s], fy_document_builder_state_txt[FYDBS_MAP_KEY]);
-               c->s = FYDBS_MAP_KEY;
-
-               fyn = fy_node_alloc(fyd, FYNT_MAPPING);
+               fyn = fy_node_create_mapping(fyd);
                fyp_error_check(fyp, fyn, err_out,
-                               "fy_node_alloc() MAPPING failed");
+                       "fy_node_create_mapping() failed");
+
+               value = fye->mapping_start.mapping_start;
+               fyn->style = value->type == FYTT_FLOW_MAPPING_START ? FYNS_FLOW : FYNS_BLOCK;
 
-               c->fyn = fyn;
-               fyn->style = fye->mapping_start.mapping_start->type == FYTT_FLOW_MAPPING_START ? FYNS_FLOW : FYNS_BLOCK;
                fyn->tag = fy_token_ref(fye->mapping_start.tag);
-               if (fye->mapping_start.anchor) {
-                       rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->mapping_start.anchor));
-                       fyp_error_check(fyp, !rc, err_out,
-                                       "fy_document_register_anchor() failed");
-               }
-               fyn->mapping_start = fy_token_ref(fye->mapping_start.mapping_start);
+               fyn->mapping_start = fy_token_ref(value);
+               fyn->mapping_end = NULL;
+               anchor = fye->mapping_start.anchor;
                break;
 
-       case FYET_MAPPING_END:
-
-               FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC, fydb->next > 1, err_out,
-                               "Unexpected MAPPING_END (unexpected end of mapping)");
-
-               cp = &fydb->stack[fydb->next - 2];
-
-               FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC, cp->s == FYDBS_MAP_KEY, err_out,
-                               "Unexpected MAPPING_END (not in mapping)");
-
-               fyn = cp->fyn;
-               fyn->mapping_end = fy_token_ref(fye->mapping_end.mapping_end);
-               fydb->next--;
-               goto complete;
-
        case FYET_SEQUENCE_START:
-               // DBG(fyp, "%d: %s -> %s\n", fydb->next - 1, fy_document_builder_state_txt[c->s], fy_document_builder_state_txt[FYDBS_SEQ]);
-               c->s = FYDBS_SEQ;
-               fyn = fy_node_alloc(fyd, FYNT_SEQUENCE);
+               fyn = fy_node_create_sequence(fyd);
                fyp_error_check(fyp, fyn, err_out,
-                               "fy_node_alloc() SEQUENCE failed");
+                       "fy_node_create_sequence() failed");
 
-               c->fyn = fyn;
-               fyn->style = fye->sequence_start.sequence_start->type == FYTT_FLOW_SEQUENCE_START ? FYNS_FLOW : FYNS_BLOCK;
-               fyn->tag = fy_token_ref(fye->sequence_start.tag);
-               if (fye->sequence_start.anchor) {
-                       rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->sequence_start.anchor));
-                       fyp_error_check(fyp, !rc, err_out,
-                                       "fy_document_register_anchor() failed");
-               }
-               fyn->sequence_start = fy_token_ref(fye->sequence_start.sequence_start);
-               break;
+               value = fye->sequence_start.sequence_start;
 
-       case FYET_SEQUENCE_END:
+               fyn->style = value->type == FYTT_FLOW_SEQUENCE_START ? FYNS_FLOW : FYNS_BLOCK;
 
-               FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC, fydb->next > 1, err_out,
-                               "Unexpected SEQUENCE_END (unexpected end of sequence)");
-
-               cp = &fydb->stack[fydb->next - 2];
-
-               FYP_TOKEN_ERROR_CHECK(fyp, fyt, FYEM_DOC, cp->s == FYDBS_SEQ, err_out,
-                               "Unexpected MAPPING_SEQUENCE (not in sequence)");
-
-               fyn = cp->fyn;
-               fyn->sequence_end = fy_token_ref(fye->sequence_end.sequence_end);
-               fydb->next--;
-               goto complete;
-
-       default:
-               /* unexpected event */
-               FYP_TOKEN_ERROR(fyp, fyt, FYEM_DOC,
-                               "Unexpected event %s in build mode\n",
-                                       fy_event_type_txt[etype]);
-               goto err_out;
-       }
-
-push:
-       FYP_PARSE_ERROR_CHECK(fyp, 0, 0, FYEM_DOC,
-                       !fydb->max_depth || fydb->next < fydb->max_depth, err_out,
-                       "Max depth (%d) exceeded\n", fydb->next);
-
-       /* grow the stack? */
-       if (fydb->next >= fydb->alloc) {
-               newc = realloc(fydb->stack, fydb->alloc * 2 * sizeof(*fydb->stack));
-               fyp_error_check(fyp, newc, err_out,
-                               "Unable to grow the context stack");
-               fydb->alloc *= 2;
-               fydb->stack = newc;
-       }
-       assert(fydb->next < fydb->alloc);
-
-       // DBG(fyp, "%d: PUSH %s -> %s\n", fydb->next - 1,
-       //              fydb->next > 0 ? fy_document_builder_state_txt[fydb->stack[fydb->next - 1].s] : "<NIL>",
-       //              fy_document_builder_state_txt[FYDBS_NODE]);
-
-       c = &fydb->stack[++fydb->next - 1];
-       memset(c, 0, sizeof(*c));
-       c->s = FYDBS_NODE;
-       return 0;
-
-err_out:
-       return -1;
-
-complete:
-       assert(fydb->next > 0);
-       c = &fydb->stack[fydb->next - 1];
-       c->fyn = fyn;
-       // DBG(fyp, "%d: COMPLETE %s -> %s\n", fydb->next - 1,
-       //      fy_document_builder_state_txt[c->s],
-       //      fydb->next > 1 ? fy_document_builder_state_txt[fydb->stack[fydb->next - 2].s] : "<NIL>");
-       assert(fydb->next > 0);
-       fydb->next--;
-
-       /* root */
-       if (fydb->next == 0) {
-               fyd->root = fyn;
-               // DBG(fyp, "root done\n");
-               /* if we're in single mode, don't wait for doc end */
-               if (fydb->single_mode)
-                       fydb->doc_done = true;
-               return 1;
-       }
-
-       c = &fydb->stack[fydb->next - 1];
-
-       // DBG(fyp, "%d: %s - COMPLETE\n", fydb->next - 1, fy_document_builder_state_txt[c->s]);
-
-       fyn_parent = c->fyn;
-
-       switch (c->s) {
-
-       case FYDBS_MAP_KEY:
-               fynp = fy_node_pair_alloc(fyd);
-               assert(fynp);
-               fynp->key = fyn;
-               c->fynp = fynp;
-
-               /* make sure we don't add an already existing key */
-               if (fy_node_mapping_key_is_duplicate(fyn_parent, fyn)) {
-                       FYP_NODE_ERROR(fyp, fyn, FYEM_DOC, "duplicate key");
-                       goto err_out;
-               }
-
-               // DBG(fyp, "%d: %s -> %s\n", fydb->next - 1, fy_document_builder_state_txt[c->s], fy_document_builder_state_txt[FYDBS_MAP_VAL]);
-               c->s = FYDBS_MAP_VAL;
-               goto push;
-
-       case FYDBS_MAP_VAL:
-               fynp = c->fynp;
-               assert(fynp);
-               fynp->value = fyn;
-
-               /* set the parent of the node pair and value */
-               fynp->parent = fyn_parent;
-               if (fynp->key) {
-                       fynp->key->parent = fyn_parent;
-                       fynp->key->key_root = true;
-               }
-               if (fynp->value)
-                       fynp->value->parent = fyn_parent;
-
-               fy_node_pair_list_add_tail(&c->fyn->mapping, fynp);
-               if (fyn->xl) {
-                       rc = fy_accel_insert(fyn->xl, fynp->key, fynp);
-                       assert(!rc);
-               }
-               if (fynp->key)
-                       fynp->key->attached = true;
-               if (fynp->value)
-                       fynp->value->attached = true;
-
-               c->fynp = NULL;
-               // DBG(fyp, "%d: %s -> %s\n", fydb->next - 1, fy_document_builder_state_txt[c->s], fy_document_builder_state_txt[FYDBS_MAP_KEY]);
-               c->s = FYDBS_MAP_KEY;
-               goto push;
-
-       case FYDBS_SEQ:
-               /* append sequence */
-               fyn->parent = fyn_parent;
-               fy_node_list_add_tail(&c->fyn->sequence, fyn);
-               fyn->attached = true;
-               goto push;
-
-       case FYDBS_NODE:
-               /* complete is a scalar */
-               fyn->parent = fyn_parent;
-               return 0;
-       }
-
-       return 0;
-}
-
-struct fy_document *
-fy_document_builder_load_document(struct fy_document_builder *fydb,
-                                 struct fy_parser *fyp)
-{
-       struct fy_eventp *fyep = NULL;
-       int rc;
-
-       if (fyp->state == FYPS_END)
-               return NULL;
-
-       while (!fy_document_builder_is_document_complete(fydb) &&
-               (fyep = fy_parse_private(fyp)) != NULL) {
-               rc = fy_document_builder_process_event(fydb, fyp, fyep);
-               fy_parse_eventp_recycle(fyp, fyep);
-               if (rc < 0) {
-                       fyp->stream_error = true;
-                       return NULL;
-               }
-       }
-
-       /* get ownership of the document */
-       return fy_document_builder_take_document(fydb);
-}
-
-static bool fy_node_iterator_ensure_space(struct fy_node_iterator *fyi)
-{
-       struct fy_node_iterator_state *new_stack;
-       size_t size;
-
-       if (fyi->count < fyi->alloc)
-               return true;
-
-       size = fyi->alloc * sizeof(*new_stack);
-
-       if (fyi->stack == fyi->in_place) {
-               new_stack = malloc(size * 2);
-               if (!new_stack) {
-                       fyi->result = FYNIR_NOMEM;
-                       assert(0);
-                       return false;
-               }
-               memcpy(new_stack, fyi->stack, size);
-       } else {
-               new_stack = realloc(fyi->stack, size * 2);
-               if (!new_stack) {
-                       fyi->result = FYNIR_NOMEM;
-                       assert(0);
-                       return false;
-               }
-       }
-       fyi->stack = new_stack;
-       fyi->alloc *= 2;
-       return true;
-}
-
-void fy_node_iterator_setup(struct fy_node_iterator *fyi, enum fy_node_iterator_flags flags)
-{
-       fyi->flags = flags;
-       fyi->result = FYNIR_OK;
-       fyi->count = 0;
-       fyi->alloc = sizeof(fyi->in_place) / sizeof(fyi->in_place[0]);
-       fyi->stack = fyi->in_place;
-}
-
-void fy_node_iterator_cleanup(struct fy_node_iterator *fyi)
-{
-       if (!fyi)
-               return;
-       if (fyi->stack != fyi->in_place)
-               free(fyi->stack);
-       fyi->result = FYNIR_OK;
-       fyi->count = 0;
-       fyi->alloc = sizeof(fyi->in_place) / sizeof(fyi->in_place[0]);
-       fyi->stack = fyi->in_place;
-}
-
-struct fy_node_iterator *fy_node_iterator_create(enum fy_node_iterator_flags flags)
-{
-       struct fy_node_iterator *fyi;
-
-       fyi = malloc(sizeof(*fyi));
-       if (!fyi)
-               return NULL;
-       fy_node_iterator_setup(fyi, flags);
-       return fyi;
-}
-
-void fy_node_iterator_destroy(struct fy_node_iterator *fyi)
-{
-       if (!fyi)
-               return;
-       fy_node_iterator_cleanup(fyi);
-       free(fyi);
-}
-
-void fy_node_iterator_start(struct fy_node_iterator *fyi, struct fy_node *fyn)
-{
-       if (!fyi || !fyn)
-               return;
-
-       fyi->count = 1;
-       fyi->stack[0].fyn = fyn;
-       fyi->result = FYNIR_OK;
-}
-
-#define fy_node_info_a(_fyn) \
-       ({ \
-               struct fy_node *__fyn = (_fyn); \
-               const char *__text = NULL; \
-               \
-               if (!__fyn) { \
-                       __text = "<NULL>"; \
-               } else { \
-                       switch (__fyn->type) { \
-                       case FYNT_SCALAR: \
-                               __text = fy_node_get_scalar0(__fyn); \
-                               break; \
-                       case FYNT_MAPPING: \
-                               __text = "{"; \
-                               break; \
-                       case FYNT_SEQUENCE: \
-                               __text = "["; \
-                               break; \
-                       } \
-               } \
-               __text; \
-       })
-
-struct fy_node *fy_node_iterator_next(struct fy_node_iterator *fyi, struct fy_node *fyn)
-{
-       struct fy_node *fyni, *parent;
-       struct fy_node_pair *fynp;
-       struct fy_node *fyna;
-       unsigned int i;
-
-       if (!fyi || fyi->count == 0)
-               return NULL;
-
-       if (!fyn) {
-               assert(fyi->count == 1);
-               /* start */
-               fyn = fyi->stack[fyi->count - 1].fyn;
-               assert(fyn);
-               // fprintf(stderr, "start: %s\n", fy_node_get_path_a(fyn));
-               goto out;
-       }
-
-       if (fyi->count == 0)
-               return NULL;
-
-       assert(fyi->count > 0);
-
-       /* protect against stupid calls */
-       if (fyn != fyi->stack[fyi->count - 1].fyn) {
-               fyi->result = FYNIR_ARGS;
-               return NULL;
-       }
-
-from_the_top:
-
-       /* if we're following links, check for self reference loop */
-       if (fyi->flags & FYNIF_FOLLOW_LINKS) {
-               for (i = 0; i < fyi->count-1; i++) {
-                       if (fyn == fyi->stack[i].fyn) {
-                               /* loop! */
-                               fyi->result = FYNIR_LOOP;
-                               return NULL;
-                       }
-               }
-       }
-
-       switch (fyn->type) {
-       case FYNT_SCALAR:
-               /* we do not follow links, or node is not an alias */
-               if (!(fyi->flags & FYNIF_FOLLOW_LINKS) || !fy_node_is_alias(fyn))
-                       break;
-
-               fyna = fy_node_resolve_alias(fyn);
-               if (!fyna) {
-                       fyi->result = FYNIR_BAD_ALIAS;
-                       return NULL;
-               }
-
-               if (!fy_node_iterator_ensure_space(fyi))
-                       return NULL;
-
-               fyi->count++;
-               fyi->stack[fyi->count - 1].fyn = fyna;
-               fyi->stack[fyi->count - 1].fynp = NULL;
-               // fprintf(stderr, "+alias: %s @%s - %s @%s\n",
-               //              fy_node_info_a(fyn), fy_node_get_path_a(fyn),
-               //              fy_node_info_a(fyna), fy_node_get_path(fyna));
-               fyn = fyna;
-               goto out;
-
-       case FYNT_SEQUENCE:
-               fyni = fy_node_list_head(&fyn->sequence);
-
-               /* if there are no items, next */
-               if (!fyni)
-                       break;
-
-               if (!fy_node_iterator_ensure_space(fyi))
-                       return NULL;
-
-               fyi->count++;
-               fyi->stack[fyi->count - 1].fyn = fyni;
-               fyi->stack[fyi->count - 1].idx = 0;
-
-               // fprintf(stderr, "+seq: %s @%s - first %s @%s\n",
-               //              fy_node_info_a(fyn), fy_node_get_path_a(fyn),
-               //              fy_node_info_a(fyni), fy_node_get_path(fyni));
-
-               goto out;
-
-       case FYNT_MAPPING:
-               fynp = fy_node_pair_list_head(&fyn->mapping);
-
-               /* empty mapping? next */
-               if (!fynp || (!fynp->key && !fynp->value))
-                       break;
-
-               /* we're not following keys, and there's no value? next */
-               if (!(fyi->flags & FYNIF_FOLLOW_KEYS) && !fynp->value)
-                       break;
-
-               if (!fy_node_iterator_ensure_space(fyi))
-                       return NULL;
-
-               fyi->count++;
-               if ((fyi->flags & FYNIF_FOLLOW_KEYS) && fynp->key) {
-                       fyi->stack[fyi->count - 1].fyn = fynp->key;
-                       // fprintf(stderr, "+map: %s @%s - first key %s @%s\n",
-                       //              fy_node_info_a(fyn), fy_node_get_path_a(fyn),
-                       //              fy_node_info_a(fynp->key), fy_node_get_path(fynp->key));
-               } else {
-                       fyi->stack[fyi->count - 1].fyn = fynp->value;
-                       // fprintf(stderr, "+map: %s @%s - first key %s @%s\n",
-                       //              fy_node_info_a(fyn), fy_node_get_path_a(fyn),
-                       //              fy_node_info_a(fynp->value), fy_node_get_path(fynp->value));
-               }
-               fyi->stack[fyi->count - 1].fynp = fynp;
-               goto out;
-       }
-
-       /* next */
-again:
-       if (fyi->count == 0) {
-               // fprintf(stderr, "end: count=0\n");
-               return NULL;
-       }
-       if (fyi->count == 1) {
-               // fprintf(stderr, "end: count=1\n");
-               /* last one */
-               fyi->count--;
-               return NULL;
-       }
-
-       parent = fyi->stack[fyi->count - 2].fyn;
-       switch (parent->type) {
-       case FYNT_SCALAR:
-               assert(fy_node_is_alias(parent));
-               // fprintf(stderr, "alias-next: %s @%s\n", fy_node_info_a(fyn), fy_node_get_path_a(fyn));
-               fyi->count--;
-               fyn = fyi->stack[fyi->count - 1].fyn;
-               goto again;
-
-       case FYNT_SEQUENCE:
-               fyn = fy_node_next(&parent->sequence, fyn);
-               if (!fyn) {
-                       fyi->count--;
-                       assert(fyi->count > 0);
-
-                       // fprintf(stderr, "seq-end: %s @%s\n", fy_node_info_a(parent), fy_node_get_path_a(parent));
-
-                       fyn = fyi->stack[fyi->count - 1].fyn;
-                       goto again;
-               }
-
-               // fprintf(stderr, "seq-next: %s @%s\n", fy_node_info_a(fyn), fy_node_get_path_a(fyn));
-
-               fyi->stack[fyi->count - 1].fyn = fyn;
-               fyi->stack[fyi->count - 1].idx++;
-               break;
-
-       case FYNT_MAPPING:
-               fynp = fyi->stack[fyi->count - 1].fynp;
-               assert(fynp);
-               assert(fyn == fynp->key || fyn == fynp->value);
-
-               /* got key? now get value */
-               if (fyn == fynp->key && fynp->value) {
-                       fyi->stack[fyi->count - 1].fyn = fynp->value;
-
-                       // fprintf(stderr, "map-next: value1 %s @%s\n", fy_node_info_a(fynp->value), fy_node_get_path_a(fynp->value));
-
-                       break;
-               }
-
-               for (;;) {
-                       fynp = fy_node_pair_next(&parent->mapping, fynp);
-                       if (!fynp) {
-                               fyi->count--;
-                               assert(fyi->count > 0);
-
-                               // fprintf(stderr, "map-end: %s @%s\n", fy_node_info_a(parent), fy_node_get_path_a(parent));
-
-                               fyn = fyi->stack[fyi->count - 1].fyn;
-                               goto again;
-                       }
-                       if ((fyi->flags & FYNIF_FOLLOW_KEYS) && fynp->key) {
-                               fyi->stack[fyi->count - 1].fyn = fynp->key;
-                               // fprintf(stderr, "map-next: key %s @%s\n", fy_node_info_a(fynp->key), fy_node_get_path_a(fynp->key));
-                               break;
-                       }
-                       if (fynp->value) {
-                               fyi->stack[fyi->count - 1].fyn = fynp->value;
-                               // fprintf(stderr, "map-next: value2 %s @%s\n", fy_node_info_a(fynp->value), fy_node_get_path_a(fynp->value));
-                               break;
-                       }
-               }
-               fyi->stack[fyi->count - 1].fynp = fynp;
-               break;
-       }
-
-out:
-       fyn = fyi->stack[fyi->count - 1].fyn;
-       assert(fyn);
-
-       /* if we're following and erasing the links and an alias, redo */
-       if ((fyi->flags & (FYNIF_FOLLOW_LINKS | FYNIF_ERASE_LINKS)) ==
-                         (FYNIF_FOLLOW_LINKS | FYNIF_ERASE_LINKS) &&
-               fy_node_is_alias(fyn))
-               goto from_the_top;
-
-       return fyn;
-}
-
-enum fy_node_iterator_result fy_node_iterator_end(struct fy_node_iterator *fyi)
-{
-       enum fy_node_iterator_result res;
-
-       if (!fyi)
-               return FYNIR_ARGS;
-
-       res = fyi->result;
-       fyi->result = FYNIR_OK;
-
-       return res;
-}
-
-struct fy_ptr_node *fy_ptr_node_create(struct fy_node *fyn)
-{
-       struct fy_ptr_node *fypn;
-
-       if (!fyn)
-               return NULL;
-
-       fypn = malloc(sizeof(*fypn));
-       if (!fypn)
-               return NULL;
-       memset(&fypn->node, 0, sizeof(fypn->node));
-       fypn->fyn = fyn;
-       return fypn;
-}
-
-void fy_ptr_node_destroy(struct fy_ptr_node *fypn)
-{
-       free(fypn);
-}
-
-void fy_ptr_node_list_free_all(struct fy_ptr_node_list *fypnl)
-{
-       struct fy_ptr_node *fypn;
-
-       while ((fypn = fy_ptr_node_list_pop(fypnl)) != NULL)
-               fy_ptr_node_destroy(fypn);
-}
-
-bool fy_ptr_node_list_contains(struct fy_ptr_node_list *fypnl, struct fy_node *fyn)
-{
-       struct fy_ptr_node *fypn;
-
-       if (!fypnl || !fyn)
-               return false;
-       for (fypn = fy_ptr_node_list_head(fypnl); fypn; fypn = fy_ptr_node_next(fypnl, fypn)) {
-               if (fypn->fyn == fyn)
-                       return true;
-       }
-       return false;
-}
-
-int fy_node_linearize_recursive(struct fy_ptr_node_list *fypnl, struct fy_node *fyn)
-{
-       struct fy_ptr_node *fypn;
-       struct fy_node *fyni;
-       struct fy_node_pair *fynp;
-       int ret;
-
-       if (!fyn)
-               return 0;
-
-       /* recursive loop */
-       if (fy_ptr_node_list_contains(fypnl, fyn))
-               return 1;
-
-       fypn = fy_ptr_node_create(fyn);
-       if (!fypn)
-               return -1;
-
-       fy_ptr_node_list_add_tail(fypnl, fypn);
-
-       switch (fyn->type) {
-       case FYNT_SCALAR:
-               break;
-
-       case FYNT_SEQUENCE:
-               for (fyni = fy_node_list_head(&fyn->sequence); fyni;
-                               fyni = fy_node_next(&fyn->sequence, fyni)) {
-
-                       ret = fy_node_linearize_recursive(fypnl, fyni);
-                       if (ret != 0)
-                               return ret;
-               }
-               break;
-
-       case FYNT_MAPPING:
-               for (fynp = fy_node_pair_list_head(&fyn->mapping); fynp;
-                               fynp = fy_node_pair_next(&fyn->mapping, fynp)) {
-
-                       ret = fy_node_linearize_recursive(fypnl, fynp->key);
-                       if (ret != 0)
-                               return ret;
-                       ret = fy_node_linearize_recursive(fypnl, fynp->value);
-                       if (ret != 0)
-                               return ret;
-               }
-               break;
-       }
-
-       return 0;
-}
-
-int fy_node_linearize(struct fy_ptr_node_list *fypnl, struct fy_node *fyn)
-{
-       struct fy_node_iterator fyi_local, *fyi = &fyi_local;
-       enum fy_node_iterator_result res;
-       struct fy_ptr_node *fypn;
-       int ret;
-
-       fy_node_iterator_setup(fyi, FYNIF_DEPTH_FIRST | FYNIF_FOLLOW_KEYS);
-
-       ret = 0;
-       fy_node_iterator_start(fyi, fyn);
-       fyn = NULL;
-       while ((fyn = fy_node_iterator_next(fyi, fyn)) != NULL) {
-
-               /* recursive loop */
-               if (fy_ptr_node_list_contains(fypnl, fyn)) {
-                       ret = 1;
-                       break;
-               }
-               fypn = fy_ptr_node_create(fyn);
-               if (!fypn) {
-                       ret = -1;
-                       break;
-               }
-               fy_ptr_node_list_add_tail(fypnl, fypn);
-       }
-
-       res = fy_node_iterator_end(fyi);
-       if (res != FYNIR_OK)
-               return -1;
-
-       fy_node_iterator_cleanup(fyi);
-
-       return ret;
-}
-
-void fy_node_iterator_check(struct fy_node *fyn)
-{
-       struct fy_ptr_node_list l1, l2;
-       struct fy_ptr_node *fypn1, *fypn2;
-       int ret __FY_DEBUG_UNUSED__;
-
-       fy_ptr_node_list_init(&l1);
-       fy_ptr_node_list_init(&l2);
-
-       ret = fy_node_linearize_recursive(&l1, fyn);
-       assert(!ret);
-       ret = fy_node_linearize(&l2, fyn);
-       assert(!ret);
-
-       fypn1 = fy_ptr_node_list_head(&l1);
-       fypn2 = fy_ptr_node_list_head(&l2);
-
-       while (fypn1 && fypn2) {
-               if (fypn1->fyn != fypn2->fyn) {
-                       fprintf(stderr, "%s: %s != %s\n", __func__, fy_node_get_path_a(fypn1->fyn), fy_node_get_path_a(fypn2->fyn));
-                       break;
-               }
-
-               fypn1 = fy_ptr_node_next(&l1, fypn1);
-               fypn2 = fy_ptr_node_next(&l2, fypn2);
-       }
-
-       if (!fypn1) {
-               if (fypn2)
-                       fprintf(stderr, "%s: <NULL> != %s\n", __func__, fy_node_get_path_a(fypn2->fyn));
-       }
-       if (!fypn2) {
-               if (fypn1)
-                       fprintf(stderr, "%s: %s != <NULL>\n", __func__, fy_node_get_path_a(fypn1->fyn));
-       }
-
-       fy_ptr_node_list_free_all(&l2);
-       fy_ptr_node_list_free_all(&l1);
-}
-
-int fy_node_check_ref_loop(struct fy_node *fyn)
-{
-       struct fy_node_iterator fyi_local, *fyi = &fyi_local;
-       enum fy_node_iterator_result res;
-
-       fy_node_iterator_setup(fyi, FYNIF_DEPTH_FIRST | FYNIF_FOLLOW_KEYS | FYNIF_FOLLOW_LINKS);
-
-       fy_node_iterator_start(fyi, fyn);
-
-       /* if there's a reference loop the iterator will NULL with an error */
-       fyn = NULL;
-       while ((fyn = fy_node_iterator_next(fyi, fyn)) != NULL) { }
-
-       res = fy_node_iterator_end(fyi);
-
-       fy_node_iterator_cleanup(fyi);
-
-       return res == FYNIR_OK ? 0 : -1;
-}
-
-struct fy_document *
-fy_document_create_from_event(struct fy_parser *fyp, struct fy_event *fye)
-{
-       struct fy_document *fyd;
-       int rc;
-
-       if (!fyp || !fye || fye->type != FYET_DOCUMENT_START)
-               return NULL;
-
-       /* TODO update document end */
-       fyd = fy_document_create(&fyp->cfg);
-       fyp_error_check(fyp, fyd, err_out,
-               "fy_document_create() failed");
-
-       rc = fy_document_set_document_state(fyd, fye->document_start.document_state);
-       fyp_error_check(fyp, !rc, err_out,
-               "fy_document_set_document_state() failed");
-
-       return fyd;
-
-err_out:
-       fy_document_destroy(fyd);
-       return NULL;
-}
-
-int
-fy_document_update_from_event(struct fy_document *fyd, struct fy_parser *fyp, struct fy_event *fye)
-{
-       if (!fyd || !fyp || !fye || fye->type != FYET_DOCUMENT_END)
-               return -1;
-
-       /* nothing besides checks */
-       return 0;
-}
-
-struct fy_node *
-fy_node_create_from_event(struct fy_document *fyd, struct fy_parser *fyp, struct fy_event *fye)
-{
-       struct fy_node *fyn = NULL;
-       struct fy_token *value = NULL, *anchor = NULL;
-       int rc;
-
-       if (!fyd || !fye)
-               return NULL;
-
-       switch (fye->type) {
-       default:
-               break;
-
-       case FYET_SCALAR:
-               fyn = fy_node_alloc(fyd, FYNT_SCALAR);
-               fyp_error_check(fyp, fyn, err_out,
-                       "fy_node_alloc() scalar failed");
-
-               value = fye->scalar.value;
-
-               if (value)      /* NULL scalar */
-                       fyn->style = fy_node_style_from_scalar_style(value->scalar.style);
-               else
-                       fyn->style = FYNS_PLAIN;
-
-               /* NULLs are OK */
-               fyn->tag = fy_token_ref(fye->scalar.tag);
-               fyn->scalar = fy_token_ref(value);
-               anchor = fye->scalar.anchor;
-               break;
-
-       case FYET_ALIAS:
-               fyn = fy_node_alloc(fyd, FYNT_SCALAR);
-               fyp_error_check(fyp, fyn, err_out,
-                       "fy_node_alloc() alias failed");
-
-               value = fye->alias.anchor;
-               fyn->style = FYNS_ALIAS;
-               fyn->scalar = fy_token_ref(value);
-               anchor = NULL;
-               break;
-
-       case FYET_MAPPING_START:
-               fyn = fy_node_create_mapping(fyd);
-               fyp_error_check(fyp, fyn, err_out,
-                       "fy_node_create_mapping() failed");
-
-               value = fye->mapping_start.mapping_start;
-               fyn->style = value->type == FYTT_FLOW_MAPPING_START ? FYNS_FLOW : FYNS_BLOCK;
-
-               fyn->tag = fy_token_ref(fye->mapping_start.tag);
-               fyn->mapping_start = fy_token_ref(value);
-               fyn->mapping_end = NULL;
-               anchor = fye->mapping_start.anchor;
-               break;
-
-       case FYET_SEQUENCE_START:
-               fyn = fy_node_create_sequence(fyd);
-               fyp_error_check(fyp, fyn, err_out,
-                       "fy_node_create_sequence() failed");
-
-               value = fye->sequence_start.sequence_start;
-
-               fyn->style = value->type == FYTT_FLOW_SEQUENCE_START ? FYNS_FLOW : FYNS_BLOCK;
-
-               fyn->tag = fy_token_ref(fye->sequence_start.tag);
-               fyn->sequence_start = fy_token_ref(value);
-               fyn->sequence_end = NULL;
-               anchor = fye->sequence_start.anchor;
+               fyn->tag = fy_token_ref(fye->sequence_start.tag);
+               fyn->sequence_start = fy_token_ref(value);
+               fyn->sequence_end = NULL;
+               anchor = fye->sequence_start.anchor;
 
                break;
 
@@ -7674,12 +6738,16 @@ fy_node_pair_create_with_key(struct fy_document *fyd, struct fy_node *fyn_parent
        if (!fyd || !fyn_parent || !fy_node_is_mapping(fyn_parent))
                return NULL;
 
-       /* make sure we don't add an already existing key */
-       is_duplicate = fy_node_mapping_key_is_duplicate(fyn_parent, fyn);
-       if (is_duplicate) {
-               FYD_NODE_ERROR(fyd, fyn, FYEM_DOC,
-                               "duplicate mapping key");
-               return NULL;
+       /* if we don't allow duplicate keys */
+       if (!(fyd->parse_cfg.flags & FYPCF_ALLOW_DUPLICATE_KEYS)) {
+
+               /* make sure we don't add an already existing key */
+               is_duplicate = fy_node_mapping_key_is_duplicate(fyn_parent, fyn);
+               if (is_duplicate) {
+                       FYD_NODE_ERROR(fyd, fyn, FYEM_DOC,
+                                       "duplicate mapping key");
+                       return NULL;
+               }
        }
 
        fynp = fy_node_pair_alloc(fyd);
@@ -7745,3 +6813,491 @@ fy_node_sequence_add_item(struct fy_node *fyn_parent, struct fy_node *fyn)
        fyn->attached = true;
        return 0;
 }
+
+void fy_document_iterator_setup(struct fy_document_iterator *fydi)
+{
+       memset(fydi, 0, sizeof(*fydi));
+       fydi->state = FYDIS_WAITING_STREAM_START;
+       fydi->fyd = NULL;
+       fydi->iterate_root = NULL;
+
+       /* suppress recycling if we must */
+       fydi->suppress_recycling_force = getenv("FY_VALGRIND") && !getenv("FY_VALGRIND_RECYCLING");
+       fydi->suppress_recycling = fydi->suppress_recycling_force;
+
+       fy_eventp_list_init(&fydi->recycled_eventp);
+       fy_token_list_init(&fydi->recycled_token);
+
+       if (!fydi->suppress_recycling) {
+               fydi->recycled_eventp_list = &fydi->recycled_eventp;
+               fydi->recycled_token_list = &fydi->recycled_token;
+       } else {
+               fydi->recycled_eventp_list = NULL;
+               fydi->recycled_token_list = NULL;
+       }
+
+       /* start with the stack pointing to the in place data */
+       fydi->stack_top = (unsigned int)-1;
+       fydi->stack_alloc = sizeof(fydi->in_place) / sizeof(fydi->in_place[0]);
+       fydi->stack = fydi->in_place;
+}
+
+void fy_document_iterator_cleanup(struct fy_document_iterator *fydi)
+{
+       struct fy_token *fyt;
+       struct fy_eventp *fyep;
+
+       /* free the stack if it's not the inplace one */
+       if (fydi->stack != fydi->in_place)
+               free(fydi->stack);
+       fydi->stack_top = (unsigned int)-1;
+       fydi->stack_alloc = sizeof(fydi->in_place) / sizeof(fydi->in_place[0]);
+       fydi->stack = fydi->in_place;
+
+       while ((fyt = fy_token_list_pop(&fydi->recycled_token)) != NULL)
+               fy_token_free(fyt);
+
+       while ((fyep = fy_eventp_list_pop(&fydi->recycled_eventp)) != NULL)
+               fy_eventp_free(fyep);
+
+       fydi->state = FYDIS_WAITING_STREAM_START;
+       fydi->fyd = NULL;
+       fydi->iterate_root = NULL;
+}
+
+struct fy_document_iterator *fy_document_iterator_create(void)
+{
+       struct fy_document_iterator *fydi;
+
+       fydi = malloc(sizeof(*fydi));
+       if (!fydi)
+               return NULL;
+       fy_document_iterator_setup(fydi);
+       return fydi;
+}
+
+void fy_document_iterator_destroy(struct fy_document_iterator *fydi)
+{
+       if (!fydi)
+               return;
+       fy_document_iterator_cleanup(fydi);
+       free(fydi);
+}
+
+static struct fy_event *
+fydi_event_create(struct fy_document_iterator *fydi, struct fy_node *fyn, bool start)
+{
+       struct fy_eventp *fyep;
+       struct fy_event *fye;
+       struct fy_anchor *fya;
+       struct fy_token *anchor = NULL;
+
+       fyep = fy_document_iterator_eventp_alloc(fydi);
+       if (!fyep) {
+               fydi->state = FYDIS_ERROR;
+               return NULL;
+       }
+       fye = &fyep->e;
+
+       if (start) {
+               fya = fy_node_get_anchor(fyn);
+               anchor = fya ? fya->anchor : NULL;
+       }
+
+       switch (fyn->type) {
+
+       case FYNT_SCALAR:
+               if (fyn->style != FYNS_ALIAS) {
+                       fye->type = FYET_SCALAR;
+                       fye->scalar.anchor = fy_token_ref(anchor);
+                       fye->scalar.tag = fy_token_ref(fyn->tag);
+                       fye->scalar.value = fy_token_ref(fyn->scalar);
+               } else {
+                       fye->type = FYET_ALIAS;
+                       fye->alias.anchor = fy_token_ref(fyn->scalar);
+               }
+               break;
+
+       case FYNT_SEQUENCE:
+               if (start) {
+                       fye->type = FYET_SEQUENCE_START;
+                       fye->sequence_start.anchor = fy_token_ref(anchor);
+                       fye->sequence_start.tag = fy_token_ref(fyn->tag);
+                       fye->sequence_start.sequence_start = fy_token_ref(fyn->sequence_start);
+               } else {
+                       fye->type = FYET_SEQUENCE_END;
+                       fye->sequence_end.sequence_end = fy_token_ref(fyn->sequence_end);
+               }
+               break;
+
+       case FYNT_MAPPING:
+               if (start) {
+                       fye->type = FYET_MAPPING_START;
+                       fye->mapping_start.anchor = fy_token_ref(anchor);
+                       fye->mapping_start.tag = fy_token_ref(fyn->tag);
+                       fye->mapping_start.mapping_start = fy_token_ref(fyn->mapping_start);
+               } else {
+                       fye->type = FYET_MAPPING_END;
+                       fye->mapping_end.mapping_end = fy_token_ref(fyn->mapping_end);
+               }
+               break;
+       }
+
+       return fye;
+}
+
+struct fy_event *
+fy_document_iterator_stream_start(struct fy_document_iterator *fydi)
+{
+       struct fy_event *fye;
+
+       if (!fydi || fydi->state == FYDIS_ERROR)
+               return NULL;
+
+       /* both none and stream start are the same for this */
+       if (fydi->state != FYDIS_WAITING_STREAM_START &&
+           fydi->state != FYDIS_WAITING_STREAM_END_OR_DOCUMENT_START)
+               goto err_out;
+
+       fye = fy_document_iterator_event_create(fydi, FYET_STREAM_START);
+       if (!fye)
+               goto err_out;
+
+       fydi->state = FYDIS_WAITING_DOCUMENT_START;
+       return fye;
+
+err_out:
+       fydi->state = FYDIS_ERROR;
+       return NULL;
+}
+
+struct fy_event *
+fy_document_iterator_stream_end(struct fy_document_iterator *fydi)
+{
+       struct fy_event *fye;
+
+       if (!fydi || fydi->state == FYDIS_ERROR)
+               return NULL;
+
+       if (fydi->state != FYDIS_WAITING_STREAM_END_OR_DOCUMENT_START &&
+           fydi->state != FYDIS_WAITING_DOCUMENT_START)
+               goto err_out;
+
+       fye = fy_document_iterator_event_create(fydi, FYET_STREAM_END);
+       if (!fye)
+               goto err_out;
+
+       fydi->state = FYDIS_WAITING_STREAM_START;
+       return fye;
+
+err_out:
+       fydi->state = FYDIS_ERROR;
+       return NULL;
+}
+
+struct fy_event *
+fy_document_iterator_document_start(struct fy_document_iterator *fydi, struct fy_document *fyd)
+{
+       struct fy_event *fye = NULL;
+       struct fy_eventp *fyep;
+
+       if (!fydi || fydi->state == FYDIS_ERROR)
+               return NULL;
+
+       if (!fyd)
+               goto err_out;
+
+       /* we can transition to document start only from document start or stream end */
+       if (fydi->state != FYDIS_WAITING_DOCUMENT_START &&
+           fydi->state != FYDIS_WAITING_STREAM_END_OR_DOCUMENT_START)
+               goto err_out;
+
+       fyep = fy_document_iterator_eventp_alloc(fydi);
+       if (!fyep)
+               goto err_out;
+       fye = &fyep->e;
+
+       fydi->fyd = fyd;
+
+       /* the iteration root is the document root */
+       fydi->iterate_root = fyd->root;
+
+       /* suppress recycling if we must */
+       fydi->suppress_recycling = (fyd->parse_cfg.flags & FYPCF_DISABLE_RECYCLING) ||
+                                  fydi->suppress_recycling_force;
+
+       if (!fydi->suppress_recycling) {
+               fydi->recycled_eventp_list = &fydi->recycled_eventp;
+               fydi->recycled_token_list = &fydi->recycled_token;
+       } else {
+               fydi->recycled_eventp_list = NULL;
+               fydi->recycled_token_list = NULL;
+       }
+
+       fye->type = FYET_DOCUMENT_START;
+       fye->document_start.document_start = NULL;
+       fye->document_start.document_state = fy_document_state_ref(fyd->fyds);
+       fye->document_start.implicit = fyd->fyds->start_implicit;
+
+       /* and go into body */
+       fydi->state = FYDIS_WAITING_BODY_START_OR_DOCUMENT_END;
+
+       return fye;
+
+err_out:
+       fy_document_iterator_event_free(fydi, fye);
+       fydi->state = FYDIS_ERROR;
+       return NULL;
+}
+
+struct fy_event *
+fy_document_iterator_document_end(struct fy_document_iterator *fydi)
+{
+       struct fy_event *fye;
+
+       if (!fydi || fydi->state == FYDIS_ERROR)
+               return NULL;
+
+       if (!fydi->fyd || !fydi->fyd->fyds ||
+           fydi->state != FYDIS_WAITING_DOCUMENT_END)
+               goto err_out;
+
+       fye = fy_document_iterator_event_create(fydi, FYET_DOCUMENT_END, (int)fydi->fyd->fyds->end_implicit);
+       if (!fye)
+               goto err_out;
+
+       fydi->fyd = NULL;
+       fydi->iterate_root = NULL;
+
+       fydi->state = FYDIS_WAITING_STREAM_END_OR_DOCUMENT_START;
+       return fye;
+
+err_out:
+       fydi->state = FYDIS_ERROR;
+       return NULL;
+}
+
+static bool
+fy_document_iterator_ensure_space(struct fy_document_iterator *fydi, unsigned int space)
+{
+       struct fy_document_iterator_body_state *new_stack;
+       size_t new_size, copy_size;
+       unsigned int new_stack_alloc;
+
+       /* empty stack should always have enough space */
+       if (fydi->stack_top == (unsigned int)-1) {
+               assert(fydi->stack_alloc >= space);
+               return true;
+       }
+
+       if (fydi->stack_top + space < fydi->stack_alloc)
+               return true;
+
+       /* make sure we have enough space */
+       new_stack_alloc = fydi->stack_alloc * 2;
+       while (fydi->stack_top + space >= new_stack_alloc)
+               new_stack_alloc *= 2;
+
+       new_size = new_stack_alloc * sizeof(*new_stack);
+
+       if (fydi->stack == fydi->in_place) {
+               new_stack = malloc(new_size);
+               if (!new_stack)
+                       return false;
+               copy_size = (fydi->stack_top + 1) * sizeof(*new_stack);
+               memcpy(new_stack, fydi->stack, copy_size);
+       } else {
+               new_stack = realloc(fydi->stack, new_size);
+               if (!new_stack)
+                       return false;
+       }
+       fydi->stack = new_stack;
+       fydi->stack_alloc = new_stack_alloc;
+       return true;
+}
+
+static bool
+fydi_push_collection(struct fy_document_iterator *fydi, struct fy_node *fyn)
+{
+       struct fy_document_iterator_body_state *s;
+
+       /* make sure there's enough space */
+       if (!fy_document_iterator_ensure_space(fydi, 1))
+               return false;
+
+       /* get the next */
+       fydi->stack_top++;
+       s = &fydi->stack[fydi->stack_top];
+       s->fyn = fyn;
+
+       switch (fyn->type) {
+       case FYNT_SEQUENCE:
+               s->fyni = fy_node_list_head(&fyn->sequence);
+               break;
+
+       case FYNT_MAPPING:
+               s->fynp = fy_node_pair_list_head(&fyn->mapping);
+               s->processed_key = false;
+               break;
+
+       default:
+               assert(0);
+               break;
+       }
+
+       return true;
+}
+
+static inline void
+fydi_pop_collection(struct fy_document_iterator *fydi)
+{
+       assert(fydi->stack_top != (unsigned int)-1);
+       fydi->stack_top--;
+}
+
+static inline struct fy_document_iterator_body_state *
+fydi_last_collection(struct fy_document_iterator *fydi)
+{
+       if (fydi->stack_top == (unsigned int)-1)
+               return NULL;
+       return &fydi->stack[fydi->stack_top];
+}
+
+bool
+fy_document_iterator_body_next_internal(struct fy_document_iterator *fydi,
+                                       struct fy_document_iterator_body_result *res)
+{
+       struct fy_document_iterator_body_state *s;
+       struct fy_node *fyn, *fyn_col;
+       bool end;
+
+       if (!fydi || !res || fydi->state == FYDIS_ERROR)
+               return false;
+
+       if (fydi->state != FYDIS_WAITING_BODY_START_OR_DOCUMENT_END &&
+           fydi->state != FYDIS_BODY)
+               goto err_out;
+
+       end = false;
+       s = fydi_last_collection(fydi);
+       if (!s) {
+
+               fyn = fydi->iterate_root;
+               /* empty root, or last */
+               if (!fyn || fydi->state == FYDIS_BODY) {
+                       fydi->state = FYDIS_WAITING_DOCUMENT_END;
+                       return false;
+               }
+
+               /* ok, in body proper */
+               fydi->state = FYDIS_BODY;
+
+       } else {
+
+               fyn_col = s->fyn;
+               assert(fyn_col);
+
+               fyn = NULL;
+               if (fyn_col->type == FYNT_SEQUENCE) {
+                       fyn = s->fyni;
+                       if (fyn)
+                               s->fyni = fy_node_next(&fyn_col->sequence, s->fyni);
+               } else {
+                       assert(fyn_col->type == FYNT_MAPPING);
+                       if (s->fynp) {
+                               if (!s->processed_key) {
+                                       fyn = s->fynp->key;
+                                       s->processed_key = true;
+                               } else {
+                                       fyn = s->fynp->value;
+                                       s->processed_key = false;
+
+                                       /* next in mapping after value */
+                                       s->fynp = fy_node_pair_next(&fyn_col->mapping, s->fynp);
+                               }
+                       }
+               }
+
+               /* if no next node in the collection, it's the end of the collection */
+               if (!fyn) {
+                       fyn = fyn_col;
+                       end = true;
+               }
+       }
+
+       assert(fyn);
+
+       /* only for collections */
+       if (fyn->type != FYNT_SCALAR) {
+               if (!end) {
+                       /* push the new sequence */
+                       if (!fydi_push_collection(fydi, fyn))
+                               goto err_out;
+               } else
+                       fydi_pop_collection(fydi);
+       }
+
+       res->fyn = fyn;
+       res->end = end;
+       return true;
+
+err_out:
+       fydi->state = FYDIS_ERROR;
+       return false;
+}
+
+struct fy_event *fy_document_iterator_body_next(struct fy_document_iterator *fydi)
+{
+       struct fy_document_iterator_body_result res;
+
+       if (!fydi)
+               return NULL;
+
+       if (!fy_document_iterator_body_next_internal(fydi, &res))
+               return NULL;
+
+       return fydi_event_create(fydi, res.fyn, !res.end);
+}
+
+void
+fy_document_iterator_node_start(struct fy_document_iterator *fydi, struct fy_node *fyn)
+{
+       /* do nothing on error */
+       if (!fydi || fydi->state == FYDIS_ERROR)
+               return;
+
+       /* and go into body */
+       fydi->state = FYDIS_WAITING_BODY_START_OR_DOCUMENT_END;
+       fydi->iterate_root = fyn;
+       fydi->fyd = NULL;
+}
+
+struct fy_node *fy_document_iterator_node_next(struct fy_document_iterator *fydi)
+{
+       struct fy_document_iterator_body_result res;
+
+       if (!fydi)
+               return NULL;
+
+       /* do not return ending nodes, are not interested in them */
+       do {
+               if (!fy_document_iterator_body_next_internal(fydi, &res))
+                       return NULL;
+
+       } while (res.end);
+
+       return res.fyn;
+}
+
+bool fy_document_iterator_get_error(struct fy_document_iterator *fydi)
+{
+       if (!fydi)
+               return true;
+
+       if (fydi->state != FYDIS_ERROR)
+               return false;
+
+       fy_document_iterator_cleanup(fydi);
+
+       return true;
+}
index 54b29b18cc0b771e9f08ba4bc25c73c193f66aa2..6c150246119dbb92f70a787e2236d9090defa8b3 100644 (file)
 #include "fy-docstate.h"
 #include "fy-accel.h"
 #include "fy-walk.h"
+#include "fy-path.h"
 
 struct fy_eventp;
 
+/* TODO vary according to platfom */
+static inline int fy_depth_limit(void)
+{
+       return FYPCF_GUARANTEED_MINIMUM_DEPTH_LIMIT;
+}
+
 FY_TYPE_FWD_DECL_LIST(document);
 
 struct fy_node;
@@ -129,11 +136,14 @@ void fy_node_mapping_perform_sort(struct fy_node *fyn_map,
                fy_node_mapping_sort_fn key_cmp, void *arg,
                struct fy_node_pair **fynpp, int count);
 
+void fy_node_mapping_fill_array(struct fy_node *fyn_map,
+               struct fy_node_pair **fynpp, int count);
+
 struct fy_node_pair **fy_node_mapping_sort_array(struct fy_node *fyn_map,
                fy_node_mapping_sort_fn key_cmp,
                void *arg, int *countp);
 
-void fy_node_mapping_sort_release_array(struct fy_node *fyn_map, struct fy_node_pair **fynpp);
+void fy_node_mapping_release_array(struct fy_node *fyn_map, struct fy_node_pair **fynpp);
 
 struct fy_node_walk_ctx {
        unsigned int max_depth;
@@ -142,6 +152,8 @@ struct fy_node_walk_ctx {
        struct fy_node *marked[0];
 };
 
+bool fy_node_is_empty(struct fy_node *fyn);
+
 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);
@@ -172,144 +184,75 @@ bool fy_document_can_be_accelerated(struct fy_document *fyd);
 /* TODO move to main include */
 struct fy_node *fy_node_collection_iterate(struct fy_node *fyn, void **prevp);
 
-enum fy_document_builder_state {
-       FYDBS_NODE,
-       FYDBS_MAP_KEY,
-       FYDBS_MAP_VAL,
-       FYDBS_SEQ,
-};
-
-struct fy_document_builder_ctx {
-       enum fy_document_builder_state s;
+/* indirect node */
+FY_TYPE_FWD_DECL_LIST(ptr_node);
+struct fy_ptr_node {
+       struct list_head node;
        struct fy_node *fyn;
-       struct fy_node_pair *fynp;      /* for mapping */
 };
+FY_TYPE_DECL_LIST(ptr_node);
 
-struct fy_document_builder {
-       struct fy_parse_cfg cfg;
-       bool single_mode;
-       struct fy_document *fyd;
-       bool in_stream;
-       bool doc_done;
-       unsigned int next;
-       unsigned int alloc;
-       unsigned int max_depth;
-       struct fy_document_builder_ctx *stack;
-};
-
-struct fy_document_builder *
-fy_document_builder_create(const struct fy_parse_cfg *cfg);
-
-void
-fy_document_builder_reset(struct fy_document_builder *fydb);
-
-void
-fy_document_builder_destroy(struct fy_document_builder *fydb);
-
-struct fy_document *
-fy_document_builder_get_document(struct fy_document_builder *fydb);
-
-bool
-fy_document_builder_is_in_stream(struct fy_document_builder *fydb);
-
-bool
-fy_document_builder_is_in_document(struct fy_document_builder *fydb);
-
-bool
-fy_document_builder_is_document_complete(struct fy_document_builder *fydb);
-
-struct fy_document *
-fy_document_builder_take_document(struct fy_document_builder *fydb);
-
-struct fy_document *
-fy_document_builder_peek_document(struct fy_document_builder *fydb);
-
-void
-fy_document_builder_set_in_stream(struct fy_document_builder *fydb);
-
-int
-fy_document_builder_set_in_document(struct fy_document_builder *fydb, struct fy_document_state *fyds, bool single);
-
-int
-fy_document_builder_process_event(struct fy_document_builder *fydb,
-               struct fy_parser *fyp, struct fy_eventp *fyep);
-
-struct fy_document *
-fy_document_builder_load_document(struct fy_document_builder *fydb,
-                                 struct fy_parser *fyp);
-
-struct fy_document *
-fy_parse_load_document_with_builder(struct fy_parser *fyp);
+struct fy_ptr_node *fy_ptr_node_create(struct fy_node *fyn);
+void fy_ptr_node_destroy(struct fy_ptr_node *fypn);
+void fy_ptr_node_list_free_all(struct fy_ptr_node_list *fypnl);
+bool fy_ptr_node_list_contains(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
+int fy_node_linearize_recursive(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
+int fy_node_linearize(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
+void fy_node_iterator_check(struct fy_node *fyn);
 
-enum fy_node_iterator_flags {
-       FYNIF_DEPTH_FIRST       = FY_BIT(0),    /* depth first iterator (only one supported for now) */
-       FYNIF_FOLLOW_KEYS       = FY_BIT(1),    /* follow any keys encountered */
-       FYNIF_FOLLOW_LINKS      = FY_BIT(2),    /* follow any links/references encountered */
-       FYNIF_ERASE_LINKS       = FY_BIT(3),    /* do not output any links encountered */
-};
 
-enum fy_node_iterator_result {
-       FYNIR_OK,               /* OK */
-       FYNIR_ARGS,             /* invalid arguments */
-       FYNIR_NOMEM,            /* out of memory */
-       FYNIR_LOOP,             /* loop detected */
-       FYNIR_BAD_ALIAS,        /* unresolvable alias */
+enum fy_document_iterator_state {
+       FYDIS_WAITING_STREAM_START,
+       FYDIS_WAITING_DOCUMENT_START,
+       FYDIS_WAITING_BODY_START_OR_DOCUMENT_END,
+       FYDIS_BODY,
+       FYDIS_WAITING_DOCUMENT_END,
+       FYDIS_WAITING_STREAM_END_OR_DOCUMENT_START,
+       FYDIS_ERROR,
 };
 
-struct fy_node_iterator_state {
-       struct fy_node *fyn;
+struct fy_document_iterator_body_state {
+       struct fy_node *fyn;    /* the collection node */
+       bool processed_key : 1; /* for mapping only */
        union {
-               struct fy_node_pair *fynp;      /* for map only */
-               unsigned int idx;               /* for sequence */
+               struct fy_node *fyni;           /* for sequence */
+               struct fy_node_pair *fynp;      /* for mapping */
        };
 };
 
-struct fy_node_iterator {
-       enum fy_node_iterator_flags flags;
-       enum fy_node_iterator_result result;
-       unsigned int count;
-       unsigned int alloc;
-       struct fy_node_iterator_state *stack;
-       struct fy_node_iterator_state in_place[FYPCF_GUARANTEED_MINIMUM_DEPTH_LIMIT];
+struct fy_document_iterator {
+       enum fy_document_iterator_state state;
+       struct fy_document *fyd;
+       struct fy_node *iterate_root;
+       bool suppress_recycling_force : 1;
+       bool suppress_recycling : 1;
+
+       struct fy_eventp_list recycled_eventp;
+       struct fy_token_list recycled_token;
+
+       struct fy_eventp_list *recycled_eventp_list;    /* NULL when suppressing */
+       struct fy_token_list *recycled_token_list;      /* NULL when suppressing */
+
+       unsigned int stack_top;
+       unsigned int stack_alloc;
+       struct fy_document_iterator_body_state *stack;
+       struct fy_document_iterator_body_state in_place[FYPCF_GUARANTEED_MINIMUM_DEPTH_LIMIT];
 };
 
-void fy_node_iterator_setup(struct fy_node_iterator *fyi, enum fy_node_iterator_flags flags);
-void fy_node_iterator_cleanup(struct fy_node_iterator *fyi);
-struct fy_node_iterator *fy_node_iterator_create(enum fy_node_iterator_flags flags);
-void fy_node_iterator_destroy(struct fy_node_iterator *fyi);
-void fy_node_iterator_start(struct fy_node_iterator *fyi, struct fy_node *fyn);
-enum fy_node_iterator_result fy_node_iterator_end(struct fy_node_iterator *fyi);
-struct fy_node *fy_node_iterator_next(struct fy_node_iterator *fyi, struct fy_node *fyn);
-
-#define fy_node_get_path_a(_fyn) \
-       ({ \
-               char *__path_a, *__path; \
-               __path = fy_node_get_path((_fyn)); \
-               if (__path) { \
-                       __path_a = alloca(strlen(__path) + 1); \
-                       strcpy(__path_a, __path); \
-                       free(__path); \
-               } else { \
-                       __path_a = alloca(1); \
-                       __path_a[0] = '\0'; \
-               } \
-               __path_a; \
-       })
+void fy_document_iterator_setup(struct fy_document_iterator *fydi);
+void fy_document_iterator_cleanup(struct fy_document_iterator *fydi);
+struct fy_document_iterator *fy_document_iterator_create(void);
+void fy_document_iterator_destroy(struct fy_document_iterator *fydi);
+void fy_document_iterator_start(struct fy_document_iterator *fydi, struct fy_document *fyd);
+void fy_document_iterator_end(struct fy_document_iterator *fydi);
 
-/* indirect node */
-FY_TYPE_FWD_DECL_LIST(ptr_node);
-struct fy_ptr_node {
-       struct list_head node;
+struct fy_document_iterator_body_result {
        struct fy_node *fyn;
+       bool end;
 };
-FY_TYPE_DECL_LIST(ptr_node);
 
-struct fy_ptr_node *fy_ptr_node_create(struct fy_node *fyn);
-void fy_ptr_node_destroy(struct fy_ptr_node *fypn);
-void fy_ptr_node_list_free_all(struct fy_ptr_node_list *fypnl);
-bool fy_ptr_node_list_contains(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
-int fy_node_linearize_recursive(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
-int fy_node_linearize(struct fy_ptr_node_list *fypnl, struct fy_node *fyn);
-void fy_node_iterator_check(struct fy_node *fyn);
+bool
+fy_document_iterator_body_next_internal(struct fy_document_iterator *fydi,
+                                       struct fy_document_iterator_body_result *res);
 
 #endif
diff --git a/src/lib/fy-docbuilder.c b/src/lib/fy-docbuilder.c
new file mode 100644 (file)
index 0000000..94f6606
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * fy-docbuilder.c - YAML document builder methods
+ *
+ * Copyright (c) 2022 Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <libfyaml.h>
+
+#include "fy-utils.h"
+
+#include "fy-docbuilder.h"
+
+#include "fy-parse.h"
+#include "fy-doc.h"
+
+const char *fy_document_builder_state_txt[] = {
+       [FYDBS_NODE]    = "node",
+       [FYDBS_MAP_KEY] = "map-key",
+       [FYDBS_MAP_VAL] = "map-val",
+       [FYDBS_SEQ]     = "seq",
+};
+
+void
+fy_document_builder_reset(struct fy_document_builder *fydb)
+{
+       struct fy_document_builder_ctx *c;
+       unsigned int i;
+
+       if (!fydb)
+               return;
+
+       for (i = 0, c = fydb->stack; i < fydb->next; i++, c++) {
+               fy_node_free(c->fyn);
+               c->fyn = NULL;
+               fy_node_pair_free(c->fynp);
+               c->fynp = NULL;
+       }
+       fydb->next = 0;
+
+       if (fydb->fyd) {
+               fy_document_destroy(fydb->fyd);
+               fydb->fyd = NULL;
+       }
+       fydb->in_stream = false;
+       fydb->doc_done = false;
+}
+
+static const struct fy_document_builder_cfg docbuilder_default_cfg = {
+       .parse_cfg = {
+               .flags = FYPCF_DEFAULT_DOC,
+       }
+};
+
+struct fy_document_builder *
+fy_document_builder_create(const struct fy_document_builder_cfg *cfg)
+{
+       struct fy_document_builder *fydb = NULL;
+
+       if (!cfg)
+               cfg = &docbuilder_default_cfg;
+
+       fydb = malloc(sizeof(*fydb));
+       if (!fydb)
+               goto err_out;
+
+       memset(fydb, 0, sizeof(*fydb));
+       fydb->cfg = *cfg;
+       fydb->next = 0;
+       fydb->in_stream = false;
+       fydb->doc_done = false;
+       fydb->alloc = fy_depth_limit(); /* always start with this */
+       fydb->max_depth = (cfg->parse_cfg.flags & FYPCF_DISABLE_DEPTH_LIMIT) ? 0 : fy_depth_limit();
+
+       fydb->stack = malloc(fydb->alloc * sizeof(*fydb->stack));
+       if (!fydb->stack)
+               goto err_out;
+
+       return fydb;
+
+err_out:
+       if (fydb) {
+               if (fydb->stack)
+                       free(fydb->stack);
+               free(fydb);
+       }
+
+       return NULL;
+}
+
+void
+fy_document_builder_destroy(struct fy_document_builder *fydb)
+{
+       if (!fydb)
+               return;
+
+       fy_document_builder_reset(fydb);
+
+       fy_diag_unref(fydb->cfg.diag);
+       if (fydb->stack)
+               free(fydb->stack);
+       free(fydb);
+}
+
+struct fy_document *
+fy_document_builder_get_document(struct fy_document_builder *fydb)
+{
+       return fydb ? fydb->fyd : NULL;
+}
+
+bool
+fy_document_builder_is_in_stream(struct fy_document_builder *fydb)
+{
+       return fydb && fydb->in_stream;
+}
+
+bool
+fy_document_builder_is_in_document(struct fy_document_builder *fydb)
+{
+       return fydb && fydb->fyd != NULL && !fydb->doc_done;
+}
+
+bool
+fy_document_builder_is_document_complete(struct fy_document_builder *fydb)
+{
+       return fydb && fydb->fyd != NULL && fydb->doc_done;
+}
+
+struct fy_document *
+fy_document_builder_take_document(struct fy_document_builder *fydb)
+{
+       struct fy_document *fyd;
+
+       if (!fy_document_builder_is_document_complete(fydb))
+               return NULL;
+       fyd = fydb->fyd;
+       fydb->fyd = NULL;
+       fydb->doc_done = false;
+       return fyd;
+}
+
+struct fy_document *
+fy_document_builder_peek_document(struct fy_document_builder *fydb)
+{
+       struct fy_document *fyd;
+       struct fy_document_builder_ctx *c;
+
+       if (!fydb)
+               return NULL;
+
+       /* just peek; may be incomplete */
+       fyd = fydb->fyd;
+
+       assert(fydb->next > 0);
+       c = &fydb->stack[0];
+
+       /* wire the root */
+       if (!fyd->root)
+               fyd->root = c->fyn;
+
+       return fyd;
+}
+
+
+void
+fy_document_builder_set_in_stream(struct fy_document_builder *fydb)
+{
+       if (!fydb)
+               return;
+       /* reset */
+       fy_document_builder_reset(fydb);
+
+       fydb->in_stream = true;
+}
+
+int
+fy_document_builder_set_in_document(struct fy_document_builder *fydb, struct fy_document_state *fyds, bool single)
+{
+       struct fy_document_builder_ctx *c;
+       int rc;
+
+       if (!fydb)
+               return -1;
+
+       /* reset */
+       fy_document_builder_reset(fydb);
+
+       fydb->in_stream = true;
+
+       fydb->fyd = fy_document_create(&fydb->cfg.parse_cfg);
+       if (!fydb->fyd)
+               return -1;
+
+       if (fyds) {
+               rc = fy_document_set_document_state(fydb->fyd, fyds);
+               if (rc)
+                       return rc;
+       }
+
+       fydb->doc_done = false;
+       fydb->single_mode = single;
+
+       /* be paranoid */
+       assert(fydb->next < fydb->alloc);
+
+       c = &fydb->stack[++fydb->next - 1];
+       memset(c, 0, sizeof(*c));
+       c->s = FYDBS_NODE;
+
+       return 0;
+}
+
+int
+fy_document_builder_process_event(struct fy_document_builder *fydb, struct fy_eventp *fyep)
+{
+       struct fy_event *fye;
+       enum fy_event_type etype;
+       struct fy_document *fyd;
+       struct fy_document_builder_ctx *c, *cp;
+       struct fy_node *fyn, *fyn_parent;
+       struct fy_node_pair *fynp;
+       struct fy_document_builder_ctx *newc;
+       struct fy_token *fyt;
+       int rc;
+
+       fye = fyep ? &fyep->e : NULL;
+       etype = fye ? fye->type : FYET_NONE;
+       fyt = fye ? fy_event_get_token(fye) : NULL;
+
+       /* not in document */
+       if (!fydb->next) {
+               switch (etype) {
+               case FYET_STREAM_START:
+                       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                                       !fydb->in_stream, err_out,
+                                       "STREAM_START while in stream error");
+                       fydb->in_stream = true;
+                       break;
+
+               case FYET_STREAM_END:
+                       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                                       fydb->in_stream, err_out,
+                                       "STREAM_END while not in stream error");
+                       fydb->in_stream = false;
+                       return 1;
+
+               case FYET_DOCUMENT_START:
+                       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                                       fydb->in_stream, err_out,
+                                       "DOCUMENT_START while not in stream error");
+
+                       /* no-one cares, destroy the document */
+                       if (!fydb->fyd)
+                               fy_document_destroy(fydb->fyd);
+
+                       fydb->fyd = fy_document_create(&fydb->cfg.parse_cfg);
+                       fydb_error_check(fydb, fydb->fyd, err_out,
+                                       "fy_document_create() failed");
+
+                       rc = fy_document_set_document_state(fydb->fyd, fyep->e.document_start.document_state);
+                       fydb_error_check(fydb, !rc, err_out,
+                                       "fy_document_set_document_state() failed");
+
+                       fydb->doc_done = false;
+                       goto push;
+
+               case FYET_DOCUMENT_END:
+                       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                                       fydb->in_stream, err_out,
+                                       "DOCUMENT_END while not in stream error");
+
+                       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                                       fydb->fyd, err_out,
+                                       "DOCUMENT_END without a document");
+
+                       fydb->doc_done = true;
+                       break;
+
+               default:
+                       /* unexpected event */
+                       FYDB_TOKEN_ERROR(fydb, fyt, FYEM_DOC,
+                                       "Unexpected event %s in non-build mode\n",
+                                               fy_event_type_txt[etype]);
+                       goto err_out;
+               }
+
+               return 0;
+       }
+
+       fyd = fydb->fyd;
+
+       c = &fydb->stack[fydb->next - 1];
+       fyn = NULL;
+
+       /* verify that we have a document */
+       assert(fydb->fyd);
+       /* the top state must always be NODE for processing the event */
+       assert(c->s == FYDBS_NODE);
+
+       switch (etype) {
+       case FYET_SCALAR:
+       case FYET_ALIAS:
+               fyn = fy_node_alloc(fyd, FYNT_SCALAR);
+               fydb_error_check(fydb, fyn, err_out,
+                               "fy_node_alloc() SCALAR failed");
+
+               if (etype == FYET_SCALAR) {
+                       if (fye->scalar.value)
+                               fyn->style = fy_node_style_from_scalar_style(fye->scalar.value->scalar.style);
+                       else
+                               fyn->style = FYNS_PLAIN;
+                       fyn->tag = fy_token_ref(fye->scalar.tag);
+                       if (fye->scalar.anchor) {
+                               rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->scalar.anchor));
+                               fydb_error_check(fydb, !rc, err_out,
+                                               "fy_document_register_anchor() failed");
+                       }
+                       fyn->scalar = fy_token_ref(fye->scalar.value);
+               } else {
+                       fyn->style = FYNS_ALIAS;
+                       fyn->scalar = fy_token_ref(fye->alias.anchor);
+               }
+               goto complete;
+
+       case FYET_MAPPING_START:
+               c->s = FYDBS_MAP_KEY;
+
+               fyn = fy_node_alloc(fyd, FYNT_MAPPING);
+               fydb_error_check(fydb, fyn, err_out,
+                               "fy_node_alloc() MAPPING failed");
+
+               c->fyn = fyn;
+               fyn->style = fye->mapping_start.mapping_start->type == FYTT_FLOW_MAPPING_START ? FYNS_FLOW : FYNS_BLOCK;
+               fyn->tag = fy_token_ref(fye->mapping_start.tag);
+               if (fye->mapping_start.anchor) {
+                       rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->mapping_start.anchor));
+                       fydb_error_check(fydb, !rc, err_out,
+                                       "fy_document_register_anchor() failed");
+               }
+               fyn->mapping_start = fy_token_ref(fye->mapping_start.mapping_start);
+               break;
+
+       case FYET_MAPPING_END:
+
+               FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC, fydb->next > 1, err_out,
+                               "Unexpected MAPPING_END (unexpected end of mapping)");
+
+               cp = &fydb->stack[fydb->next - 2];
+
+               FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC, cp->s == FYDBS_MAP_KEY, err_out,
+                               "Unexpected MAPPING_END (not in mapping)");
+
+               fyn = cp->fyn;
+               fyn->mapping_end = fy_token_ref(fye->mapping_end.mapping_end);
+               fydb->next--;
+               goto complete;
+
+       case FYET_SEQUENCE_START:
+               c->s = FYDBS_SEQ;
+               fyn = fy_node_alloc(fyd, FYNT_SEQUENCE);
+               fydb_error_check(fydb, fyn, err_out,
+                               "fy_node_alloc() SEQUENCE failed");
+
+               c->fyn = fyn;
+               fyn->style = fye->sequence_start.sequence_start->type == FYTT_FLOW_SEQUENCE_START ? FYNS_FLOW : FYNS_BLOCK;
+               fyn->tag = fy_token_ref(fye->sequence_start.tag);
+               if (fye->sequence_start.anchor) {
+                       rc = fy_document_register_anchor(fyd, fyn, fy_token_ref(fye->sequence_start.anchor));
+                       fydb_error_check(fydb, !rc, err_out,
+                                       "fy_document_register_anchor() failed");
+               }
+               fyn->sequence_start = fy_token_ref(fye->sequence_start.sequence_start);
+               break;
+
+       case FYET_SEQUENCE_END:
+
+               FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC, fydb->next > 1, err_out,
+                               "Unexpected SEQUENCE_END (unexpected end of sequence)");
+
+               cp = &fydb->stack[fydb->next - 2];
+
+               FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC, cp->s == FYDBS_SEQ, err_out,
+                               "Unexpected MAPPING_SEQUENCE (not in sequence)");
+
+               fyn = cp->fyn;
+               fyn->sequence_end = fy_token_ref(fye->sequence_end.sequence_end);
+               fydb->next--;
+               goto complete;
+
+       default:
+               /* unexpected event */
+               FYDB_TOKEN_ERROR(fydb, fyt, FYEM_DOC,
+                               "Unexpected event %s in build mode\n",
+                                       fy_event_type_txt[etype]);
+               goto err_out;
+       }
+
+push:
+       FYDB_TOKEN_ERROR_CHECK(fydb, fyt, FYEM_DOC,
+                       !fydb->max_depth || fydb->next < fydb->max_depth, err_out,
+                       "Max depth (%d) exceeded\n", fydb->next);
+
+       /* grow the stack? */
+       if (fydb->next >= fydb->alloc) {
+               newc = realloc(fydb->stack, fydb->alloc * 2 * sizeof(*fydb->stack));
+               fydb_error_check(fydb, newc, err_out,
+                               "Unable to grow the context stack");
+               fydb->alloc *= 2;
+               fydb->stack = newc;
+       }
+       assert(fydb->next < fydb->alloc);
+
+       c = &fydb->stack[++fydb->next - 1];
+       memset(c, 0, sizeof(*c));
+       c->s = FYDBS_NODE;
+       return 0;
+
+err_out:
+       return -1;
+
+complete:
+       assert(fydb->next > 0);
+       c = &fydb->stack[fydb->next - 1];
+       c->fyn = fyn;
+       assert(fydb->next > 0);
+       fydb->next--;
+
+       /* root */
+       if (fydb->next == 0) {
+               fyd->root = fyn;
+               /* if we're in single mode, don't wait for doc end */
+               if (fydb->single_mode)
+                       fydb->doc_done = true;
+               return 1;
+       }
+
+       c = &fydb->stack[fydb->next - 1];
+
+       fyn_parent = c->fyn;
+
+       switch (c->s) {
+
+       case FYDBS_MAP_KEY:
+               fynp = fy_node_pair_alloc(fyd);
+               assert(fynp);
+               fynp->key = fyn;
+               c->fynp = fynp;
+
+               /* if we don't allow duplicate keys */
+               if (!(fyd->parse_cfg.flags & FYPCF_ALLOW_DUPLICATE_KEYS)) {
+
+                       /* make sure we don't add an already existing key */
+                       if (fy_node_mapping_key_is_duplicate(fyn_parent, fyn)) {
+                               FYDB_NODE_ERROR(fydb, fyn, FYEM_DOC, "duplicate key");
+                               goto err_out;
+                       }
+               }
+
+               c->s = FYDBS_MAP_VAL;
+               goto push;
+
+       case FYDBS_MAP_VAL:
+               fynp = c->fynp;
+               assert(fynp);
+               fynp->value = fyn;
+
+               /* set the parent of the node pair and value */
+               fynp->parent = fyn_parent;
+               if (fynp->key) {
+                       fynp->key->parent = fyn_parent;
+                       fynp->key->key_root = true;
+               }
+               if (fynp->value)
+                       fynp->value->parent = fyn_parent;
+
+               fy_node_pair_list_add_tail(&c->fyn->mapping, fynp);
+               if (fyn->xl) {
+                       rc = fy_accel_insert(fyn->xl, fynp->key, fynp);
+                       assert(!rc);
+               }
+               if (fynp->key)
+                       fynp->key->attached = true;
+               if (fynp->value)
+                       fynp->value->attached = true;
+
+               c->fynp = NULL;
+               c->s = FYDBS_MAP_KEY;
+               goto push;
+
+       case FYDBS_SEQ:
+               /* append sequence */
+               fyn->parent = fyn_parent;
+               fy_node_list_add_tail(&c->fyn->sequence, fyn);
+               fyn->attached = true;
+               goto push;
+
+       case FYDBS_NODE:
+               /* complete is a scalar */
+               fyn->parent = fyn_parent;
+               return 0;
+       }
+
+       return 0;
+}
+
+struct fy_document *
+fy_document_builder_load_document(struct fy_document_builder *fydb,
+                                 struct fy_parser *fyp)
+{
+       struct fy_eventp *fyep = NULL;
+       int rc;
+
+       if (fyp->state == FYPS_END)
+               return NULL;
+
+       while (!fy_document_builder_is_document_complete(fydb) &&
+               (fyep = fy_parse_private(fyp)) != NULL) {
+               rc = fy_document_builder_process_event(fydb, fyep);
+               fy_parse_eventp_recycle(fyp, fyep);
+               if (rc < 0) {
+                       fyp->stream_error = true;
+                       return NULL;
+               }
+       }
+
+       /* get ownership of the document */
+       return fy_document_builder_take_document(fydb);
+}
diff --git a/src/lib/fy-docbuilder.h b/src/lib/fy-docbuilder.h
new file mode 100644 (file)
index 0000000..aa506d6
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * fy-docbuilder.h - YAML document builder internal header file
+ *
+ * Copyright (c) 2022 Pantelis Antoniou <pantelis.antoniou@konsulko.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+#ifndef FY_DOCBUILDER_H
+#define FY_DOCBUILDER_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include <libfyaml.h>
+
+#include "fy-doc.h"
+
+enum fy_document_builder_state {
+       FYDBS_NODE,
+       FYDBS_MAP_KEY,
+       FYDBS_MAP_VAL,
+       FYDBS_SEQ,
+};
+
+struct fy_document_builder_ctx {
+       enum fy_document_builder_state s;
+       struct fy_node *fyn;
+       struct fy_node_pair *fynp;      /* for mapping */
+};
+
+struct fy_document_builder_cfg {
+       struct fy_parse_cfg parse_cfg;
+       void *userdata;
+       struct fy_diag *diag;
+};
+
+struct fy_document_builder {
+       struct fy_document_builder_cfg cfg;
+       struct fy_document *fyd;
+       bool single_mode;
+       bool in_stream;
+       bool doc_done;
+       unsigned int next;
+       unsigned int alloc;
+       unsigned int max_depth;
+       struct fy_document_builder_ctx *stack;
+};
+
+struct fy_document_builder *
+fy_document_builder_create(const struct fy_document_builder_cfg *cfg);
+
+void
+fy_document_builder_reset(struct fy_document_builder *fydb);
+
+void
+fy_document_builder_destroy(struct fy_document_builder *fydb);
+
+struct fy_document *
+fy_document_builder_get_document(struct fy_document_builder *fydb);
+
+bool
+fy_document_builder_is_in_stream(struct fy_document_builder *fydb);
+
+bool
+fy_document_builder_is_in_document(struct fy_document_builder *fydb);
+
+bool
+fy_document_builder_is_document_complete(struct fy_document_builder *fydb);
+
+struct fy_document *
+fy_document_builder_take_document(struct fy_document_builder *fydb);
+
+struct fy_document *
+fy_document_builder_peek_document(struct fy_document_builder *fydb);
+
+void
+fy_document_builder_set_in_stream(struct fy_document_builder *fydb);
+
+int
+fy_document_builder_set_in_document(struct fy_document_builder *fydb, struct fy_document_state *fyds, bool single);
+
+int
+fy_document_builder_process_event(struct fy_document_builder *fydb, struct fy_eventp *fyep);
+
+struct fy_document *
+fy_document_builder_load_document(struct fy_document_builder *fydb,
+                                 struct fy_parser *fyp);
+
+struct fy_document *
+fy_parse_load_document_with_builder(struct fy_parser *fyp);
+
+#endif
index 554c6f0f9ccbc2e450d63531302835202e8edb53..e7876e4ea6c7fabd92485907161e7b6f78028a74 100644 (file)
@@ -151,6 +151,7 @@ struct fy_document_state *fy_document_state_default(
        fyds->tags_explicit = false;
        fyds->start_implicit = true;
        fyds->end_implicit = true;
+       fyds->json_mode = false;
 
        memset(&fyds->start_mark, 0, sizeof(fyds->start_mark));
        memset(&fyds->end_mark, 0, sizeof(fyds->end_mark));
@@ -185,6 +186,7 @@ struct fy_document_state *fy_document_state_copy(struct fy_document_state *fyds)
        fyds_new->tags_explicit = fyds->tags_explicit;
        fyds_new->start_implicit = fyds->start_implicit;
        fyds_new->end_implicit = fyds->end_implicit;
+       fyds_new->json_mode = fyds->json_mode;
 
        fyds_new->start_mark = fyds->start_mark;
        fyds_new->end_mark = fyds->end_mark;
@@ -214,6 +216,8 @@ struct fy_document_state *fy_document_state_copy(struct fy_document_state *fyds)
                fyt_td->tag_directive.uri_length = fyt->tag_directive.uri_length;
                fyt_td->tag_directive.is_default = fyt->tag_directive.is_default;
                fyt_td->handle = fyt->handle;
+               fyt_td->tag_directive.prefix0 = NULL;
+               fyt_td->tag_directive.handle0 = NULL;
 
                /* take reference */
                fy_input_ref(fyt_td->handle.fyi);
@@ -306,6 +310,7 @@ int fy_document_state_merge(struct fy_document_state *fyds,
        /* merge other document state */
        fyds->version_explicit |= fydsc->version_explicit;
        fyds->tags_explicit |= fydsc->tags_explicit;
+       /* NOTE: json mode is not carried over */
 
        if (fyds->version.major < fydsc->version.major ||
            (fyds->version.major == fydsc->version.major &&
@@ -355,6 +360,11 @@ bool fy_document_state_end_implicit(struct fy_document_state *fyds)
        return fyds ? fyds->end_implicit : true;
 }
 
+bool fy_document_state_json_mode(struct fy_document_state *fyds)
+{
+       return fyds ? fyds->json_mode : true;
+}
+
 const struct fy_tag *
 fy_document_state_tag_directive_iterate(struct fy_document_state *fyds, void **iterp)
 {
index 80cd43d933d4ef3c333c0821c9290ca79cae6ad6..380c5f0d8ceb118946c824a52e7d76ba0f27e464 100644 (file)
@@ -33,6 +33,7 @@ struct fy_document_state {
        bool tags_explicit : 1;
        bool start_implicit : 1;
        bool end_implicit : 1;
+       bool json_mode : 1;
        struct fy_mark start_mark;
        struct fy_mark end_mark;
        struct fy_token *fyt_vd;                /* version directive */
index c66b451cf3d32a99574a076db64e398722c4493b..36d8d8ef78af986b942758ce41a1e8687ec86a17 100644 (file)
@@ -16,6 +16,7 @@
 #include <limits.h>
 #include <unistd.h>
 #include <ctype.h>
+#include <errno.h>
 
 #include <libfyaml.h>
 
@@ -29,8 +30,12 @@ void fy_emit_printf(struct fy_emitter *emit, enum fy_emitter_write_type type, co
 
 static inline bool fy_emit_is_json_mode(const struct fy_emitter *emit)
 {
-       enum fy_emitter_cfg_flags flags = emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK);
+       enum fy_emitter_cfg_flags flags;
+
+       if (emit->force_json)
+               return true;
 
+       flags = emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK);
        return flags == FYECF_MODE_JSON || flags == FYECF_MODE_JSON_TP || flags == FYECF_MODE_JSON_ONELINE;
 }
 
@@ -45,7 +50,7 @@ static inline bool fy_emit_is_block_mode(const struct fy_emitter *emit)
 {
        enum fy_emitter_cfg_flags flags = emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK);
 
-       return flags == FYECF_MODE_BLOCK || flags == FYECF_MODE_DEJSON;
+       return flags == FYECF_MODE_BLOCK || flags == FYECF_MODE_DEJSON || flags == FYECF_MODE_PRETTY;
 }
 
 static inline bool fy_emit_is_oneline(const struct fy_emitter *emit)
@@ -55,13 +60,20 @@ static inline bool fy_emit_is_oneline(const struct fy_emitter *emit)
        return flags == FYECF_MODE_FLOW_ONELINE || flags == FYECF_MODE_JSON_ONELINE;
 }
 
-static inline bool fy_emit_is_pretty_mode(const struct fy_emitter *emit)
+static inline bool fy_emit_is_dejson_mode(const struct fy_emitter *emit)
 {
        enum fy_emitter_cfg_flags flags = emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK);
 
        return flags == FYECF_MODE_DEJSON;
 }
 
+static inline bool fy_emit_is_pretty_mode(const struct fy_emitter *emit)
+{
+       enum fy_emitter_cfg_flags flags = emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK);
+
+       return flags == FYECF_MODE_PRETTY;
+}
+
 static inline int fy_emit_indent(struct fy_emitter *emit)
 {
        int indent;
@@ -141,7 +153,7 @@ static int fy_emit_node_check(struct fy_emitter *emit, struct fy_node *fyn)
        if (!fyn)
                return 0;
 
-       if (fy_emit_is_json_mode(emit)) {
+       if (fy_emit_is_json_mode(emit) && !emit->source_json) {
                ret = fy_emit_node_check_json(emit, fyn);
                if (ret)
                        return ret;
@@ -450,6 +462,34 @@ struct fy_atom *fy_emit_token_comment_handle(struct fy_emitter *emit, struct fy_
        return handle && fy_atom_is_set(handle) ? handle : NULL;
 }
 
+void fy_emit_document_start_indicator(struct fy_emitter *emit)
+{
+       /* do not emit twice */
+       if (emit->flags & FYEF_HAD_DOCUMENT_START)
+               return;
+
+       /* do not try to emit if it's json mode */
+       if (fy_emit_is_json_mode(emit))
+               goto no_doc_emit;
+
+       /* output linebreak anyway */
+       if (emit->column)
+               fy_emit_putc(emit, fyewt_linebreak, '\n');
+
+       /* stripping doc indicators, do not emit */
+       if (emit->cfg.flags & FYECF_STRIP_DOC)
+               goto no_doc_emit;
+
+       /* ok, emit document start indicator */
+       fy_emit_puts(emit, fyewt_document_indicator, "---");
+       emit->flags &= ~FYEF_WHITESPACE;
+       emit->flags |= FYEF_HAD_DOCUMENT_START;
+       return;
+
+no_doc_emit:
+       emit->flags &= ~FYEF_HAD_DOCUMENT_START;
+}
+
 struct fy_token *fy_node_value_token(struct fy_node *fyn)
 {
        struct fy_token *fyt;
@@ -617,6 +657,10 @@ void fy_emit_node_internal(struct fy_emitter *emit, struct fy_node *fyn, int fla
 
        switch (type) {
        case FYNT_SCALAR:
+               /* if we're pretty and root at column 0 (meaning it's a single scalar document) output --- */
+               if ((flags & DDNF_ROOT) && fy_emit_is_pretty_mode(emit) && !emit->column &&
+                               !fy_emit_is_flow_mode(emit) && !(flags & DDNF_FLOW))
+                       fy_emit_document_start_indicator(emit);
                fy_emit_scalar(emit, fyn, flags, indent, is_key);
                break;
        case FYNT_SEQUENCE:
@@ -1216,10 +1260,8 @@ fy_emit_token_scalar_style(struct fy_emitter *emit, struct fy_token *fyt,
        if (json && (style == FYNS_LITERAL || style == FYNS_FOLDED))
                return FYNS_DOUBLE_QUOTED;
 
-       is_json_plain = false;
-
        /* is this a plain json atom? */
-       is_json_plain = (json || fy_emit_is_pretty_mode(emit)) &&
+       is_json_plain = (json || emit->source_json || fy_emit_is_dejson_mode(emit)) &&
                        (!atom || atom->size0 ||
                        !fy_atom_strcmp(atom, "false") ||
                        !fy_atom_strcmp(atom, "true") ||
@@ -1237,10 +1279,7 @@ fy_emit_token_scalar_style(struct fy_emitter *emit, struct fy_token *fyt,
        }
 
        /* JSON NULL, but with plain style */
-       if (json && (!atom || atom->size0) && style == FYNS_PLAIN)
-               return FYNS_PLAIN;
-
-       if (json && style == FYNS_PLAIN && is_json_plain)
+       if (json && (style == FYNS_PLAIN || style == FYNS_ANY) && (!atom || (is_json_plain && !atom->size0)))
                return FYNS_PLAIN;
 
        if (json)
@@ -1269,11 +1308,29 @@ fy_emit_token_scalar_style(struct fy_emitter *emit, struct fy_token *fyt,
                style = !(aflags & FYTTAF_EMPTY) ? FYNS_PLAIN : FYNS_DOUBLE_QUOTED;
        }
 
+       /* try to pretify */
        if (!flow && fy_emit_is_pretty_mode(emit) &&
                (style == FYNS_ANY || style == FYNS_DOUBLE_QUOTED || style == FYNS_SINGLE_QUOTED)) {
 
-               if ((aflags & FYTTAF_CAN_BE_PLAIN) && (style != FYNS_DOUBLE_QUOTED || !is_json_plain))
+               /* any original style can be a plain, but contains linebreaks, do a literal */
+               if ((aflags & (FYTTAF_CAN_BE_PLAIN | FYTTAF_HAS_LB)) == (FYTTAF_CAN_BE_PLAIN | FYTTAF_HAS_LB)) {
+                       style = FYNS_LITERAL;
+                       goto out;
+               }
+
+               /* any style, can be just a plain, just make it so */
+               if (style == FYNS_ANY && (aflags & (FYTTAF_CAN_BE_PLAIN | FYTTAF_HAS_LB)) == FYTTAF_CAN_BE_PLAIN) {
+                       style = FYNS_PLAIN;
+                       goto out;
+               }
+
+       }
+
+       if (!flow && emit->source_json && fy_emit_is_dejson_mode(emit)) {
+               if (is_json_plain || (aflags & (FYTTAF_CAN_BE_PLAIN | FYTTAF_HAS_LB)) == FYTTAF_CAN_BE_PLAIN) {
                        style = FYNS_PLAIN;
+                       goto out;
+               }
        }
 
 out:
@@ -1349,6 +1406,7 @@ static void fy_emit_sequence_prolog(struct fy_emitter *emit, struct fy_emit_save
 {
        bool json = fy_emit_is_json_mode(emit);
        bool oneline = fy_emit_is_oneline(emit);
+       bool was_flow = sc->flow;
 
        sc->old_indent = sc->indent;
        if (!json) {
@@ -1373,8 +1431,10 @@ static void fy_emit_sequence_prolog(struct fy_emitter *emit, struct fy_emit_save
                fy_emit_write_indicator(emit, di_left_bracket, sc->flags, sc->indent, fyewt_indicator);
        }
 
-       if (!oneline)
-               sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent);
+       if (!oneline) {
+               if (was_flow || (sc->flags & (DDNF_ROOT | DDNF_SEQ)))
+                       sc->indent = fy_emit_increase_indent(emit, sc->flags, sc->indent);
+       }
 
        sc->flags &= ~DDNF_ROOT;
 }
@@ -1448,7 +1508,7 @@ void fy_emit_sequence(struct fy_emitter *emit, struct fy_node *fyn, int flags, i
                fyt_value = fy_node_value_token(fyni);
 
                fy_emit_sequence_item_prolog(emit, sc, fyt_value);
-               fy_emit_node_internal(emit, fyni, sc->flags, sc->indent, false);
+               fy_emit_node_internal(emit, fyni, (sc->flags & ~DDNF_ROOT), sc->indent, false);
                fy_emit_sequence_item_epilog(emit, sc, last, fyt_value);
        }
 
@@ -1571,8 +1631,8 @@ void fy_emit_mapping(struct fy_emitter *emit, struct fy_node *fyn, int flags, in
 {
        struct fy_node_pair *fynp, *fynpn, **fynpp = NULL;
        struct fy_token *fyt_key, *fyt_value;
-       bool last, simple_key;
-       int aflags, i;
+       bool last, simple_key, used_malloc = false;
+       int aflags, i, count;
        struct fy_emit_save_ctx sct, *sc = &sct;
 
        memset(sc, 0, sizeof(*sc));
@@ -1586,11 +1646,39 @@ void fy_emit_mapping(struct fy_emitter *emit, struct fy_node *fyn, int flags, in
 
        fy_emit_mapping_prolog(emit, sc);
 
-       if (!(emit->cfg.flags & FYECF_SORT_KEYS)) {
+       if (!(emit->cfg.flags & (FYECF_SORT_KEYS | FYECF_STRIP_EMPTY_KV))) {
                fynp = fy_node_pair_list_head(&fyn->mapping);
                fynpp = NULL;
        } else {
-               fynpp = fy_node_mapping_sort_array(fyn, NULL, NULL, NULL);
+               count = fy_node_mapping_item_count(fyn);
+
+               /* heuristic, avoid allocation for small maps */
+               if (count > 64) {
+                       fynpp = malloc((count + 1) * sizeof(*fynpp));
+                       fyd_error_check(fyn->fyd, fynpp, err_out,
+                                       "malloc() failed");
+                       used_malloc = true;
+               } else
+                       fynpp = alloca((count + 1) * sizeof(*fynpp));
+
+               /* fill (removing empty KVs) */
+               i = 0;
+               for (fynp = fy_node_pair_list_head(&fyn->mapping); fynp;
+                               fynp = fy_node_pair_next(&fyn->mapping, fynp)) {
+
+                       /* strip key/value pair from the output if it's empty */
+                       if ((emit->cfg.flags & FYECF_STRIP_EMPTY_KV) && fy_node_is_empty(fynp->value))
+                               continue;
+
+                       fynpp[i++] = fynp;
+               }
+               count = i;
+               fynpp[count] = NULL;
+
+               /* sort the keys */
+               if (emit->cfg.flags & FYECF_SORT_KEYS)
+                       fy_node_mapping_perform_sort(fyn, NULL, NULL, fynpp, count);
+
                i = 0;
                fynp = fynpp[i];
        }
@@ -1630,17 +1718,17 @@ void fy_emit_mapping(struct fy_emitter *emit, struct fy_node *fyn, int flags, in
 
                fy_emit_mapping_key_prolog(emit, sc, fyt_key, simple_key);
                if (fynp->key)
-                       fy_emit_node_internal(emit, fynp->key, sc->flags, sc->indent, true);
+                       fy_emit_node_internal(emit, fynp->key, (sc->flags & ~DDNF_ROOT), sc->indent, true);
                fy_emit_mapping_key_epilog(emit, sc, fyt_key);
 
                fy_emit_mapping_value_prolog(emit, sc, fyt_value);
                if (fynp->value)
-                       fy_emit_node_internal(emit, fynp->value, sc->flags, sc->indent, false);
+                       fy_emit_node_internal(emit, fynp->value, (sc->flags & ~DDNF_ROOT), sc->indent, false);
                fy_emit_mapping_value_epilog(emit, sc, last, fyt_value);
        }
 
-       if (fynpp)
-               fy_node_mapping_sort_release_array(fyn, fynpp);
+       if (fynpp && used_malloc)
+               free(fynpp);
 
        fy_emit_mapping_epilog(emit, sc);
 
@@ -1736,16 +1824,9 @@ int fy_emit_common_document_start(struct fy_emitter *emit,
                   !(emit->flags & FYEF_HAD_DOCUMENT_END))
                dsm = true;
 
-       if (!fy_emit_is_json_mode(emit) && dsm) {
-               if (emit->column)
-                       fy_emit_putc(emit, fyewt_linebreak, '\n');
-               if (!(emit->cfg.flags & FYECF_STRIP_DOC)) {
-                       fy_emit_puts(emit, fyewt_document_indicator, "---");
-                       emit->flags &= ~FYEF_WHITESPACE;
-                       emit->flags |= FYEF_HAD_DOCUMENT_START;
-               }
-       } else
-               emit->flags &= ~FYEF_HAD_DOCUMENT_START;
+       /* output document start indicator if we should */
+       if (dsm)
+               fy_emit_document_start_indicator(emit);
 
        /* clear that in any case */
        emit->flags &= ~FYEF_HAD_DOCUMENT_END;
@@ -1776,19 +1857,23 @@ int fy_emit_document_start(struct fy_emitter *emit, struct fy_document *fyd,
        return 0;
 }
 
-int fy_emit_common_document_end(struct fy_emitter *emit)
+int fy_emit_common_document_end(struct fy_emitter *emit, bool override_state, bool implicit_override)
 {
        const struct fy_document_state *fyds;
        enum fy_emitter_cfg_flags flags = emit->cfg.flags;
        enum fy_emitter_cfg_flags dem_flags = flags & FYECF_DOC_END_MARK(FYECF_DOC_END_MARK_MASK);
-       bool dem;
+       bool implicit, dem;
 
        if (!emit || !emit->fyds)
                return -1;
 
        fyds = emit->fyds;
 
-       dem = ((dem_flags == FYECF_DOC_END_MARK_AUTO && !fyds->end_implicit) ||
+       implicit = fyds->end_implicit;
+       if (override_state)
+               implicit = implicit_override;
+
+       dem = ((dem_flags == FYECF_DOC_END_MARK_AUTO && !implicit) ||
                dem_flags == FYECF_DOC_END_MARK_ON) &&
               !(emit->cfg.flags & FYECF_STRIP_DOC);
 
@@ -1831,7 +1916,7 @@ int fy_emit_document_end(struct fy_emitter *emit)
 {
        int ret;
 
-       ret = fy_emit_common_document_end(emit);
+       ret = fy_emit_common_document_end(emit, false, false);
        if (ret)
                return ret;
 
@@ -1946,6 +2031,18 @@ int fy_emit_setup(struct fy_emitter *emit, const struct fy_emitter_cfg *cfg)
        fy_eventp_list_init(&emit->recycled_eventp);
        fy_token_list_init(&emit->recycled_token);
 
+       /* suppress recycling if we must */
+       emit->suppress_recycling_force = getenv("FY_VALGRIND") && !getenv("FY_VALGRIND_RECYCLING");
+       emit->suppress_recycling = emit->suppress_recycling_force;
+
+       if (!emit->suppress_recycling) {
+               emit->recycled_eventp_list = &emit->recycled_eventp;
+               emit->recycled_token_list = &emit->recycled_token;
+       } else {
+               emit->recycled_eventp_list = NULL;
+               emit->recycled_token_list = NULL;
+       }
+
        fy_emit_reset(emit, false);
 
        return 0;
@@ -1956,10 +2053,15 @@ void fy_emit_cleanup(struct fy_emitter *emit)
        struct fy_eventp *fyep;
        struct fy_token *fyt;
 
+       /* call the finalizer if it exists */
+       if (emit->finalizer)
+               emit->finalizer(emit);
+
        while ((fyt = fy_token_list_pop(&emit->recycled_token)) != NULL)
                fy_token_free(fyt);
 
-       fy_emit_eventp_vacuum(emit);
+       while ((fyep = fy_eventp_list_pop(&emit->recycled_eventp)) != NULL)
+               fy_eventp_free(fyep);
 
        if (!emit->fyd && emit->fyds)
                fy_document_state_unref(emit->fyds);
@@ -1978,6 +2080,13 @@ void fy_emit_cleanup(struct fy_emitter *emit)
        fy_diag_unref(emit->diag);
 }
 
+int fy_emit_node_no_check(struct fy_emitter *emit, struct fy_node *fyn)
+{
+       if (fyn)
+               fy_emit_node_internal(emit, fyn, DDNF_ROOT, -1, false);
+       return 0;
+}
+
 int fy_emit_node(struct fy_emitter *emit, struct fy_node *fyn)
 {
        int ret;
@@ -1986,22 +2095,14 @@ int fy_emit_node(struct fy_emitter *emit, struct fy_node *fyn)
        if (ret)
                return ret;
 
-       if (fyn)
-               fy_emit_node_internal(emit, fyn, DDNF_ROOT, -1, false);
-       return 0;
+       return fy_emit_node_no_check(emit, fyn);
 }
 
-int fy_emit_root_node(struct fy_emitter *emit, struct fy_node *fyn)
+int fy_emit_root_node_no_check(struct fy_emitter *emit, struct fy_node *fyn)
 {
-       int ret;
-
        if (!emit || !fyn)
                return -1;
 
-       ret = fy_emit_node_check(emit, fyn);
-       if (ret)
-               return ret;
-
        /* top comment first */
        fy_emit_node_comment(emit, fyn, DDNF_ROOT, -1, fycp_top);
 
@@ -2016,7 +2117,32 @@ int fy_emit_root_node(struct fy_emitter *emit, struct fy_node *fyn)
        return 0;
 }
 
-int fy_emit_document(struct fy_emitter *emit, struct fy_document *fyd)
+int fy_emit_root_node(struct fy_emitter *emit, struct fy_node *fyn)
+{
+       int ret;
+
+       if (!emit || !fyn)
+               return -1;
+
+       ret = fy_emit_node_check(emit, fyn);
+       if (ret)
+               return ret;
+
+       return fy_emit_root_node_no_check(emit, fyn);
+}
+
+void fy_emit_prepare_document_state(struct fy_emitter *emit, struct fy_document_state *fyds)
+{
+       if (!emit || !fyds)
+               return;
+
+       /* if the original document was JSON and the mode is ORIGINAL turn on JSON mode */
+       emit->source_json = fyds && fyds->json_mode;
+       emit->force_json = (emit->cfg.flags & FYECF_MODE(FYECF_MODE_MASK)) == FYECF_MODE_ORIGINAL &&
+                          emit->source_json;
+}
+
+int fy_emit_document_no_check(struct fy_emitter *emit, struct fy_document *fyd)
 {
        int rc;
 
@@ -2024,7 +2150,7 @@ int fy_emit_document(struct fy_emitter *emit, struct fy_document *fyd)
        if (rc)
                return rc;
 
-       rc = fy_emit_root_node(emit, fyd->root);
+       rc = fy_emit_root_node_no_check(emit, fyd->root);
        if (rc)
                return rc;
 
@@ -2033,6 +2159,26 @@ int fy_emit_document(struct fy_emitter *emit, struct fy_document *fyd)
        return rc;
 }
 
+int fy_emit_document(struct fy_emitter *emit, struct fy_document *fyd)
+{
+       int ret;
+
+       if (!emit)
+               return -1;
+
+       if (fyd) {
+               fy_emit_prepare_document_state(emit, fyd->fyds);
+
+               if (fyd->root) {
+                       ret = fy_emit_node_check(emit, fyd->root);
+                       if (ret)
+                               return ret;
+               }
+       }
+
+       return fy_emit_document_no_check(emit, fyd);
+}
+
 struct fy_emitter *fy_emitter_create(const struct fy_emitter_cfg *cfg)
 {
        struct fy_emitter *emit;
@@ -2100,26 +2246,41 @@ int fy_emitter_set_diag(struct fy_emitter *emit, struct fy_diag *diag)
        return 0;
 }
 
+void fy_emitter_set_finalizer(struct fy_emitter *emit,
+               void (*finalizer)(struct fy_emitter *emit))
+{
+       if (!emit)
+               return;
+       emit->finalizer = finalizer;
+}
+
 struct fy_emit_buffer_state {
+       char **bufp;
+       size_t *sizep;
        char *buf;
-       int size;
-       int pos;
-       int need;
-       bool grow;
+       size_t size;
+       size_t pos;
+       size_t need;
+       bool allocate_buffer;
 };
 
-static int do_buffer_output(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len, void *userdata)
+static int do_buffer_output(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int leni, void *userdata)
 {
        struct fy_emit_buffer_state *state = emit->cfg.userdata;
-       int left;
-       int pagesize = 0;
-       int size;
+       size_t left, pagesize, size, len;
        char *bufnew;
 
+       /* convert to unsigned and use that */
+       len = (size_t)leni;
+
+       /* no funky business */
+       if (len < 0)
+               return -1;
+
        state->need += len;
        left = state->size - state->pos;
        if (left < len) {
-               if (!state->grow)
+               if (!state->allocate_buffer)
                        return 0;
 
                pagesize = sysconf(_SC_PAGESIZE);
@@ -2144,64 +2305,162 @@ static int do_buffer_output(struct fy_emitter *emit, enum fy_emitter_write_type
        return len;
 }
 
-static int fy_emit_str_internal(struct fy_document *fyd,
-                               enum fy_emitter_cfg_flags flags,
-                               struct fy_node *fyn, char **bufp, int *sizep,
-                               bool grow)
+static void
+fy_emitter_str_finalizer(struct fy_emitter *emit)
 {
-       struct fy_emitter emit_state, *emit = &emit_state;
+       struct fy_emit_buffer_state *state;
+
+       if (!emit || !(state = emit->cfg.userdata))
+               return;
+
+       /* if the buffer is allowed to allocate_buffer... */
+       if (state->allocate_buffer && state->buf)
+               free(state->buf);
+       free(state);
+
+       emit->cfg.userdata = NULL;
+}
+
+static struct fy_emitter *
+fy_emitter_create_str_internal(enum fy_emitter_cfg_flags flags, char **bufp, size_t *sizep, bool allocate_buffer)
+{
+       struct fy_emitter *emit;
        struct fy_emitter_cfg emit_cfg;
-       struct fy_emit_buffer_state state;
-       int rc = -1;
+       struct fy_emit_buffer_state *state;
 
-       memset(&emit_cfg, 0, sizeof(emit_cfg));
-       memset(&state, 0, sizeof(state));
+       state = malloc(sizeof(*state));
+       if (!state)
+               return NULL;
+
+       /* if any of these NULL, it's a allocation case */
+       if ((!bufp || !sizep) && !allocate_buffer)
+               return NULL;
+
+       if (bufp && sizep) {
+               state->bufp = bufp;
+               state->buf = *bufp;
+               state->sizep = sizep;
+               state->size = *sizep;
+       } else {
+               state->bufp = NULL;
+               state->buf = NULL;
+               state->sizep = NULL;
+               state->size = 0;
+       }
+       state->pos = 0;
+       state->need = 0;
+       state->allocate_buffer = allocate_buffer;
 
+       memset(&emit_cfg, 0, sizeof(emit_cfg));
        emit_cfg.output = do_buffer_output;
-       emit_cfg.userdata = &state;
+       emit_cfg.userdata = state;
        emit_cfg.flags = flags;
-       state.buf = *bufp;
-       state.size = *sizep;
-       state.grow = grow;
 
-       fy_emit_setup(emit, &emit_cfg);
-       rc = fyd ? fy_emit_document(emit, fyd) : fy_emit_node(emit, fyn);
-       fy_emit_cleanup(emit);
+       emit = fy_emitter_create(&emit_cfg);
+       if (!emit)
+               goto err_out;
 
-       if (rc)
-               goto out_err;
+       /* set finalizer to cleanup */
+       fy_emitter_set_finalizer(emit, fy_emitter_str_finalizer);
 
-       /* terminating zero */
-       rc = do_buffer_output(emit, fyewt_terminating_zero, "\0", 1, emit->cfg.userdata);
+       return emit;
 
-       if (rc != 1) {
-               rc = -1;
-               goto out_err;
-       }
+err_out:
+       if (state)
+               free(state);
+       return NULL;
+}
+
+static int
+fy_emitter_collect_str_internal(struct fy_emitter *emit, char **bufp, size_t *sizep)
+{
+       struct fy_emit_buffer_state *state;
+       char *buf;
+       int rc;
 
-       *sizep = state.need;
+       state = emit->cfg.userdata;
+       assert(state);
 
-       if (!grow)
-               return 0;
+       /* if NULL, then use the values stored on the state */
+       if (!bufp)
+               bufp = state->bufp;
+       if (!sizep)
+               sizep = state->sizep;
 
-       *bufp = realloc(state.buf, *sizep);
-       if (!*bufp) {
-               rc = -1;
-               goto out_err;
+       /* terminating zero */
+       rc = do_buffer_output(emit, fyewt_terminating_zero, "\0", 1, state);
+       if (rc != 1)
+               goto err_out;
+
+       state->size = state->need;
+
+       if (state->allocate_buffer) {
+               /* resize */
+               buf = realloc(state->buf, state->size);
+               /* very likely since we shrink the buffer, but make sure we don't error out */
+               if (buf)
+                       state->buf = buf;
        }
 
+       /* retreive the buffer and size */
+       *sizep = state->size;
+       *bufp = state->buf;
+
+       /* reset the buffer, ownership now to the caller */
+       state->buf = NULL;
+       state->size = 0;
+       state->pos = 0;
+       state->bufp = NULL;
+       state->sizep = NULL;
+
        return 0;
 
-out_err:
-       if (grow && state.buf)
-               free(state.buf);
+err_out:
        *bufp = NULL;
        *sizep = 0;
+       return -1;
+}
 
+static int fy_emit_str_internal(struct fy_document *fyd,
+                               enum fy_emitter_cfg_flags flags,
+                               struct fy_node *fyn, char **bufp, size_t *sizep,
+                               bool allocate_buffer)
+{
+       struct fy_emitter *emit = NULL;
+       int rc = -1;
+
+       emit = fy_emitter_create_str_internal(flags, bufp, sizep, allocate_buffer);
+       if (!emit)
+               goto out_err;
+
+       if (fyd) {
+               fy_emit_prepare_document_state(emit, fyd->fyds);
+               rc = 0;
+               if (fyd->root)
+                       rc = fy_emit_node_check(emit, fyd->root);
+               if (!rc)
+                       rc = fy_emit_document_no_check(emit, fyd);
+       } else {
+               rc = fy_emit_node_check(emit, fyn);
+               if (!rc)
+                       rc = fy_emit_node_no_check(emit, fyn);
+       }
+
+       if (rc)
+               goto out_err;
+
+       rc = fy_emitter_collect_str_internal(emit, NULL, NULL);
+       if (rc)
+               goto out_err;
+
+       /* OK, all done */
+
+out_err:
+       fy_emitter_destroy(emit);
        return rc;
 }
 
-int fy_emit_document_to_buffer(struct fy_document *fyd, enum fy_emitter_cfg_flags flags, char *buf, int size)
+int fy_emit_document_to_buffer(struct fy_document *fyd, enum fy_emitter_cfg_flags flags, char *buf, size_t size)
 {
        int rc;
 
@@ -2213,18 +2472,77 @@ int fy_emit_document_to_buffer(struct fy_document *fyd, enum fy_emitter_cfg_flag
 
 char *fy_emit_document_to_string(struct fy_document *fyd, enum fy_emitter_cfg_flags flags)
 {
-       char *buf = NULL;
-       int rc, size = 0;
+       char *buf;
+       size_t size;
+       int rc;
 
+       buf = NULL;
+       size = 0;
        rc = fy_emit_str_internal(fyd, flags, NULL, &buf, &size, true);
        if (rc != 0)
                return NULL;
        return buf;
 }
 
-static int do_file_output(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int len, void *userdata)
+struct fy_emitter *
+fy_emit_to_buffer(enum fy_emitter_cfg_flags flags, char *buf, size_t size)
+{
+       if (!buf)
+               return NULL;
+
+       return fy_emitter_create_str_internal(flags, &buf, &size, false);
+}
+
+char *
+fy_emit_to_buffer_collect(struct fy_emitter *emit, size_t *sizep)
+{
+       int rc;
+       char *buf;
+
+       if (!emit || !sizep)
+               return NULL;
+
+       rc = fy_emitter_collect_str_internal(emit, &buf, sizep);
+       if (rc) {
+               *sizep = 0;
+               return NULL;
+       }
+       return buf;
+}
+
+struct fy_emitter *
+fy_emit_to_string(enum fy_emitter_cfg_flags flags)
+{
+       return fy_emitter_create_str_internal(flags, NULL, NULL, true);
+}
+
+char *
+fy_emit_to_string_collect(struct fy_emitter *emit, size_t *sizep)
+{
+       int rc;
+       char *buf;
+
+       if (!emit || !sizep)
+               return NULL;
+
+       rc = fy_emitter_collect_str_internal(emit, &buf, sizep);
+       if (rc) {
+               *sizep = 0;
+               return NULL;
+       }
+       return buf;
+}
+
+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;
+
+       /* no funky stuff */
+       if (len < 0)
+               return -1;
 
        return fwrite(str, 1, len, fp);
 }
@@ -2244,7 +2562,15 @@ int fy_emit_document_to_fp(struct fy_document *fyd, enum fy_emitter_cfg_flags fl
        emit_cfg.userdata = fp;
        emit_cfg.flags = flags;
        fy_emit_setup(emit, &emit_cfg);
-       rc = fy_emit_document(emit, fyd);
+
+       fy_emit_prepare_document_state(emit, fyd->fyds);
+
+       rc = 0;
+       if (fyd->root)
+               rc = fy_emit_node_check(emit, fyd->root);
+
+       rc = fy_emit_document_no_check(emit, fyd);
+
        fy_emit_cleanup(emit);
 
        return rc ? rc : 0;
@@ -2269,7 +2595,75 @@ int fy_emit_document_to_file(struct fy_document *fyd,
        return rc ? rc : 0;
 }
 
-int fy_emit_node_to_buffer(struct fy_node *fyn, enum fy_emitter_cfg_flags flags, char *buf, int size)
+static int do_fd_output(struct fy_emitter *emit, enum fy_emitter_write_type type, const char *str, int leni, void *userdata)
+{
+       size_t len;
+       int fd;
+       ssize_t wrn;
+       int total;
+
+       len = (size_t)leni;
+
+       /* no funky stuff */
+       if (len < 0)
+               return -1;
+
+       /* get the file descriptor */
+       fd = (int)(uintptr_t)userdata;
+       if (fd < 0)
+               return -1;
+
+       /* loop output to fd */
+       total = 0;
+       while (len > 0) {
+
+               do {
+                       wrn = write(fd, str, len);
+               } while (wrn == -1 && errno == EAGAIN);
+
+               if (wrn == -1)
+                       return -1;
+
+               if (wrn == 0)
+                       return total;
+
+               len -= wrn;
+               str += wrn;
+               total += wrn;
+       }
+
+       return total;
+}
+
+int fy_emit_document_to_fd(struct fy_document *fyd, enum fy_emitter_cfg_flags flags, int fd)
+{
+       struct fy_emitter emit_state, *emit = &emit_state;
+       struct fy_emitter_cfg emit_cfg;
+       int rc;
+
+       if (fd < 0)
+               return -1;
+
+       memset(&emit_cfg, 0, sizeof(emit_cfg));
+       emit_cfg.output = do_fd_output;
+       emit_cfg.userdata = (void *)(uintptr_t)fd;
+       emit_cfg.flags = flags;
+       fy_emit_setup(emit, &emit_cfg);
+
+       fy_emit_prepare_document_state(emit, fyd->fyds);
+
+       rc = 0;
+       if (fyd->root)
+               rc = fy_emit_node_check(emit, fyd->root);
+
+       rc = fy_emit_document_no_check(emit, fyd);
+
+       fy_emit_cleanup(emit);
+
+       return rc ? rc : 0;
+}
+
+int fy_emit_node_to_buffer(struct fy_node *fyn, enum fy_emitter_cfg_flags flags, char *buf, size_t size)
 {
        int rc;
 
@@ -2281,9 +2675,12 @@ int fy_emit_node_to_buffer(struct fy_node *fyn, enum fy_emitter_cfg_flags flags,
 
 char *fy_emit_node_to_string(struct fy_node *fyn, enum fy_emitter_cfg_flags flags)
 {
-       char *buf = NULL;
-       int rc, size = 0;
+       char *buf;
+       size_t size;
+       int rc;
 
+       buf = NULL;
+       size = 0;
        rc = fy_emit_str_internal(NULL, flags, fyn, &buf, &size, true);
        if (rc != 0)
                return NULL;
@@ -2498,6 +2895,10 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_eventp *fye
                break;
 
        case FYET_SCALAR:
+               /* if we're pretty and at column 0 (meaning it's a single scalar document) output --- */
+               if ((emit->s_flags & DDNF_ROOT) && fy_emit_is_pretty_mode(emit) && !emit->column &&
+                               !fy_emit_is_flow_mode(emit) && !(emit->s_flags & DDNF_FLOW))
+                       fy_emit_document_start_indicator(emit);
                fy_emit_common_node_preamble(emit, fye->scalar.anchor, fye->scalar.tag, emit->s_flags, emit->s_indent);
                style = fye->scalar.value ?
                                fy_node_style_from_scalar_style(fye->scalar.value->scalar.style) :
@@ -2520,7 +2921,7 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_eventp *fye
 
                /* create new context */
                memset(sc, 0, sizeof(*sc));
-               sc->flags = DDNF_SEQ | (emit->s_flags & DDNF_ROOT);
+               sc->flags = emit->s_flags & (DDNF_ROOT | DDNF_SEQ | DDNF_MAP);
                sc->indent = emit->s_indent;
                sc->empty = fy_emit_streaming_sequence_empty(emit);
                sc->flow_token = fye->sequence_start.sequence_start &&
@@ -2533,6 +2934,8 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_eventp *fye
                sc->s_indent = s_indent;
 
                fy_emit_sequence_prolog(emit, sc);
+               sc->flags &= ~DDNF_MAP;
+               sc->flags |= DDNF_SEQ;
 
                emit->s_flags = sc->flags;
                emit->s_indent = sc->indent;
@@ -2553,7 +2956,7 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_eventp *fye
 
                /* create new context */
                memset(sc, 0, sizeof(*sc));
-               sc->flags = DDNF_MAP | (emit->s_flags & DDNF_ROOT);
+               sc->flags = emit->s_flags & (DDNF_ROOT | DDNF_SEQ | DDNF_MAP);
                sc->indent = emit->s_indent;
                sc->empty = fy_emit_streaming_mapping_empty(emit);
                sc->flow_token = fye->mapping_start.mapping_start &&
@@ -2566,6 +2969,8 @@ static int fy_emit_streaming_node(struct fy_emitter *emit, struct fy_eventp *fye
                sc->s_indent = s_indent;
 
                fy_emit_mapping_prolog(emit, sc);
+               sc->flags &= ~DDNF_SEQ;
+               sc->flags |= DDNF_MAP;
 
                emit->s_flags = sc->flags;
                emit->s_indent = sc->indent;
@@ -2617,6 +3022,9 @@ static int fy_emit_handle_document_start(struct fy_emitter *emit, struct fy_even
        fyds = fye->document_start.document_state;
        fye->document_start.document_state = NULL;
 
+       /* prepare (i.e. adapt to the document state) */
+       fy_emit_prepare_document_state(emit, fyds);
+
        fy_emit_common_document_start(emit, fyds, false);
 
        fy_emit_goto_state(emit, FYES_DOCUMENT_CONTENT);
@@ -2624,17 +3032,6 @@ static int fy_emit_handle_document_start(struct fy_emitter *emit, struct fy_even
        return 0;
 }
 
-static int fy_emit_handle_document_content(struct fy_emitter *emit, struct fy_eventp *fyep)
-{
-       int ret;
-
-       ret = fy_emit_push_state(emit, FYES_DOCUMENT_END);
-       if (ret)
-               return ret;
-
-       return fy_emit_streaming_node(emit, fyep, DDNF_ROOT);
-}
-
 static int fy_emit_handle_document_end(struct fy_emitter *emit, struct fy_eventp *fyep)
 {
        struct fy_document_state *fyds;
@@ -2648,7 +3045,7 @@ static int fy_emit_handle_document_end(struct fy_emitter *emit, struct fy_eventp
 
        fyds = emit->fyds;
 
-       ret = fy_emit_common_document_end(emit);
+       ret = fy_emit_common_document_end(emit, true, fye->document_end.implicit);
        if (ret)
                return ret;
 
@@ -2659,6 +3056,22 @@ static int fy_emit_handle_document_end(struct fy_emitter *emit, struct fy_eventp
        return 0;
 }
 
+static int fy_emit_handle_document_content(struct fy_emitter *emit, struct fy_eventp *fyep)
+{
+       struct fy_event *fye = &fyep->e;
+       int ret;
+
+       /* empty document? */
+       if (fye->type == FYET_DOCUMENT_END)
+               return fy_emit_handle_document_end(emit, fyep);
+
+       ret = fy_emit_push_state(emit, FYES_DOCUMENT_END);
+       if (ret)
+               return ret;
+
+       return fy_emit_streaming_node(emit, fyep, DDNF_ROOT);
+}
+
 static int fy_emit_handle_sequence_item(struct fy_emitter *emit, struct fy_eventp *fyep, bool first)
 {
        struct fy_event *fye = &fyep->e;
@@ -2666,7 +3079,7 @@ static int fy_emit_handle_sequence_item(struct fy_emitter *emit, struct fy_event
        struct fy_token *fyt_item = NULL;
        int ret;
 
-       fy_token_unref_rl(&emit->recycled_token, sc->fyt_last_value);
+       fy_token_unref_rl(emit->recycled_token_list, sc->fyt_last_value);
        sc->fyt_last_value = NULL;
 
        switch (fye->type) {
@@ -2747,9 +3160,9 @@ static int fy_emit_handle_mapping_key(struct fy_emitter *emit, struct fy_eventp
        int ret, aflags;
        bool simple_key;
 
-       fy_token_unref_rl(&emit->recycled_token, sc->fyt_last_key);
+       fy_token_unref_rl(emit->recycled_token_list, sc->fyt_last_key);
        sc->fyt_last_key = NULL;
-       fy_token_unref_rl(&emit->recycled_token, sc->fyt_last_value);
+       fy_token_unref_rl(emit->recycled_token_list, sc->fyt_last_value);
        sc->fyt_last_value = NULL;
 
        simple_key = false;
@@ -3098,7 +3511,7 @@ int fy_emitter_default_output(struct fy_emitter *fye, enum fy_emitter_write_type
 
 int fy_document_default_emit_to_fp(struct fy_document *fyd, FILE *fp)
 {
-       struct fy_emitter fye_local, *fye = &fye_local;
+       struct fy_emitter emit_local, *emit = &emit_local;
        struct fy_emitter_cfg ecfg_local, *ecfg = &ecfg_local;
        struct fy_emitter_default_output_data d_local, *d = &d_local;
        int rc;
@@ -3112,20 +3525,26 @@ int fy_document_default_emit_to_fp(struct fy_document *fyd, FILE *fp)
        ecfg->diag = fyd->diag;
        ecfg->userdata = d;
 
-       rc = fy_emit_setup(fye, ecfg);
+       rc = fy_emit_setup(emit, ecfg);
        if (rc)
                goto err_setup;
 
-       rc = fy_emit_document(fye, fyd);
+       fy_emit_prepare_document_state(emit, fyd->fyds);
+
+       rc = 0;
+       if (fyd->root)
+               rc = fy_emit_node_check(emit, fyd->root);
+
+       rc = fy_emit_document_no_check(emit, fyd);
        if (rc)
                goto err_emit;
 
-       fy_emit_cleanup(fye);
+       fy_emit_cleanup(emit);
 
        return 0;
 
 err_emit:
-       fy_emit_cleanup(fye);
+       fy_emit_cleanup(emit);
 err_setup:
        return -1;
 }
index a01ee503002d5c68dc94b9171d6935ac916b983f..3bbd8b5f1c7b12bb468b1a7bdde4f658e73e17e7 100644 (file)
@@ -77,6 +77,11 @@ struct fy_emitter {
        int flow_level;
        unsigned int flags;
        bool output_error : 1;
+       bool source_json : 1;           /* the source was json */
+       bool force_json : 1;            /* force JSON mode unconditionally */
+       bool suppress_recycling_force : 1;
+       bool suppress_recycling : 1;
+
        /* current document */
        struct fy_emitter_cfg cfg;      /* yeah, it isn't worth just to save a few bytes */
        struct fy_document *fyd;
@@ -103,6 +108,12 @@ struct fy_emitter {
        /* recycled */
        struct fy_eventp_list recycled_eventp;
        struct fy_token_list recycled_token;
+
+       struct fy_eventp_list *recycled_eventp_list;    /* NULL when suppressing */
+       struct fy_token_list *recycled_token_list;      /* NULL when suppressing */
+
+       /* for special needs */
+       void (*finalizer)(struct fy_emitter *emit);
 };
 
 int fy_emit_setup(struct fy_emitter *emit, const struct fy_emitter_cfg *cfg);
index 231ed04d7ff5f9c5a0e0f4dfe130298cba091f77..222b87ec296fc90882322ffad362ef66950b97d0 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "fy-parse.h"
 #include "fy-emit.h"
+#include "fy-doc.h"
 
 #include "fy-ctype.h"
 #include "fy-utf8.h"
@@ -38,8 +39,6 @@ struct fy_eventp *fy_eventp_alloc(void)
        if (!fyep)
                return NULL;
 
-       memset(fyep, 0, sizeof(*fyep));
-
        fyep->e.type = FYET_NONE;
 
        return fyep;
@@ -100,13 +99,10 @@ void fy_eventp_clean_rl(struct fy_token_list *fytl, struct fy_eventp *fyep)
 
 void fy_parse_eventp_clean(struct fy_parser *fyp, struct fy_eventp *fyep)
 {
-       struct fy_token_list *fytl;
-
        if (!fyp || !fyep)
                return;
 
-       fytl = !fyp->suppress_recycling ? &fyp->recycled_token : NULL;
-       fy_eventp_clean_rl(fytl, fyep);
+       fy_eventp_clean_rl(fyp->recycled_token_list, fyep);
 }
 
 void fy_emit_eventp_clean(struct fy_emitter *emit, struct fy_eventp *fyep)
@@ -114,7 +110,7 @@ void fy_emit_eventp_clean(struct fy_emitter *emit, struct fy_eventp *fyep)
        if (!emit || !fyep)
                return;
 
-       fy_eventp_clean_rl(&emit->recycled_token, fyep);
+       fy_eventp_clean_rl(emit->recycled_token_list, fyep);
 }
 
 void fy_eventp_free(struct fy_eventp *fyep)
@@ -140,8 +136,8 @@ struct fy_eventp *fy_parse_eventp_alloc(struct fy_parser *fyp)
        if (!fyp)
                return NULL;
 
-       if (!fyp->suppress_recycling)
-               fyep = fy_eventp_list_pop(&fyp->recycled_eventp);
+       if (fyp->recycled_eventp_list)
+               fyep = fy_eventp_list_pop(fyp->recycled_eventp_list);
        if (!fyep)
                fyep = fy_eventp_alloc();
        if (!fyep)
@@ -161,26 +157,12 @@ void fy_parse_eventp_recycle(struct fy_parser *fyp, struct fy_eventp *fyep)
        fy_parse_eventp_clean(fyp, fyep);
 
        /* and push to the parser recycle list */
-       if (!fyp->suppress_recycling)
-               fy_eventp_list_push(&fyp->recycled_eventp, fyep);
+       if (fyp->recycled_eventp_list)
+               fy_eventp_list_push(fyp->recycled_eventp_list, fyep);
        else
                fy_eventp_free(fyep);
 }
 
-void fy_parse_eventp_vacuum(struct fy_parser *fyp)
-{
-       struct fy_eventp *fyep;
-
-       if (!fyp)
-               return;
-
-       while ((fyep = fy_eventp_list_pop(&fyp->recycled_eventp)) != NULL) {
-               /* catch double recycles */
-               /* assert(fy_eventp_list_head(&fyp->recycled_eventp)!= fyep); */
-               fy_eventp_free(fyep);
-       }
-}
-
 void fy_parser_event_free(struct fy_parser *fyp, struct fy_event *fye)
 {
        struct fy_eventp *fyep;
@@ -201,8 +183,10 @@ void fy_emit_eventp_recycle(struct fy_emitter *emit, struct fy_eventp *fyep)
        /* clean, safe to do */
        fy_emit_eventp_clean(emit, fyep);
 
-       /* and push to the parser recycle list */
-       fy_eventp_list_push(&emit->recycled_eventp, fyep);
+       if (emit->recycled_eventp_list)
+               fy_eventp_list_push(emit->recycled_eventp_list, fyep);
+       else
+               fy_eventp_free(fyep);
 }
 
 void fy_emit_event_free(struct fy_emitter *emit, struct fy_event *fye)
@@ -217,17 +201,6 @@ void fy_emit_event_free(struct fy_emitter *emit, struct fy_event *fye)
        fy_emit_eventp_recycle(emit, fyep);
 }
 
-void fy_emit_eventp_vacuum(struct fy_emitter *emit)
-{
-       struct fy_eventp *fyep;
-
-       if (!emit)
-               return;
-
-       while ((fyep = fy_eventp_list_pop(&emit->recycled_eventp)) != NULL)
-               fy_eventp_free(fyep);
-}
-
 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)
@@ -550,7 +523,7 @@ fy_emit_event_vcreate(struct fy_emitter *emit, enum fy_event_type type, va_list
        if (!emit)
                return NULL;
 
-       fyep = fy_eventp_vcreate_internal(&emit->recycled_eventp, emit->diag, emit->fyds, type, ap);
+       fyep = fy_eventp_vcreate_internal(emit->recycled_eventp_list, emit->diag, emit->fyds, type, ap);
        if (!fyep)
                return NULL;
 
@@ -578,7 +551,7 @@ fy_parse_event_vcreate(struct fy_parser *fyp, enum fy_event_type type, va_list a
        if (!fyp)
                return NULL;
 
-       fyep = fy_eventp_vcreate_internal(&fyp->recycled_eventp, fyp->diag, fyp->current_document_state, type, ap);
+       fyep = fy_eventp_vcreate_internal(fyp->recycled_eventp_list, fyp->diag, fyp->current_document_state, type, ap);
        if (!fyep)
                return NULL;
 
@@ -856,3 +829,87 @@ fy_document_start_event_version(struct fy_event *fye)
        return fy_document_state_version(fye->document_start.document_state);
 }
 
+struct fy_eventp *
+fy_document_iterator_eventp_alloc(struct fy_document_iterator *fydi)
+{
+       struct fy_eventp *fyep = NULL;
+
+       if (!fydi)
+               return NULL;
+
+       if (fydi->recycled_eventp_list)
+               fyep = fy_eventp_list_pop(fydi->recycled_eventp_list);
+       if (!fyep)
+               fyep = fy_eventp_alloc();
+       if (!fyep)
+               return NULL;
+
+       fyep->e.type = FYET_NONE;
+
+       return fyep;
+}
+
+void fy_document_iterator_eventp_clean(struct fy_document_iterator *fydi, struct fy_eventp *fyep)
+{
+       if (!fydi || !fyep)
+               return;
+
+       fy_eventp_clean_rl(fydi->recycled_token_list, fyep);
+}
+
+void fy_document_iterator_eventp_recycle(struct fy_document_iterator *fydi, struct fy_eventp *fyep)
+{
+       if (!fydi || !fyep)
+               return;
+
+       /* clean, safe to do */
+       fy_document_iterator_eventp_clean(fydi, fyep);
+
+       if (fydi->recycled_eventp_list)
+               fy_eventp_list_push(fydi->recycled_eventp_list, fyep);
+       else
+               fy_eventp_free(fyep);
+}
+
+struct fy_event *
+fy_document_iterator_event_vcreate(struct fy_document_iterator *fydi, enum fy_event_type type, va_list ap)
+{
+       struct fy_eventp *fyep;
+
+       if (!fydi)
+               return NULL;
+
+       fyep = fy_eventp_vcreate_internal(fydi->recycled_eventp_list,
+                       fydi->fyd ? fydi->fyd->diag : NULL,
+                       fydi->fyd ? fydi->fyd->fyds : NULL,
+                       type, ap);
+       if (!fyep)
+               return NULL;
+
+       return &fyep->e;
+}
+
+struct fy_event *
+fy_document_iterator_event_create(struct fy_document_iterator *fydi, enum fy_event_type type, ...)
+{
+       struct fy_event *fye;
+       va_list ap;
+
+       va_start(ap, type);
+       fye = fy_document_iterator_event_vcreate(fydi, type, ap);
+       va_end(ap);
+
+       return fye;
+}
+
+void fy_document_iterator_event_free(struct fy_document_iterator *fydi, struct fy_event *fye)
+{
+       struct fy_eventp *fyep;
+
+       if (!fydi || !fye)
+               return;
+
+       fyep = container_of(fye, struct fy_eventp, e);
+
+       fy_document_iterator_eventp_recycle(fydi, fyep);
+}
index 3153f8ccee4ffedae4c3073481e537eb2f86f09c..75f20fb279547c1ca92568edc0949291bf682ea8 100644 (file)
@@ -36,10 +36,16 @@ void fy_eventp_release(struct fy_eventp *fyep);
 
 struct fy_eventp *fy_parse_eventp_alloc(struct fy_parser *fyp);
 void fy_parse_eventp_recycle(struct fy_parser *fyp, struct fy_eventp *fyep);
-void fy_parse_eventp_vacuum(struct fy_parser *fyp);
 
 struct fy_eventp *fy_emit_eventp_alloc(struct fy_emitter *fye);
 void fy_emit_eventp_recycle(struct fy_emitter *emit, struct fy_eventp *fyep);
-void fy_emit_eventp_vacuum(struct fy_emitter *emit);
+
+struct fy_document_iterator;
+
+struct fy_eventp *fy_document_iterator_eventp_alloc(struct fy_document_iterator *fydi);
+void fy_document_iterator_eventp_recycle(struct fy_document_iterator *fydi, struct fy_eventp *fyep);
+struct fy_event *fy_document_iterator_event_create(struct fy_document_iterator *document_iterator, enum fy_event_type type, ...);
+struct fy_event *fy_document_iterator_event_vcreate(struct fy_document_iterator *document_iterator, enum fy_event_type type, va_list ap);
+void fy_document_iterator_event_free(struct fy_document_iterator *document_iterator, struct fy_event *fye);
 
 #endif
index 29b1945b2745d111a7c55ac515285b8569c936c8..c41140853f8490db4bce59a3603bf1174848c058 100644 (file)
 
 #include "fy-input.h"
 
+/* amount of multiplication of page size for CHOP size
+ * for a 4K page this is 64K blocks
+ */
+#ifndef FYI_CHOP_MULT
+#define FYI_CHOP_MULT  16
+#endif
+
 struct fy_input *fy_input_alloc(void)
 {
        struct fy_input *fyi;
@@ -100,6 +107,7 @@ static void fy_input_from_data_setup(struct fy_input *fyi,
        fyi->allocated = 0;
        fyi->read = 0;
        fyi->chunk = 0;
+       fyi->chop = 0;
        fyi->fp = NULL;
 
        if (!handle)
@@ -111,7 +119,7 @@ static void fy_input_from_data_setup(struct fy_input *fyi,
                aflags = fy_analyze_scalar_content(data, size,
                                false, fylb_cr_nl, fyfws_space_tab);    /* hardcoded yaml mode */
        else
-               aflags = FYACF_EMPTY | FYACF_FLOW_PLAIN | FYACF_BLOCK_PLAIN;
+               aflags = FYACF_EMPTY | FYACF_FLOW_PLAIN | FYACF_BLOCK_PLAIN | FYACF_SIZE0;
 
        handle->start_mark.input_pos = 0;
        handle->start_mark.line = 0;
@@ -204,21 +212,28 @@ void fy_input_close(struct fy_input *fyi)
                return;
 
        switch (fyi->cfg.type) {
+
        case fyit_file:
-               if (fyi->file.fd != -1) {
-                       close(fyi->file.fd);
-                       fyi->file.fd = -1;
-               }
+       case fyit_fd:
+
                if (fyi->addr && fyi->addr != MAP_FAILED) {
-                       munmap(fyi->addr, fyi->file.length);
-                       fyi->addr = NULL;
+                       munmap(fyi->addr, fyi->length);
+                       fyi->addr = MAP_FAILED;
+               }
+
+               if (fyi->fd != -1) {
+                       if (!fyi->cfg.no_close_fd)
+                               close(fyi->fd);
+                       fyi->fd = -1;
                }
+
                if (fyi->buffer) {
                        free(fyi->buffer);
                        fyi->buffer = NULL;
                }
                if (fyi->fp) {
-                       fclose(fyi->fp);
+                       if (!fyi->cfg.no_fclose_fp)
+                               fclose(fyi->fp);
                        fyi->fp = NULL;
                }
                break;
@@ -306,6 +321,38 @@ void fy_reader_cleanup(struct fy_reader *fyr)
        fy_reader_reset(fyr);
 }
 
+void fy_reader_apply_mode(struct fy_reader *fyr)
+{
+       struct fy_input *fyi;
+
+       assert(fyr);
+
+       /* set input mode from the current reader settings */
+       switch (fyr->mode) {
+       case fyrm_yaml:
+               fyr->json_mode = false;
+               fyr->lb_mode = fylb_cr_nl;
+               fyr->fws_mode = fyfws_space_tab;
+               break;
+       case fyrm_json:
+               fyr->json_mode = true;
+               fyr->lb_mode = fylb_cr_nl;
+               fyr->fws_mode = fyfws_space;
+               break;
+       case fyrm_yaml_1_1:
+               fyr->json_mode = false;
+               fyr->lb_mode = fylb_cr_nl_N_L_P;
+               fyr->fws_mode = fyfws_space_tab;
+               break;
+       }
+       fyi = fyr->current_input;
+       if (fyi) {
+               fyi->json_mode = fyr->json_mode;
+               fyi->lb_mode = fyr->lb_mode;
+               fyi->fws_mode = fyr->fws_mode;
+       }
+}
+
 int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const struct fy_reader_input_cfg *icfg)
 {
        struct stat sb;
@@ -318,7 +365,7 @@ int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const stru
        fy_input_unref(fyr->current_input);
        fyr->current_input = fy_input_ref(fyi);
 
-       fy_reader_apply_mode_to_input(fyr);
+       fy_reader_apply_mode(fyr);
 
        if (!icfg)
                memset(&fyr->current_input_cfg, 0, sizeof(fyr->current_input_cfg));
@@ -330,64 +377,63 @@ int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const stru
        fyi->allocated = 0;
        fyi->read = 0;
        fyi->chunk = 0;
+       fyi->chop = 0;
        fyi->fp = NULL;
 
        switch (fyi->cfg.type) {
+
        case fyit_file:
-               memset(&fyi->file, 0, sizeof(fyi->file));
-               fyi->file.fd = fy_reader_file_open(fyr, fyi->cfg.file.filename);
-               fyr_error_check(fyr, fyi->file.fd != -1, err_out,
-                               "failed to open %s",  fyi->cfg.file.filename);
+       case fyit_fd:
+
+               switch (fyi->cfg.type) {
+               case fyit_file:
+                       fyi->fd = fy_reader_file_open(fyr, fyi->cfg.file.filename);
+                       fyr_error_check(fyr, fyi->fd != -1, err_out,
+                                       "failed to open %s",  fyi->cfg.file.filename);
+                       break;
+
+               case fyit_fd:
+                       fyi->fd = fyi->cfg.fd.fd;
+                       fyr_error_check(fyr, fyi->fd >= 0, err_out,
+                                       "bad file.fd %d",  fyi->cfg.fd.fd);
+                       break;
+               default:
+                       assert(0);      // will never happen
+               }
 
-               rc = fstat(fyi->file.fd, &sb);
+               rc = fstat(fyi->fd, &sb);
                fyr_error_check(fyr, rc != -1, err_out,
                                "failed to fstat %s", fyi->cfg.file.filename);
 
-               fyi->file.length = sb.st_size;
+               fyi->length = sb.st_size;
 
                /* only map if not zero (and is not disabled) */
                if (sb.st_size > 0 && !fyr->current_input_cfg.disable_mmap_opt) {
-                       fyi->addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE,
-                                       fyi->file.fd, 0);
+                       fyi->addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fyi->fd, 0);
 
                        /* convert from MAP_FAILED to NULL */
-                       if (fyi->addr == MAP_FAILED) {
+                       if (fyi->addr == MAP_FAILED)
                                fyr_debug(fyr, "mmap failed for file %s",
                                                fyi->cfg.file.filename);
-                               fyi->addr = NULL;
-                       }
                }
                /* if we've managed to mmap, we' good */
-               if (fyi->addr)
+               if (fyi->addr != MAP_FAILED)
                        break;
 
-               fyr_debug(fyr, "direct mmap mode unavailable for file %s, switching to stream mode",
-                               fyi->cfg.file.filename);
-
-               fyi->fp = fdopen(fyi->file.fd, "r");
-               fyr_error_check(fyr, rc != -1, err_out,
-                               "failed to fdopen %s", fyi->cfg.file.filename);
-
-               /* fd ownership assigned to file */
-               fyi->file.fd = -1;
+               /* if we're not ignoring stdio, open a FILE* using the fd */
+               if (!fyi->cfg.ignore_stdio) {
+                       fyi->fp = fdopen(fyi->fd, "r");
+                       fyr_error_check(fyr, rc != -1, err_out, "failed to fdopen %s", fyi->name);
+               } else
+                       fyi->fp = NULL;
 
-               /* switch to stream mode */
-               fyi->chunk = sysconf(_SC_PAGESIZE);
-               fyi->buffer = malloc(fyi->chunk);
-               fyr_error_check(fyr, fyi->buffer, err_out,
-                               "fy_alloc() failed");
-               fyi->allocated = fyi->chunk;
                break;
 
        case fyit_stream:
-               fyi->chunk = fyi->cfg.stream.chunk;
-               if (!fyi->chunk)
-                       fyi->chunk = sysconf(_SC_PAGESIZE);
-               fyi->buffer = malloc(fyi->chunk);
-               fyr_error_check(fyr, fyi->buffer, err_out,
-                               "fy_alloc() failed");
-               fyi->allocated = fyi->chunk;
-               fyi->fp = fyi->cfg.stream.fp;
+               if (!fyi->cfg.ignore_stdio)
+                       fyi->fp = fyi->cfg.stream.fp;
+               else
+                       fyi->fd = fileno(fyi->cfg.stream.fp);
                break;
 
        case fyit_memory:
@@ -399,11 +445,6 @@ int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const stru
                break;
 
        case fyit_callback:
-               fyi->chunk = sysconf(_SC_PAGESIZE);
-               fyi->buffer = malloc(fyi->chunk);
-               fyr_error_check(fyr, fyi->buffer, err_out,
-                               "fy_alloc() failed");
-               fyi->allocated = fyi->chunk;
                break;
 
        default:
@@ -411,6 +452,31 @@ int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const stru
                break;
        }
 
+       switch (fyi->cfg.type) {
+
+               /* those two need no memory */
+       case fyit_memory:
+       case fyit_alloc:
+               break;
+
+               /* all the rest need it */
+       default:
+               /* if we're not in mmap mode */
+               if (fyi->addr != MAP_FAILED)
+                       break;
+
+               fyi->chunk = fyi->cfg.chunk;
+               if (!fyi->chunk)
+                       fyi->chunk = sysconf(_SC_PAGESIZE);
+               fyi->chop = fyi->chunk * FYI_CHOP_MULT;
+               fyi->buffer = malloc(fyi->chunk);
+               fyr_error_check(fyr, fyi->buffer, err_out,
+                               "fy_alloc() failed");
+               fyi->allocated = fyi->chunk;
+               break;
+       }
+
+       fyr->this_input_start = 0;
        fyr->current_input_pos = 0;
        fyr->line = 0;
        fyr->column = 0;
@@ -442,7 +508,8 @@ int fy_reader_input_done(struct fy_reader *fyr)
 
        switch (fyi->cfg.type) {
        case fyit_file:
-               if (fyi->addr)
+       case fyit_fd:
+               if (fyi->addr != MAP_FAILED)
                        break;
 
                /* fall-through */
@@ -475,6 +542,69 @@ err_out:
        return -1;
 }
 
+int fy_reader_input_scan_token_mark_slow_path(struct fy_reader *fyr)
+{
+       struct fy_input *fyi, *fyi_new = NULL;
+
+       assert(fyr);
+
+       if (!fy_reader_input_chop_active(fyr))
+               return 0;
+
+       fyi = fyr->current_input;
+       assert(fyi);
+
+       fyi_new = fy_input_alloc();
+       fyr_error_check(fyr, fyi_new, err_out,
+                       "fy_input_alloc() failed\n");
+
+       /* copy the config over */
+       fyi_new->cfg = fyi->cfg;
+       fyi_new->name = strdup(fyi->name);
+       fyr_error_check(fyr, fyi_new->name, err_out,
+                       "strdup() failed\n");
+
+       fyi_new->chunk = fyi->chunk;
+       fyi_new->chop = fyi->chop;
+       fyi_new->buffer = malloc(fyi->chunk);
+       fyr_error_check(fyr, fyi_new->buffer, err_out,
+                       "fy_alloc() failed");
+       fyi_new->allocated = fyi->chunk;
+       fyi_new->fp = fyi->fp;
+
+       fyi->fp = NULL; /* the file pointer now assigned to the new */
+
+       fyi_new->lb_mode = fyi->lb_mode;
+       fyi_new->fws_mode = fyi->fws_mode;
+
+       fyi_new->state = FYIS_PARSE_IN_PROGRESS;
+
+       /* adjust and copy the left over reads */
+       assert(fyi->read >= fyr->current_input_pos);
+       fyi_new->read = fyi->read - fyr->current_input_pos;
+       if (fyi_new->read > 0)
+               memcpy(fyi_new->buffer, fyi->buffer + fyr->current_input_pos, fyi_new->read);
+
+       fyr->this_input_start += fyr->current_input_pos;
+
+       /* update the reader to point to the new input */
+       fyr->current_input = fyi_new;
+       fyr->current_input_pos = 0;
+       fyr->current_ptr = fyi_new->buffer;
+
+       /* free the old input - while references to it exist it will hang around */
+       fyi->state = FYIS_PARSED;
+       fy_input_unref(fyi);
+       fyi = NULL;
+
+       fyr_debug(fyr, "chop at this_input_start=%zu chop=%zu\n", fyr->this_input_start, fyi->chop);
+
+       return 0;
+err_out:
+       fy_input_unref(fyi_new);
+       return -1;
+}
+
 const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp)
 {
        struct fy_input *fyi;
@@ -494,8 +624,9 @@ const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp)
        /* tokens cannot cross boundaries */
        switch (fyi->cfg.type) {
        case fyit_file:
-               if (fyi->addr) {
-                       left = fyi->file.length - fyr->current_input_pos;
+       case fyit_fd:
+               if (fyi->addr != MAP_FAILED) {
+                       left = fyi->length - (fyr->this_input_start + fyr->current_input_pos);
                        p = fyi->addr + fyr->current_input_pos;
                        break;
                }
@@ -504,7 +635,7 @@ const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp)
 
        case fyit_stream:
        case fyit_callback:
-               left = fyi->read - fyr->current_input_pos;
+               left = fyi->read - (fyr->this_input_start + fyr->current_input_pos);
                p = fyi->buffer + fyr->current_input_pos;
                break;
 
@@ -531,7 +662,7 @@ const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp)
 
        fyr->current_ptr = p;
        fyr->current_left = left;
-       fyr->current_c = fy_utf8_get(fyr->current_ptr, fyr->current_left, &fyr->current_w);
+       fyr->current_c = fy_utf8_get(p, left, &fyr->current_w);
 
        return p;
 }
@@ -557,11 +688,12 @@ const void *fy_reader_input_try_pull(struct fy_reader *fyr, struct fy_input *fyi
 
        switch (fyi->cfg.type) {
        case fyit_file:
+       case fyit_fd:
 
-               if (fyi->addr) {
-                       assert(fyi->file.length >= pos);
+               if (fyi->addr != MAP_FAILED) {
+                       assert(fyi->length >= (fyr->this_input_start + pos));
 
-                       left = fyi->file.length - pos;
+                       left = fyi->length - (fyr->this_input_start + pos);
                        if (!left) {
                                fyr_debug(fyr, "file input exhausted");
                                break;
@@ -649,56 +781,58 @@ const void *fy_reader_input_try_pull(struct fy_reader *fyr, struct fy_input *fyi
                                        break;
                                }
 
-                       } else {
-                               if (!fyi->cfg.stream.ignore_stdio) {
+                       } else if (fyi->fp) {
 
-                                       fyr_debug(fyr, "performing fread request of %zu", nreadreq);
+                               fyr_debug(fyr, "performing fread request of %zu", nreadreq);
 
-                                       nread = fread(fyi->buffer + fyi->read, 1, nreadreq, fyi->fp);
+                               nread = fread(fyi->buffer + fyi->read, 1, nreadreq, fyi->fp);
 
-                                       fyr_debug(fyr, "fread returned %zu", nread);
+                               fyr_debug(fyr, "fread returned %zu", nread);
 
-                                       if (nread <= 0) {
-                                               fyi->err = ferror(fyi->fp);
-                                               if (fyi->err) {
-                                                       fyi->eof = true;
-                                                       fyr_debug(fyr, "fread got ERROR");
-                                                       goto err_out;
-                                               }
-
-                                               fyi->eof = feof(fyi->fp);
-                                               if (fyi->eof)
-                                                       fyr_debug(fyr, "fread got EOF");
-                                               nread = 0;
-                                               break;
+                               if (nread <= 0) {
+                                       fyi->err = ferror(fyi->fp);
+                                       if (fyi->err) {
+                                               fyi->eof = true;
+                                               fyr_debug(fyr, "fread got ERROR");
+                                               goto err_out;
                                        }
 
-                               } else {
+                                       fyi->eof = feof(fyi->fp);
+                                       if (fyi->eof)
+                                               fyr_debug(fyr, "fread got EOF");
+                                       nread = 0;
+                                       break;
+                               }
 
-                                       fyr_debug(fyr, "performing read request of %zu", nreadreq);
+                       } else if (fyi->fd >= 0) {
 
-                                       do {
-                                               snread = read(fileno(fyi->fp), fyi->buffer + fyi->read, nreadreq);
-                                       } while (snread == -1 && errno == EAGAIN);
+                               fyr_debug(fyr, "performing read request of %zu", nreadreq);
 
-                                       fyr_debug(fyr, "read returned %zd", snread);
+                               do {
+                                       snread = read(fyi->fd, fyi->buffer + fyi->read, nreadreq);
+                               } while (snread == -1 && errno == EAGAIN);
 
-                                       if (snread == -1) {
-                                               fyi->err = true;
-                                               fyi->eof = true;
-                                               fyr_error(fyr, "read() failed");
-                                               goto err_out;
-                                       }
+                               fyr_debug(fyr, "read returned %zd", snread);
 
-                                       if (!snread) {
-                                               fyi->eof = true;
-                                               fyr_error(fyr, "read() failed");
-                                               nread = 0;
-                                               break;
-                                       }
+                               if (snread == -1) {
+                                       fyi->err = true;
+                                       fyi->eof = true;
+                                       fyr_error(fyr, "read() failed: %s", strerror(errno));
+                                       goto err_out;
+                               }
 
-                                       nread = snread;
+                               if (!snread) {
+                                       fyi->eof = true;
+                                       nread = 0;
+                                       break;
                                }
+
+                               nread = snread;
+                       } else {
+                               fyr_error(fyr, "No FILE* nor fd available?");
+                               fyi->eof = true;
+                               nread = 0;
+                               goto err_out;
                        }
 
                        assert(nread > 0);
@@ -791,9 +925,17 @@ struct fy_input *fy_input_create(const struct fy_input_cfg *fyic)
 
        /* copy filename pointers and switch */
        switch (fyic->type) {
+
        case fyit_file:
                fyi->name = strdup(fyic->file.filename);
                break;
+
+       case fyit_fd:
+               ret = asprintf(&fyi->name, "<fd-%d>", fyic->fd.fd);
+               if (ret == -1)
+                       fyi->name = NULL;
+               break;
+
        case fyit_stream:
                if (fyic->stream.name)
                        fyi->name = strdup(fyic->stream.name);
@@ -807,13 +949,13 @@ struct fy_input *fy_input_create(const struct fy_input_cfg *fyic)
                }
                break;
        case fyit_memory:
-               ret = asprintf(&fyi->name, "<memory-@0x%p-0x%p>",
+               ret = asprintf(&fyi->name, "<memory-@%p-%p>",
                        fyic->memory.data, fyic->memory.data + fyic->memory.size - 1);
                if (ret == -1)
                        fyi->name = NULL;
                break;
        case fyit_alloc:
-               ret = asprintf(&fyi->name, "<alloc-@0x%p-0x%p>",
+               ret = asprintf(&fyi->name, "<alloc-@%p-%p>",
                        fyic->memory.data, fyic->memory.data + fyic->memory.size - 1);
                if (ret == -1)
                        fyi->name = NULL;
@@ -834,35 +976,11 @@ struct fy_input *fy_input_create(const struct fy_input_cfg *fyic)
        fyi->allocated = 0;
        fyi->read = 0;
        fyi->chunk = 0;
+       fyi->chop = 0;
        fyi->fp = NULL;
-
-       switch (fyi->cfg.type) {
-       case fyit_file:
-               memset(&fyi->file, 0, sizeof(fyi->file));
-               fyi->file.fd = -1;
-               fyi->addr = MAP_FAILED;
-               break;
-
-               /* nothing for those two */
-       case fyit_stream:
-               break;
-
-       case fyit_memory:
-               /* nothing to do for memory */
-               break;
-
-       case fyit_alloc:
-               /* nothing to do for memory */
-               break;
-
-       case fyit_callback:
-               /* nothing to do for callback */
-               break;
-
-       default:
-               assert(0);
-               break;
-       }
+       fyi->fd = -1;
+       fyi->addr = MAP_FAILED;
+       fyi->length = -1;
 
        /* default modes */
        fyi->lb_mode = fylb_cr_nl;
index 61316d24064a8d6cc6cd10abc8c1f68960b12d22..618f3b8be0b767eca935e95d4763001b5ee54dff 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <libfyaml.h>
 
+#include "fy-utils.h"
 #include "fy-typelist.h"
 #include "fy-ctype.h"
 
@@ -38,11 +39,16 @@ enum fy_input_type {
        fyit_memory,
        fyit_alloc,
        fyit_callback,
+       fyit_fd,
 };
 
 struct fy_input_cfg {
        enum fy_input_type type;
        void *userdata;
+       size_t chunk;
+       bool ignore_stdio : 1;
+       bool no_fclose_fp : 1;
+       bool no_close_fd : 1;
        union {
                struct {
                        const char *filename;
@@ -50,8 +56,6 @@ struct fy_input_cfg {
                struct {
                        const char *name;
                        FILE *fp;
-                       size_t chunk;
-                       bool ignore_stdio;
                } stream;
                struct {
                        const void *data;
@@ -65,6 +69,9 @@ struct fy_input_cfg {
                        /* negative return is error, 0 is EOF */
                        ssize_t (*input)(void *user, void *buf, size_t count);
                } callback;
+               struct {
+                       int fd;
+               } fd;
        };
 };
 
@@ -80,28 +87,25 @@ struct fy_input {
        struct list_head node;
        enum fy_input_state state;
        struct fy_input_cfg cfg;
+       int refs;               /* number of referers */
        char *name;
        void *buffer;           /* when the file can't be mmaped */
        uint64_t generation;
        size_t allocated;
        size_t read;
        size_t chunk;
-       FILE *fp;
-       int refs;
+       size_t chop;
+       FILE *fp;               /* FILE* for the input if it exists */
+       int fd;                 /* fd for file and stream */
+       size_t length;          /* length of file */
        void *addr;             /* mmaped for files, allocated for streams */
        bool eof : 1;           /* got EOF */
        bool err : 1;           /* got an error */
 
        /* propagated */
+       bool json_mode;
        enum fy_lb_mode lb_mode;
        enum fy_flow_ws_mode fws_mode;
-
-       union {
-               struct {
-                       int fd;                 /* fd for file and stream */
-                       size_t length;
-               } file;
-       };
 };
 FY_TYPE_DECL_LIST(input);
 
@@ -144,7 +148,7 @@ static inline size_t fy_input_size(const struct fy_input *fyi)
        switch (fyi->cfg.type) {
        case fyit_file:
                if (fyi->addr) {
-                       size = fyi->file.length;
+                       size = fyi->length;
                        break;
                }
                /* fall-through */
@@ -240,6 +244,7 @@ struct fy_reader {
        struct fy_reader_input_cfg current_input_cfg;
        struct fy_input *current_input;
 
+       size_t this_input_start;        /* this input start */
        size_t current_input_pos;       /* from start of input */
        const void *current_ptr;        /* current pointer into the buffer */
        int current_c;                  /* current utf8 character at current_ptr (-1 if not cached) */
@@ -252,6 +257,11 @@ struct fy_reader {
        int tabsize;                    /* very experimental tab size for indent purposes */
 
        struct fy_diag *diag;
+
+       /* decoded mode variables; update when changing modes */
+       bool json_mode;
+       enum fy_lb_mode lb_mode;
+       enum fy_flow_ws_mode fws_mode;
 };
 
 void fy_reader_reset(struct fy_reader *fyr);
@@ -260,96 +270,108 @@ void fy_reader_cleanup(struct fy_reader *fyr);
 
 int fy_reader_input_open(struct fy_reader *fyr, struct fy_input *fyi, const struct fy_reader_input_cfg *icfg);
 int fy_reader_input_done(struct fy_reader *fyr);
+int fy_reader_input_scan_token_mark_slow_path(struct fy_reader *fyr);
 
-const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp);
-const void *fy_reader_ensure_lookahead_slow_path(struct fy_reader *fyr, size_t size, size_t *leftp);
-
-static inline void
-fy_reader_apply_mode_to_input(struct fy_reader *fyr)
+static inline bool
+fy_reader_input_chop_active(struct fy_reader *fyr)
 {
-       if (!fyr || !fyr->current_input)
-               return;
+       struct fy_input *fyi;
 
-       /* set input mode from the current reader settings */
-       switch (fyr->mode) {
-       case fyrm_yaml:
-               fyr->current_input->lb_mode = fylb_cr_nl;
-               fyr->current_input->fws_mode = fyfws_space_tab;
-               break;
-       case fyrm_json:
-               fyr->current_input->lb_mode = fylb_cr_nl;
-               fyr->current_input->fws_mode = fyfws_space;
-               break;
-       case fyrm_yaml_1_1:
-               fyr->current_input->lb_mode = fylb_cr_nl_N_L_P;
-               fyr->current_input->fws_mode = fyfws_space_tab;
+       assert(fyr);
+
+       fyi = fyr->current_input;
+       assert(fyi);
+
+       if (!fyi->chop)
+               return false;
+
+       switch (fyi->cfg.type) {
+       case fyit_file:
+               return !fyi->addr && fyi->fp;   /* non-mmap mode */
+
+       case fyit_stream:
+       case fyit_callback:
+               return true;
+
+       default:
+               /* all the others do not support chop */
                break;
        }
+
+       return false;
+}
+
+static inline int
+fy_reader_input_scan_token_mark(struct fy_reader *fyr)
+{
+       /* don't chop until ready */
+       if (!fy_reader_input_chop_active(fyr) ||
+           fyr->current_input->chop > fyr->current_input_pos)
+               return 0;
+
+       return fy_reader_input_scan_token_mark_slow_path(fyr);
 }
 
-static inline enum fy_reader_mode
+const void *fy_reader_ptr_slow_path(struct fy_reader *fyr, size_t *leftp);
+const void *fy_reader_ensure_lookahead_slow_path(struct fy_reader *fyr, size_t size, size_t *leftp);
+
+void fy_reader_apply_mode(struct fy_reader *fyr);
+
+static FY_ALWAYS_INLINE inline enum fy_reader_mode
 fy_reader_get_mode(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return fyrm_yaml;
+       assert(fyr);
        return fyr->mode;
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_set_mode(struct fy_reader *fyr, enum fy_reader_mode mode)
 {
-       if (!fyr)
-               return;
-
+       assert(fyr);
        fyr->mode = mode;
-       fy_reader_apply_mode_to_input(fyr);
+       fy_reader_apply_mode(fyr);
 }
 
-static inline struct fy_input *
+static FY_ALWAYS_INLINE inline struct fy_input *
 fy_reader_current_input(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return NULL;
+       assert(fyr);
        return fyr->current_input;
 }
 
-static inline uint64_t
+static FY_ALWAYS_INLINE inline uint64_t
 fy_reader_current_input_generation(const struct fy_reader *fyr)
 {
-       if (!fyr || !fyr->current_input)
-               return 0;
+       assert(fyr);
+       assert(fyr->current_input);
        return fyr->current_input->generation;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_column(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return -1;
+       assert(fyr);
        return fyr->column;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_tabsize(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return -1;
+       assert(fyr);
        return fyr->tabsize;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_line(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return -1;
+       assert(fyr);
        return fyr->line;
 }
 
 /* force new line at the end of stream */
 static inline void fy_reader_stream_end(struct fy_reader *fyr)
 {
-       if (!fyr)
-               return;
+       assert(fyr);
 
        /* force new line */
        if (fyr->column) {
@@ -358,7 +380,7 @@ static inline void fy_reader_stream_end(struct fy_reader *fyr)
        }
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_get_mark(struct fy_reader *fyr, struct fy_mark *fym)
 {
        assert(fyr);
@@ -367,7 +389,7 @@ fy_reader_get_mark(struct fy_reader *fyr, struct fy_mark *fym)
        fym->column = fyr->column;
 }
 
-static inline const void *
+static FY_ALWAYS_INLINE inline const void *
 fy_reader_ptr(struct fy_reader *fyr, size_t *leftp)
 {
        if (fyr->current_ptr) {
@@ -379,90 +401,83 @@ fy_reader_ptr(struct fy_reader *fyr, size_t *leftp)
        return fy_reader_ptr_slow_path(fyr, leftp);
 }
 
-static inline bool fy_reader_json_mode(const struct fy_reader *fyr)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_json_mode(const struct fy_reader *fyr)
 {
-       return fyr && fyr->mode == fyrm_json;
+       assert(fyr);
+       return fyr->json_mode;
 }
 
-static inline enum fy_lb_mode fy_reader_lb_mode(const struct fy_reader *fyr)
+static FY_ALWAYS_INLINE inline enum fy_lb_mode
+fy_reader_lb_mode(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return fylb_cr_nl;
-
-       switch (fyr->mode) {
-       case fyrm_yaml:
-       case fyrm_json:
-               return fylb_cr_nl;
-       case fyrm_yaml_1_1:
-               return fylb_cr_nl_N_L_P;
-       }
-
-       return fylb_cr_nl;
+       assert(fyr);
+       return fyr->lb_mode;
 }
 
-static inline enum fy_flow_ws_mode fy_reader_flow_ws_mode(const struct fy_reader *fyr)
+static FY_ALWAYS_INLINE inline enum fy_flow_ws_mode
+fy_reader_flow_ws_mode(const struct fy_reader *fyr)
 {
-       if (!fyr)
-               return fyfws_space_tab;
-
-       switch (fyr->mode) {
-       case fyrm_yaml:
-       case fyrm_yaml_1_1:
-               return fyfws_space_tab;
-       case fyrm_json:
-               return fyfws_space;
-       }
-
-       return fyfws_space_tab;
+       assert(fyr);
+       return fyr->fws_mode;
 }
 
-static inline bool fy_reader_is_lb(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_lb(const struct fy_reader *fyr, int c)
 {
        return fy_is_lb_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_lbz(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_lbz(const struct fy_reader *fyr, int c)
 {
        return fy_is_lbz_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_blankz(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_blankz(const struct fy_reader *fyr, int c)
 {
        return fy_is_blankz_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_generic_lb(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_generic_lb(const struct fy_reader *fyr, int c)
 {
        return fy_is_generic_lb_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_generic_lbz(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_generic_lbz(const struct fy_reader *fyr, int c)
 {
        return fy_is_generic_lbz_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_generic_blankz(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_generic_blankz(const struct fy_reader *fyr, int c)
 {
        return fy_is_generic_blankz_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline bool fy_reader_is_flow_ws(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_flow_ws(const struct fy_reader *fyr, int c)
 {
        return fy_is_flow_ws_m(c, fy_reader_flow_ws_mode(fyr));
 }
 
-static inline bool fy_reader_is_flow_blank(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_flow_blank(const struct fy_reader *fyr, int c)
 {
        return fy_reader_is_flow_ws(fyr, c);    /* same */
 }
 
-static inline bool fy_reader_is_flow_blankz(const struct fy_reader *fyr, int c)
+static FY_ALWAYS_INLINE inline bool
+fy_reader_is_flow_blankz(const struct fy_reader *fyr, int c)
 {
        return fy_is_flow_ws_m(c, fy_reader_flow_ws_mode(fyr)) ||
               fy_is_generic_lbz_m(c, fy_reader_lb_mode(fyr));
 }
 
-static inline const void *
+static FY_ALWAYS_INLINE inline const void *
 fy_reader_ensure_lookahead(struct fy_reader *fyr, size_t size, size_t *leftp)
 {
        if (fyr->current_ptr && fyr->current_left >= size) {
@@ -480,6 +495,7 @@ fy_reader_strncmp(struct fy_reader *fyr, const char *str, size_t n)
        const char *p;
        int ret;
 
+       assert(fyr);
        p = fy_reader_ensure_lookahead(fyr, n, NULL);
        if (!p)
                return -1;
@@ -487,13 +503,14 @@ fy_reader_strncmp(struct fy_reader *fyr, const char *str, size_t n)
        return ret ? 1 : 0;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_peek_at_offset(struct fy_reader *fyr, size_t offset)
 {
        const uint8_t *p;
        size_t left;
        int w;
 
+       assert(fyr);
        if (offset == 0 && fyr->current_c >= 0)
                return fyr->current_c;
 
@@ -517,12 +534,13 @@ fy_reader_peek_at_offset(struct fy_reader *fyr, size_t offset)
        return fy_utf8_get(p + offset, left - offset, &w);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_peek_at_internal(struct fy_reader *fyr, int pos, ssize_t *offsetp)
 {
        int i, c;
        size_t offset;
 
+       assert(fyr);
        if (!offsetp || *offsetp < 0) {
                for (i = 0, offset = 0; i < pos; i++, offset += fy_utf8_width(c)) {
                        c = fy_reader_peek_at_offset(fyr, offset);
@@ -540,25 +558,25 @@ fy_reader_peek_at_internal(struct fy_reader *fyr, int pos, ssize_t *offsetp)
        return c;
 }
 
-static inline bool
+static FY_ALWAYS_INLINE inline bool
 fy_reader_is_blank_at_offset(struct fy_reader *fyr, size_t offset)
 {
        return fy_is_blank(fy_reader_peek_at_offset(fyr, offset));
 }
 
-static inline bool
+static FY_ALWAYS_INLINE inline bool
 fy_reader_is_blankz_at_offset(struct fy_reader *fyr, size_t offset)
 {
        return fy_reader_is_blankz(fyr, fy_reader_peek_at_offset(fyr, offset));
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_peek_at(struct fy_reader *fyr, int pos)
 {
        return fy_reader_peek_at_internal(fyr, pos, NULL);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_peek(struct fy_reader *fyr)
 {
        if (fyr->current_c >= 0)
@@ -567,7 +585,7 @@ fy_reader_peek(struct fy_reader *fyr)
        return fy_reader_peek_at_offset(fyr, 0);
 }
 
-static inline const void *
+static FY_ALWAYS_INLINE inline const void *
 fy_reader_peek_block(struct fy_reader *fyr, size_t *lenp)
 {
        const void *p;
@@ -583,9 +601,10 @@ fy_reader_peek_block(struct fy_reader *fyr, size_t *lenp)
        return p;
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_advance_octets(struct fy_reader *fyr, size_t advance)
 {
+       assert(fyr);
        assert(fyr->current_left >= advance);
 
        fyr->current_input_pos += advance;
@@ -597,14 +616,15 @@ fy_reader_advance_octets(struct fy_reader *fyr, size_t advance)
 
 void fy_reader_advance_slow_path(struct fy_reader *fyr, int c);
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_advance_printable_ascii(struct fy_reader *fyr, int c)
 {
+       assert(fyr);
        fy_reader_advance_octets(fyr, 1);
        fyr->column++;
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_advance(struct fy_reader *fyr, int c)
 {
        if (fy_utf8_is_printable_ascii(c))
@@ -613,7 +633,7 @@ fy_reader_advance(struct fy_reader *fyr, int c)
                fy_reader_advance_slow_path(fyr, c);
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_advance_ws(struct fy_reader *fyr, int c)
 {
        /* skip this character */
@@ -625,14 +645,14 @@ fy_reader_advance_ws(struct fy_reader *fyr, int c)
                fyr->column++;
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_reader_advance_space(struct fy_reader *fyr)
 {
        fy_reader_advance_octets(fyr, 1);
        fyr->column++;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_get(struct fy_reader *fyr)
 {
        int value;
@@ -646,7 +666,7 @@ fy_reader_get(struct fy_reader *fyr)
        return value;
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_reader_advance_by(struct fy_reader *fyr, int count)
 {
        int i, c;
index 3f59fe7535b7c3add93c295897a089bde51e5863..3c8618d277848870600e631a36a2d2304ba70ff7 100644 (file)
@@ -122,6 +122,10 @@ int fy_parse_get_next_input(struct fy_parser *fyp)
        /* take off the reference; reader now owns */
        fy_input_unref(fyi);
 
+       // inherit the JSON mode
+       if (fyp->current_document_state)
+               fyp->current_document_state->json_mode = fyp_json_mode(fyp);
+
        fyp_scan_debug(fyp, "get next input: new input - %s mode", json_mode ? "JSON" : "YAML");
 
        return 1;
@@ -131,28 +135,70 @@ err_out:
        return -1;
 }
 
+static inline void
+fy_token_queue_epilogue(struct fy_parser *fyp, struct fy_token *fyt)
+{
+       /* special handling for zero indented scalars */
+       fyp->token_activity_counter++;
+       if (fyt->type == FYTT_DOCUMENT_START)
+               fyp->document_first_content_token = true;
+       else if (fyp->document_first_content_token && fy_token_type_is_content(fyt->type))
+               fyp->document_first_content_token = false;
+}
+
+static inline struct fy_token *
+fy_token_queue_simple_internal(struct fy_parser *fyp, struct fy_token_list *fytl, enum fy_token_type type, int advance_octets)
+{
+       struct fy_reader *fyr = fyp->reader;
+       struct fy_token *fyt;
+
+       /* allocate and copy in place */
+       fyt = fy_token_alloc_rl(fyp->recycled_token_list);
+       if (!fyt)
+               return NULL;
+
+       fyt->type = type;
+
+       /* the advance is always octets */
+       fy_reader_fill_atom_start(fyr, &fyt->handle);
+       if (advance_octets > 0) {
+               fy_reader_advance_octets(fyr, advance_octets);
+               fyr->column += advance_octets;
+       }
+       fy_reader_fill_atom_end(fyr, &fyt->handle);
+
+       fy_input_ref(fyt->handle.fyi);
+
+       fy_token_list_add_tail(fytl, fyt);
+
+       return fyt;
+}
+
+static inline struct fy_token *
+fy_token_queue_simple(struct fy_parser *fyp, struct fy_token_list *fytl, enum fy_token_type type, int advance_octets)
+{
+       struct fy_token *fyt;
+
+       fyt = fy_token_queue_simple_internal(fyp, fytl, type, advance_octets);
+       if (!fyt)
+               return NULL;
+
+       fy_token_queue_epilogue(fyp, fyt);
+       return fyt;
+}
+
 struct fy_token *
 fy_token_vqueue_internal(struct fy_parser *fyp, struct fy_token_list *fytl,
                         enum fy_token_type type, va_list ap)
 {
        struct fy_token *fyt;
 
-       fyt = fy_token_vcreate_rl(fy_parse_recycled_token(fyp), type, ap);
+       fyt = fy_token_vcreate_rl(fyp->recycled_token_list, type, ap);
        if (!fyt)
                return NULL;
        fy_token_list_add_tail(fytl, fyt);
 
-       /* special handling for zero indented scalars */
-       if (fyt->type == FYTT_DOCUMENT_START) {
-               fyp->document_first_content_token = true;
-               fyp_scan_debug(fyp, "document_first_content_token set to true");
-       } else if (fyp->document_first_content_token &&
-                       fy_token_type_is_content(fyt->type)) {
-               fyp->document_first_content_token = false;
-               fyp_scan_debug(fyp, "document_first_content_token set to false");
-       }
-
-       fyp_debug_dump_token_list(fyp, fytl, fyt, "queued: ");
+       fy_token_queue_epilogue(fyp, fyt);
        return fyt;
 }
 
@@ -394,6 +440,8 @@ int fy_reset_document_state(struct fy_parser *fyp)
                fyp_error_check(fyp, fyds_new, err_out,
                                "fy_document_state_copy() failed");
        }
+       // inherit the JSON mode
+       fyds_new->json_mode = fyp_json_mode(fyp);
 
        if (fyp->current_document_state)
                fy_document_state_unref(fyp->current_document_state);
@@ -492,7 +540,7 @@ int fy_parse_version_directive(struct fy_parser *fyp, struct fy_token *fyt, bool
                                "duplicate version directive");
        } else {
                /* in scan mode, we just override everything */
-               fy_token_unref_rl(fy_parse_recycled_token(fyp), fyds->fyt_vd);
+               fy_token_unref_rl(fyp->recycled_token_list, fyds->fyt_vd);
                fyds->fyt_vd = NULL;
        }
 
@@ -537,7 +585,7 @@ int fy_parse_version_directive(struct fy_parser *fyp, struct fy_token *fyt, bool
 err_out:
        rc = -1;
 err_out_rc:
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyt);
+       fy_token_unref_rl(fyp->recycled_token_list, fyt);
        return rc;
 }
 
@@ -572,7 +620,7 @@ int fy_parse_tag_directive(struct fy_parser *fyp, struct fy_token *fyt, bool sca
        if (fyt_td) {
                /* fyp_notice(fyp, "overriding tag"); */
                fy_token_list_del(&fyds->fyt_td, fyt_td);
-               fy_token_unref_rl(fy_parse_recycled_token(fyp), fyt_td);
+               fy_token_unref_rl(fyp->recycled_token_list, fyt_td);
                /* when we override a default tag the tags are explicit */
                fyds->tags_explicit = true;
        }
@@ -588,7 +636,7 @@ int fy_parse_tag_directive(struct fy_parser *fyp, struct fy_token *fyt, bool sca
 
        return 0;
 err_out:
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyt);
+       fy_token_unref_rl(fyp->recycled_token_list, fyt);
        return -1;
 }
 
@@ -741,6 +789,14 @@ int fy_parse_setup(struct fy_parser *fyp, const struct fy_parse_cfg *cfg)
        if (fyp->suppress_recycling)
                fyp_parse_debug(fyp, "Suppressing recycling");
 
+       if (!fyp->suppress_recycling) {
+               fyp->recycled_eventp_list = &fyp->recycled_eventp;
+               fyp->recycled_token_list = &fyp->recycled_token;
+       } else {
+               fyp->recycled_eventp_list = NULL;
+               fyp->recycled_token_list = NULL;
+       }
+
        fyp->current_document_state = NULL;
 
        rc = fy_reset_document_state(fyp);
@@ -755,6 +811,7 @@ err_out_rc:
 void fy_parse_cleanup(struct fy_parser *fyp)
 {
        struct fy_input *fyi, *fyin;
+       struct fy_eventp *fyep;
        struct fy_token *fyt;
 
        fy_composer_destroy(fyp->fyc);
@@ -767,7 +824,7 @@ void fy_parse_cleanup(struct fy_parser *fyp)
        fy_parse_parse_state_log_list_recycle_all(fyp, &fyp->state_stack);
        fy_parse_flow_list_recycle_all(fyp, &fyp->flow_stack);
 
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyp->stream_end_token);
+       fy_token_unref_rl(fyp->recycled_token_list, fyp->stream_end_token);
 
        fy_document_state_unref(fyp->current_document_state);
        fy_document_state_unref(fyp->default_document_state);
@@ -784,9 +841,15 @@ void fy_parse_cleanup(struct fy_parser *fyp)
        fy_parse_indent_vacuum(fyp);
        fy_parse_simple_key_vacuum(fyp);
        fy_parse_parse_state_log_vacuum(fyp);
-       fy_parse_eventp_vacuum(fyp);
        fy_parse_flow_vacuum(fyp);
 
+       /* free the recycled events */
+       while ((fyep = fy_eventp_list_pop(&fyp->recycled_eventp)) != NULL) {
+               /* catch double recycles */
+               /* assert(fy_eventp_list_head(&fyp->recycled_eventp)!= fyep); */
+               fy_eventp_free(fyep);
+       }
+
        /* and the recycled tokens */
        while ((fyt = fy_token_list_pop(&fyp->recycled_token)) != NULL)
                fy_token_free(fyt);
@@ -964,13 +1027,17 @@ err_out_rc:
 int fy_scan_to_next_token(struct fy_parser *fyp)
 {
        int c, c_after_ws, i, rc = 0;
-       bool tabs_allowed;
+       bool tabs_allowed, sloppy_flow, no_indent;
        ssize_t offset;
        struct fy_atom *handle;
        struct fy_reader *fyr;
 
        fyr = fyp->reader;
 
+       rc = fy_reader_input_scan_token_mark(fyr);
+       fyp_error_check(fyp, !rc, err_out_rc,
+                       "fy_reader_input_scan_token_mark() failed");
+
        /* skip BOM at the start of the stream */
        if (fyr->current_input_pos == 0 && (c = fy_parse_peek(fyp)) == FY_UTF8_BOM) {
 
@@ -985,21 +1052,55 @@ int fy_scan_to_next_token(struct fy_parser *fyp)
                goto done;
        }
 
-       for (;;) {
+       tabs_allowed = fyp->flow_level > 0 || !fyp->simple_key_allowed || fyp_tabsize(fyp) > 0;
+       sloppy_flow = fyp->flow_level > 0 && (fyp->cfg.flags & FYPCF_SLOPPY_FLOW_INDENTATION);
 
-               tabs_allowed = fyp->flow_level || !fyp->simple_key_allowed;
+       for (;;) {
 
                /* skip white space, tabs are allowed in flow context */
                /* tabs also allowed in block context but not at start of line or after -?: */
 
-               if (!fyp_tabsize(fyp) && !tabs_allowed) {
+               /* if we're not in sloppy flow indent mode, a tab may not be used as indentation */
+               if (!sloppy_flow) {
+                       // fyp_notice(fyp, "not sloppy flow check c='%c' col=%d indent=%d\n", fy_parse_peek(fyp), fyp_column(fyp), fyp->indent);
+                       c = -1;
+                       while (fyp_column(fyp) <= fyp->indent && fy_is_ws(c = fy_parse_peek(fyp))) {
+                               if (fy_is_tab(c))
+                                       break;
+                               fy_advance(fyp, c);
+                       }
+
+                       /* it's an error, only if it is used for intentation */
+                       /* comments and empty lines are OK */
+                       if (fy_is_tab(c)) {
+
+                               /* skip all space and tabs */
+                               i = 0;
+                               offset = -1;
+                               while (fy_is_ws(c_after_ws = fy_parse_peek_at_internal(fyp, i, &offset)))
+                                       i++;
+
+                               no_indent = c_after_ws == '#' || fyp_is_lb(fyp, c_after_ws);
+
+                               FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
+                                               no_indent, err_out,
+                                               "tab character may not be used as indentation");
+
+                               /* advance by that amount */
+                               fy_advance_by(fyp, i);
+                       }
+               }
+
+               if (!tabs_allowed) {
                        /* skip space only */
                        fy_reader_skip_space(fyr);
                        c = fy_parse_peek(fyp);
 
-                       /* if it's a tab, we need to see if after ws follows a flow start marker */
+                       /* it's a tab, here we go */
                        if (fy_is_tab(c)) {
 
+                               /* we need to see if after ws follows a flow start marker */
+
                                /* skip all space and tabs */
                                i = 0;
                                offset = -1;
@@ -1027,6 +1128,8 @@ int fy_scan_to_next_token(struct fy_parser *fyp)
                        rc = fy_scan_comment(fyp, handle, false);
                        fyp_error_check(fyp, !rc, err_out_rc,
                                        "fy_scan_comment() failed");
+
+                       tabs_allowed = (fyp->flow_level || !fyp->simple_key_allowed) || fyp_tabsize(fyp);
                }
 
                c = fy_parse_peek(fyp);
@@ -1039,18 +1142,26 @@ int fy_scan_to_next_token(struct fy_parser *fyp)
                fy_advance(fyp, c);
 
                /* may start simple key (in block ctx) */
-               if (!fyp->flow_level) {
+               if (!fyp->flow_level && !fyp->simple_key_allowed) {
                        fyp->simple_key_allowed = true;
+                       tabs_allowed = fyp->flow_level || !fyp->simple_key_allowed || fyp_tabsize(fyp);
                        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
                }
        }
 
        fyp_scan_debug(fyp, "%s: no-next-token", __func__);
+       return 0;
 
+err_out:
+       rc = -1;
 err_out_rc:
        return rc;
 
 done:
+       rc = fy_reader_input_scan_token_mark(fyr);
+       fyp_error_check(fyp, !rc, err_out_rc,
+                       "fy_reader_input_scan_token_mark() failed");
+
        fyp_scan_debug(fyp, "%s: next token starts with c='%s'", __func__,
                        fy_utf8_format_a(fy_parse_peek(fyp), fyue_singlequote));
        return 0;
@@ -1091,6 +1202,12 @@ static void fy_purge_required_simple_key_report(struct fy_parser *fyp,
                        "could not find expected ':'");
 }
 
+static inline bool
+fy_any_simple_keys(struct fy_parser *fyp)
+{
+       return !fy_simple_key_list_empty(&fyp->simple_keys);
+}
+
 static int fy_purge_stale_simple_keys(struct fy_parser *fyp, bool *did_purgep,
                enum fy_token_type next_type)
 {
@@ -1222,9 +1339,9 @@ int fy_parse_unroll_indent(struct fy_parser *fyp, int column)
                fyp_scan_debug(fyp, "unrolling: %d/%d", fyp->indent, column);
 
                /* create a block end token */
-               fyt = fy_token_queue(fyp, FYTT_BLOCK_END, fy_fill_atom_a(fyp, 0));
+               fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_BLOCK_END, 0);
                fyp_error_check(fyp, fyt, err_out,
-                               "fy_token_queue() failed");
+                               "fy_token_queue_simple() failed");
 
                rc = fy_pop_indent(fyp);
                fyp_error_check(fyp, !rc, err_out,
@@ -1321,9 +1438,11 @@ int fy_save_simple_key(struct fy_parser *fyp, struct fy_mark *mark, struct fy_ma
        fyp_error_check(fyp, fyt && mark && end_mark, err_out,
                        "illegal arguments to fy_save_simple_key");
 
-       rc = fy_purge_stale_simple_keys(fyp, &did_purge, next_type);
-       fyp_error_check(fyp, !rc, err_out_rc,
-               "fy_purge_stale_simple_keys() failed");
+       if (fy_any_simple_keys(fyp)) {
+               rc = fy_purge_stale_simple_keys(fyp, &did_purge, next_type);
+               fyp_error_check(fyp, !rc, err_out_rc,
+                       "fy_purge_stale_simple_keys() failed");
+       }
 
        /* if no simple key is allowed, don't save */
        if (!fyp->simple_key_allowed) {
@@ -1483,9 +1602,9 @@ int fy_fetch_stream_start(struct fy_parser *fyp)
        fyp->simple_key_allowed = true;
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
 
-       fyt = fy_token_queue(fyp, FYTT_STREAM_START, fy_fill_atom_a(fyp, 0));
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_STREAM_START, 0);
        fyp_error_check(fyp, fyt, err_out,
-                       "fy_token_queue() failed");
+                       "fy_token_queue_simple() failed");
        return 0;
 
 err_out:
@@ -1503,16 +1622,20 @@ int fy_fetch_stream_end(struct fy_parser *fyp)
 
        fy_remove_all_simple_keys(fyp);
 
-       rc = fy_parse_unroll_indent(fyp, -1);
-       fyp_error_check(fyp, !rc, err_out_rc,
-                       "fy_parse_unroll_indent() failed");
+       if (fyp_block_mode(fyp)) {
+               rc = fy_parse_unroll_indent(fyp, -1);
+               fyp_error_check(fyp, !rc, err_out_rc,
+                               "fy_parse_unroll_indent() failed");
+       }
 
-       fyt = fy_token_queue(fyp, FYTT_STREAM_END, fy_fill_atom_a(fyp, 0));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_STREAM_END, 0);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        return 0;
 
+err_out:
+       rc = -1;
 err_out_rc:
        return rc;
 }
@@ -1794,11 +1917,11 @@ int fy_scan_directive(struct fy_parser *fyp)
        struct fy_token *fyt;
        int i, lastc;
 
-       if (!fy_parse_strcmp(fyp, "YAML")) {
-               advance = 4;
+       if (!fy_parse_strcmp(fyp, "YAML") && fy_is_ws(fy_parse_peek_at(fyp, 4))) {
+               advance = 5;
                type = FYTT_VERSION_DIRECTIVE;
-       } else if (!fy_parse_strcmp(fyp, "TAG")) {
-               advance = 3;
+       } else if (!fy_parse_strcmp(fyp, "TAG") && fy_is_ws(fy_parse_peek_at(fyp, 3))) {
+               advance = 4;
                type = FYTT_TAG_DIRECTIVE;
        } else {
                /* skip until linebreak (or #) */
@@ -1837,14 +1960,6 @@ int fy_scan_directive(struct fy_parser *fyp)
        /* advance */
        fy_advance_by(fyp, advance);
 
-       /* the next must be space */
-       c = fy_parse_peek(fyp);
-
-       FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
-                       fy_is_ws(c), err_out,
-                       "missing space in %s directive",
-                               type == FYTT_VERSION_DIRECTIVE ? "YAML" : "TAG");
-
        /* skip white space */
        while (fy_is_ws(c = fy_parse_peek(fyp)))
                fy_advance(fyp, c);
@@ -1937,9 +2052,11 @@ int fy_fetch_directive(struct fy_parser *fyp)
 
        fy_remove_all_simple_keys(fyp);
 
-       rc = fy_parse_unroll_indent(fyp, -1);
-       fyp_error_check(fyp, !rc, err_out_rc,
-                       "fy_parse_unroll_indent() failed");
+       if (fyp_block_mode(fyp)) {
+               rc = fy_parse_unroll_indent(fyp, -1);
+               fyp_error_check(fyp, !rc, err_out_rc,
+                               "fy_parse_unroll_indent() failed");
+       }
 
        rc = fy_scan_directive(fyp);
        fyp_error_check(fyp, !rc, err_out_rc,
@@ -1958,16 +2075,18 @@ int fy_fetch_document_indicator(struct fy_parser *fyp, enum fy_token_type type)
 
        fy_remove_all_simple_keys(fyp);
 
-       rc = fy_parse_unroll_indent(fyp, -1);
-       fyp_error_check(fyp, !rc, err_out_rc,
-                       "fy_parse_unroll_indent() failed");
+       if (fyp_block_mode(fyp)) {
+               rc = fy_parse_unroll_indent(fyp, -1);
+               fyp_error_check(fyp, !rc, err_out_rc,
+                               "fy_parse_unroll_indent() failed");
+       }
 
        fyp->simple_key_allowed = false;
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
 
-       fyt = fy_token_queue(fyp, type, fy_fill_atom_a(fyp, 3));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, type, 3);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        /* skip whitespace after the indicator */
        while (fy_is_ws(c = fy_parse_peek(fyp)))
@@ -1975,16 +2094,23 @@ int fy_fetch_document_indicator(struct fy_parser *fyp, enum fy_token_type type)
 
        return 0;
 
+err_out:
+       rc = -1;
 err_out_rc:
        return rc;
 }
 
-static inline bool fy_flow_indent_check(struct fy_parser *fyp)
+static inline bool fy_flow_indent_check_internal(struct fy_parser *fyp, int column, int indent)
 {
-       return (!fyp->flow_level || fyp_column(fyp) > fyp->indent) ||
+       return (!fyp->flow_level || column > indent) ||
                ((fyp->cfg.flags & FYPCF_SLOPPY_FLOW_INDENTATION) && fyp->flow_level);
 }
 
+static inline bool fy_flow_indent_check(struct fy_parser *fyp)
+{
+       return fy_flow_indent_check_internal(fyp, fyp_column(fyp), fyp->indent);
+}
+
 static inline bool fy_block_indent_check(struct fy_parser *fyp)
 {
        return fyp->flow_level > 0 || fyp_column(fyp) > fyp->indent;
@@ -2012,9 +2138,9 @@ int fy_fetch_flow_collection_mark_start(struct fy_parser *fyp, int c)
 
        fy_get_simple_key_mark(fyp, &skm);
 
-       fyt = fy_token_queue(fyp, type, fy_fill_atom_a(fyp, 1));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, type, 1);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        rc = fy_save_simple_key_mark(fyp, &skm, type, NULL);
        fyp_error_check(fyp, !rc, err_out_rc,
@@ -2106,9 +2232,9 @@ int fy_fetch_flow_collection_mark_end(struct fy_parser *fyp, int c)
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n",
                                fyp->simple_key_allowed ? "true" : "false");
 
-       fyt = fy_token_queue(fyp, type, fy_fill_atom_a(fyp, 1));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, type, 1);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        if (fyp->parse_flow_only && fyp->flow_level == 0) {
                rc = fy_fetch_stream_end(fyp);
@@ -2134,15 +2260,17 @@ int fy_fetch_flow_collection_mark_end(struct fy_parser *fyp, int c)
 
        /* we must be a key, purge */
        if (c == ':') {
-               rc = fy_purge_stale_simple_keys(fyp, &did_purge, type);
-               fyp_error_check(fyp, !rc, err_out_rc,
-                               "fy_purge_stale_simple_keys() failed");
+               if (fy_any_simple_keys(fyp)) {
+                       rc = fy_purge_stale_simple_keys(fyp, &did_purge, type);
+                       fyp_error_check(fyp, !rc, err_out_rc,
+                                       "fy_purge_stale_simple_keys() failed");
 
-               /* if we did purge and the the list is now empty, we're hosed */
-               if (did_purge && fy_simple_key_list_empty(&fyp->simple_keys)) {
-                       FYP_PARSE_ERROR(fyp, 0, 1, FYEM_SCAN,
-                                       "invalid multiline flow %s key ", typestr);
-                       goto err_out;
+                       /* if we did purge and the the list is now empty, we're hosed */
+                       if (did_purge && fy_simple_key_list_empty(&fyp->simple_keys)) {
+                               FYP_PARSE_ERROR(fyp, 0, 1, FYEM_SCAN,
+                                               "invalid multiline flow %s key ", typestr);
+                               goto err_out;
+                       }
                }
        }
 
@@ -2170,9 +2298,9 @@ int fy_fetch_flow_collection_entry(struct fy_parser *fyp, int c)
        /* transform '? a,' to '? a: ,' */
        if (fyp->pending_complex_key_column >= 0) {
 
-               fyt = fy_token_queue(fyp, FYTT_VALUE, fy_fill_atom_a(fyp, 0));
+               fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_VALUE, 0);
                fyp_error_check(fyp, fyt, err_out,
-                               "fy_token_queue() failed");
+                               "fy_token_queue_simple() failed");
 
                fyp->pending_complex_key_column = -1;
 
@@ -2186,9 +2314,10 @@ int fy_fetch_flow_collection_entry(struct fy_parser *fyp, int c)
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
 
        fyt_last = fy_token_list_tail(&fyp->queued_tokens);
-       fyt = fy_token_queue(fyp, type, fy_fill_atom_a(fyp, 1));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, type, 1);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        /* the comment indicator must have at least a space */
        c = fy_parse_peek(fyp);
@@ -2227,6 +2356,8 @@ int fy_fetch_block_entry(struct fy_parser *fyp, int c)
        struct fy_mark mark;
        struct fy_simple_key *fysk;
        struct fy_token *fyt;
+       int adv, tab_adv;
+       bool indentation, found_tab;
 
        fyp_error_check(fyp, c == '-', err_out,
                        "illegal block entry");
@@ -2253,17 +2384,16 @@ int fy_fetch_block_entry(struct fy_parser *fyp, int c)
        /* we have to save the start mark */
        fy_get_mark(fyp, &mark);
 
-       if (!fyp->flow_level && fyp->indent < fyp_column(fyp)) {
+       if (fyp_block_mode(fyp) && fyp->indent < fyp_column(fyp)) {
 
                /* push the new indent level */
                rc = fy_push_indent(fyp, fyp_column(fyp), false, fyp_line(fyp));
                fyp_error_check(fyp, !rc, err_out_rc,
                                "fy_push_indent() failed");
 
-               fyt = fy_token_queue_internal(fyp, &fyp->queued_tokens,
-                               FYTT_BLOCK_SEQUENCE_START, fy_fill_atom_a(fyp, 0));
-               fyp_error_check(fyp, fyt, err_out_rc,
-                               "fy_token_queue_internal() failed");
+               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 (c == '-' && fyp->flow_level) {
@@ -2296,12 +2426,37 @@ int fy_fetch_block_entry(struct fy_parser *fyp, int c)
        fyp->simple_key_allowed = true;
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
 
-       fyt = fy_token_queue(fyp, FYTT_BLOCK_ENTRY, fy_fill_atom_a(fyp, 1));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_BLOCK_ENTRY, 1);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        /* special case for allowing whitespace (including tabs) after - */
-       if (fy_is_ws(c = fy_parse_peek(fyp)))
+       found_tab = false;
+
+       /* scan forward, keeping track if we found a tab */
+       adv = 0;
+       tab_adv = -1;
+       while (fy_is_ws(c = fy_parse_peek_at(fyp, adv))) {
+               if (!found_tab && fy_is_tab(c)) {
+                       found_tab = true;
+                       tab_adv = adv;
+               }
+               adv++;
+       }
+
+       if (found_tab) {
+               indentation = fy_utf8_strchr("?:|>", c) ||
+                               (c == '-' && fyp_is_blankz(fyp, fy_parse_peek_at(fyp, adv + 1)));
+
+               /* any kind of block indentation is not allowed */
+               FYP_PARSE_ERROR_CHECK(fyp, tab_adv, 1, FYEM_SCAN,
+                               !indentation, err_out,
+                               "cannot use tab for indentation of block entry");
+               fy_advance_by(fyp, tab_adv + 1);
+       }
+
+       /* now chomp spaces only afterwards */
+       while (fy_is_space(c = fy_parse_peek(fyp)))
                fy_advance(fyp, c);
 
        return 0;
@@ -2337,17 +2492,16 @@ int fy_fetch_key(struct fy_parser *fyp, int c)
                        fyp->flow_level || fyp->simple_key_allowed, err_out,
                        "invalid mapping key (not allowed in this context)");
 
-       if (!fyp->flow_level && fyp->indent < fyp_column(fyp)) {
+       if (fyp_block_mode(fyp) && fyp->indent < fyp_column(fyp)) {
 
                /* push the new indent level */
                rc = fy_push_indent(fyp, fyp_column(fyp), true, fyp_line(fyp));
                fyp_error_check(fyp, !rc, err_out_rc,
                                "fy_push_indent() failed");
 
-               fyt = fy_token_queue_internal(fyp, &fyp->queued_tokens,
-                               FYTT_BLOCK_MAPPING_START, fy_fill_atom_a(fyp, 0));
-               fyp_error_check(fyp, fyt, err_out_rc,
-                               "fy_token_queue_internal() failed");
+               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");
        }
 
        rc = fy_remove_simple_key(fyp, FYTT_KEY);
@@ -2361,9 +2515,11 @@ int fy_fetch_key(struct fy_parser *fyp, int c)
        fyp_scan_debug(fyp, "pending_complex_key_column %d",
                        fyp->pending_complex_key_column);
 
-       fyt = fy_token_queue(fyp, FYTT_KEY, fy_fill_atom_a(fyp, 1), fyp->flow_level);
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_KEY, 1);
        fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+                       "fy_token_queue_simple() failed");
+       /* extra KEY data */
+       fyt->key.flow_level = fyp->flow_level;
 
        fyp->simple_key_allowed = target_simple_key_allowed;
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
@@ -2398,7 +2554,6 @@ int fy_fetch_value(struct fy_parser *fyp, int c)
        struct fy_simple_key *fysk = NULL;
        struct fy_mark mark, mark_insert, mark_end_insert;
        struct fy_token *fyt_insert, *fyt;
-       struct fy_atom handle;
        bool target_simple_key_allowed, is_complex, has_bmap;
        bool push_bmap_start, push_key_only, did_purge, final_complex_key;
        bool is_multiline __FY_DEBUG_UNUSED__;
@@ -2413,7 +2568,40 @@ int fy_fetch_value(struct fy_parser *fyp, int c)
                        "JSON considers keys when not in mapping context invalid");
 
        /* special handling for :: weirdness */
-       fyp->colon_follows_colon = fyp->flow_level > 0 && fy_parse_peek_at(fyp, 1) == ':';
+       if (!fyp_json_mode(fyp) && fyp->flow_level > 0) {
+               int adv, nextc, nextcol, tabsize, indent;
+
+               /* this requires some explanation...
+                * we need to detect x::x, x: :x, and x:\n:x as the same
+                */
+               adv = 1;
+               indent = fyp->indent;
+               nextcol = fyp_column(fyp) + 1;
+               tabsize = fyp_tabsize(fyp);
+
+               while ((nextc = fy_parse_peek_at(fyp, adv)) > 0) {
+
+                       if (fyp_is_lb(fyp, nextc))
+                               nextcol = 0;
+                       else if (fy_is_tab(nextc)) {
+                               if (tabsize)
+                                       nextcol += tabsize - (nextcol % tabsize);
+                               else
+                                       nextcol++;
+                       } else if (fy_is_space(nextc))
+                               nextcol++;
+                       else {
+                               if (!fy_flow_indent_check_internal(fyp, nextcol, indent))
+                                       nextc = -1;
+                               break;
+                       }
+
+                       adv++;
+               }
+
+               fyp->colon_follows_colon = nextc == ':';
+       } else
+               fyp->colon_follows_colon = false;
 
        fy_get_mark(fyp, &mark);
 
@@ -2423,9 +2611,11 @@ int fy_fetch_value(struct fy_parser *fyp, int c)
                        fy_flow_indent_check(fyp), err_out,
                        "wrongly indented mapping value in flow mode");
 
-       rc = fy_purge_stale_simple_keys(fyp, &did_purge, FYTT_VALUE);
-       fyp_error_check(fyp, !rc, err_out_rc,
-                       "fy_purge_stale_simple_keys() failed");
+       if (fy_any_simple_keys(fyp)) {
+               rc = fy_purge_stale_simple_keys(fyp, &did_purge, FYTT_VALUE);
+               fyp_error_check(fyp, !rc, err_out_rc,
+                               "fy_purge_stale_simple_keys() failed");
+       }
 
        /* get the simple key (if available) for the value */
        fysk = fy_simple_key_list_head(&fyp->simple_keys);
@@ -2490,23 +2680,22 @@ int fy_fetch_value(struct fy_parser *fyp, int c)
                fyp_error_check(fyp, !rc, err_out_rc,
                                "fy_push_indent() failed");
 
-               fy_fill_atom_start(fyp, &handle);
-               fy_fill_atom_end(fyp, &handle);
-
-               handle.start_mark = handle.end_mark = mark_insert;
+               fyt = fy_token_queue_simple_internal(fyp, &sk_tl, FYTT_BLOCK_MAPPING_START, 0);
+               fyp_error_check(fyp, fyt, err_out,
+                               "fy_token_queue_simple_internal() failed");
 
-               /* and the block mapping start */
-               fyt = fy_token_queue_internal(fyp, &sk_tl, FYTT_BLOCK_MAPPING_START, &handle);
-               fyp_error_check(fyp, fyt, err_out_rc,
-                               "fy_token_queue_internal() failed");
+               /* update with this mark */
+               fyt->handle.start_mark = fyt->handle.end_mark = mark_insert;
        }
 
        if (push_bmap_start || push_key_only) {
 
-               fyt = fy_token_queue_internal(fyp, &sk_tl, FYTT_KEY, fy_fill_atom_a(fyp, 0), fyp->flow_level);
-               fyp_error_check(fyp, fyt, err_out_rc,
-                               "fy_token_queue_internal() failed");
+               fyt = fy_token_queue_simple_internal(fyp, &sk_tl, FYTT_KEY, 0);
+               fyp_error_check(fyp, fyt, err_out,
+                               "fy_token_queue_simple_internal() failed");
 
+               /* update with the flow level */
+               fyt->key.flow_level = fyp->flow_level;
        }
 
        fyp_debug_dump_token(fyp, fyt_insert, "insert-token: ");
@@ -2526,9 +2715,9 @@ int fy_fetch_value(struct fy_parser *fyp, int c)
 
        target_simple_key_allowed = fysk ? false : !fyp->flow_level;
 
-       fyt = fy_token_queue(fyp, FYTT_VALUE, fy_fill_atom_a(fyp, 1));
-       fyp_error_check(fyp, fyt, err_out_rc,
-                       "fy_token_queue() failed");
+       fyt = fy_token_queue_simple(fyp, &fyp->queued_tokens, FYTT_VALUE, 1);
+       fyp_error_check(fyp, fyt, err_out,
+                       "fy_token_queue_simple() failed");
 
        fyp->simple_key_allowed = target_simple_key_allowed;
        fyp_scan_debug(fyp, "simple_key_allowed -> %s\n", fyp->simple_key_allowed ? "true" : "false");
@@ -2806,7 +2995,7 @@ err_out_rc:
 }
 
 int fy_scan_block_scalar_indent(struct fy_parser *fyp, int indent, int *breaks, int *breaks_length,
-                               int *presentation_breaks_length, int *first_break_length)
+                               int *presentation_breaks_length, int *first_break_length, int *lastc)
 {
        int c, max_indent = 0, min_indent, break_length;
 
@@ -2825,13 +3014,19 @@ int fy_scan_block_scalar_indent(struct fy_parser *fyp, int indent, int *breaks,
                /* skip over indentation */
 
                if (!fyp_tabsize(fyp)) {
-                       while ((c = fy_parse_peek(fyp)) == ' ' &&
-                               (!indent || fyp_column(fyp) < indent))
+                       /* we must respect the enclosed indent */
+                       while (fyp_column(fyp) <= fyp->indent && fy_is_ws(c = fy_parse_peek(fyp))) {
+                               FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
+                                               !fy_is_tab(c), err_out,
+                                               "invalid tab character as indent instead of space");
                                fy_advance(fyp, c);
+                       }
 
-                       FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
-                                       c != '\t' || !(!indent && fyp_column(fyp) < indent), err_out,
-                                       "invalid tab character as indent instead of space");
+                       /* skip over spaces only */
+                       while ((c = fy_parse_peek(fyp)) == ' ' &&
+                                       (!indent || fyp_column(fyp) < indent)) {
+                               fy_advance(fyp, c);
+                       }
                } else {
                        while (fy_is_ws((c = fy_parse_peek(fyp))) &&
                                (!indent || fyp_column(fyp) < indent))
@@ -2841,9 +3036,11 @@ int fy_scan_block_scalar_indent(struct fy_parser *fyp, int indent, int *breaks,
                if (fyp_column(fyp) > max_indent)
                        max_indent = fyp_column(fyp);
 
-               /* non-empty line? */
-               if (!fyp_is_lb(fyp, c))
+               /* non-empty line or EOF */
+               if (!fyp_is_lb(fyp, c)) {
+                       *lastc = c;
                        break;
+               }
 
                fy_advance(fyp, c);
 
@@ -2881,7 +3078,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
        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 pending_nl;
+       bool pending_nl, ends_with_eof, starts_with_eof;
        struct fy_token *fyt;
        size_t length, line_length, trailing_ws, trailing_breaks_length;
        size_t leading_ws;
@@ -2986,6 +3183,8 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
 
        fy_fill_atom_start(fyp, &handle);
 
+       starts_with_eof = c < 0;
+
        current_indent = fyp->indent >= 0 ? fyp->indent : 0;
        indent = increment ? current_indent + increment : 0;
 
@@ -3001,13 +3200,12 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
        ends_with_lb = false;
        trailing_lb = false;
 
-       new_indent = fy_scan_block_scalar_indent(fyp, indent, &breaks, &breaks_length, &presentation_breaks_length, &first_break_length);
+       new_indent = fy_scan_block_scalar_indent(fyp, indent, &breaks, &breaks_length, &presentation_breaks_length, &first_break_length, &lastc);
        fyp_error_check(fyp, new_indent >= 0, err_out,
                        "fy_scan_block_scalar_indent() failed");
 
        length = breaks_length;
        length += presentation_breaks_length;
-
        indent = new_indent;
 
        doc_start_end_detected = false;
@@ -3024,7 +3222,6 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
        chomp_amt = increment ? (unsigned int)(current_indent + increment) : (unsigned int)-1;
 
        actual_lb_length = 1;
-       lastc = -1;
        while ((c = fy_parse_peek(fyp)) > 0 && fyp_column(fyp) >= indent) {
 
                lastc = c;
@@ -3083,7 +3280,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
                        fy_advance(fyp, c);
 
                        has_lb = true;
-                       new_indent = fy_scan_block_scalar_indent(fyp, indent, &breaks, &breaks_length, &presentation_breaks_length, &first_break_length);
+                       new_indent = fy_scan_block_scalar_indent(fyp, indent, &breaks, &breaks_length, &presentation_breaks_length, &first_break_length, &lastc);
                        fyp_error_check(fyp, new_indent >= 0, err_out,
                                        "fy_scan_block_scalar_indent() failed");
                        if (fy_is_lb_LS_PS(c))
@@ -3091,7 +3288,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
                } else {
                        has_lb = false;
                        new_indent = indent;
-                       chomp = FYAC_STRIP;
+                       // was chomp = FYAC_STRIP, very very wrong
 
                        breaks = 0;
                        breaks_length = 0;
@@ -3099,6 +3296,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
                        first_break_length = 0;
 
                        actual_lb_length = 0;
+
                }
 
                if (is_literal) {
@@ -3171,7 +3369,6 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
 
 
                length += prefix_length + line_length + suffix_length;
-
                indent = new_indent;
 
                prev_empty_line = empty_line;
@@ -3198,6 +3395,9 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
                goto err_out;
        }
 
+       /* are we ended with EOF? */
+       ends_with_eof = starts_with_eof || (c == FYUG_EOF && !fyp_is_lb(fyp, lastc) && !breaks);
+
        /* detect wrongly indented block scalar */
        if (c != FYUG_EOF && !(!empty || fyp_column(fyp) <= fyp->indent || c == '#' || doc_start_end_detected)) {
                FYP_MARK_ERROR(fyp, &handle.start_mark, &handle.end_mark, FYEM_SCAN,
@@ -3216,7 +3416,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
 
        switch (chomp) {
        case FYAC_CLIP:
-               if (pending_nl) {
+               if (pending_nl || (!starts_with_eof && ends_with_eof)) {
                        if (actual_lb_length <= 2)
                                length += 1;
                        else
@@ -3231,18 +3431,20 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
                                ends_with_ws = true;
                }
                break;
-       case FYAC_KEEP: {
-               length += (pending_nl ? actual_lb_length : 0) + breaks + presentation_breaks_length;
+       case FYAC_KEEP:
+               if (pending_nl || (!starts_with_eof && ends_with_eof))
+                       length += actual_lb_length;
+
+               length += breaks + presentation_breaks_length;
 
                trailing_lb = trailing_breaks_length > 0;
-               if (pending_nl || trailing_breaks_length) {
+               if (pending_nl || (!starts_with_eof && ends_with_eof) || trailing_breaks_length) {
                        ends_with_lb = true;
                        ends_with_ws = false;
                } else if (fy_is_ws(lastc)) {
                        ends_with_ws = true;
                        ends_with_lb = false;
                }
-                       }
                break;
        case FYAC_STRIP:
                ends_with_lb = false;
@@ -3273,6 +3475,7 @@ int fy_fetch_block_scalar(struct fy_parser *fyp, bool is_literal, int c)
        handle.lb_mode = fyp_lb_mode(fyp);
        handle.fws_mode = fyp_fws_mode(fyp);
        handle.tabsize = fyp_tabsize(fyp);
+       handle.ends_with_eof = ends_with_eof;
 
 #ifdef ATOM_SIZE_CHECK
        tlength = fy_atom_format_text_length(&handle);
@@ -3318,7 +3521,7 @@ int fy_reader_fetch_flow_scalar_handle(struct fy_reader *fyr, int c, int indent,
 {
        size_t length;
        int code_length, i = 0, j, end_c, last_line, lastc;
-       int breaks_found, blanks_found, break_run, total_code_length, total_digits;
+       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;
@@ -3522,7 +3725,6 @@ int fy_reader_fetch_flow_scalar_handle(struct fy_reader *fyr, int c, int indent,
                                if (unicode_esc) {
 
                                        total_code_length = 0;
-                                       total_digits = 0;
                                        j = 0;
                                        hi_surrogate = lo_surrogate = 0;
                                        for (;;) {
@@ -3548,7 +3750,6 @@ int fy_reader_fetch_flow_scalar_handle(struct fy_reader *fyr, int c, int indent,
                                                }
 
                                                total_code_length += code_length;
-                                               total_digits += code_length;
                                                j++;
 
                                                /* 0x10000 + (HI - 0xd800) * 0x400 + (LO - 0xdc00) */
@@ -3647,6 +3848,13 @@ int fy_reader_fetch_flow_scalar_handle(struct fy_reader *fyr, int c, int indent,
 
                        break_run = 0;
 
+                       /* check for tab used as indentation */
+                       if (!fy_reader_tabsize(fyr) && fy_is_tab(c)) {
+                               FYR_PARSE_ERROR_CHECK(fyr, 0, 1, FYEM_SCAN,
+                                               fy_reader_column(fyr) > indent, err_out,
+                                               "invalid tab used as indentation");
+                       }
+
                        fy_reader_advance(fyr, c);
 
                        if (fy_reader_is_lb(fyr, c)) {
@@ -3698,7 +3906,12 @@ int fy_reader_fetch_flow_scalar_handle(struct fy_reader *fyr, int c, int indent,
        handle->ends_with_lb = ends_with_lb;
        handle->trailing_lb = trailing_lb;
        handle->size0 = length == 0;
+       handle->valid_anchor = false;
+       handle->json_mode = fy_reader_json_mode(fyr);
+       handle->lb_mode = fy_reader_lb_mode(fyr);
+       handle->fws_mode = fy_reader_flow_ws_mode(fyr);
        handle->tabsize = fy_reader_tabsize(fyr);
+       handle->ends_with_eof = false;  /* flow scalars never end with EOF and be valid */
 
        /* skip over block scalar end */
        fy_reader_advance_by(fyr, 1);
@@ -3734,7 +3947,7 @@ int fy_reader_fetch_plain_scalar_handle(struct fy_reader *fyr, int c, int indent
        bool has_leading_blanks;
        bool last_ptr;
        struct fy_mark mark, last_mark;
-       bool is_multiline, has_lb, has_ws;
+       bool is_multiline, has_lb, has_ws, ends_with_eof;
        bool has_json_esc;
 #ifdef ATOM_SIZE_CHECK
        size_t tlength;
@@ -3759,6 +3972,11 @@ int fy_reader_fetch_plain_scalar_handle(struct fy_reader *fyr, int c, int indent
                        flow_level > 0 || !((c == '?' || c == ':') && fy_reader_is_blank_at_offset(fyr, 1)), err_out,
                        "plain scalar cannot start with '%c' followed by blank (in block context)", c);
 
+       /* may not start with - followed by ",[]{}" in flow context */
+       FYR_PARSE_ERROR_CHECK(fyr, 0, 2, FYEM_SCAN,
+                       flow_level == 0 || !(c == '-' && fy_utf8_strchr(",[]{}", fy_reader_peek_at(fyr, 1))), err_out,
+                       "plain scalar cannot start with '%c' followed by ,[]{} (in flow context)", c);
+
        fy_reader_get_mark(fyr, &mark);
 
        fy_reader_fill_atom_start(fyr, handle);
@@ -3849,7 +4067,7 @@ int fy_reader_fetch_plain_scalar_handle(struct fy_reader *fyr, int c, int indent
                                if (fy_reader_is_blankz(fyr, nextc)) {
                                        /* super rare case :: not followed by space  */
                                        /* :: not followed by space */
-                                       if (lastc != ':' || fy_is_ws(nextc))
+                                       if (lastc != ':' || fy_reader_is_blankz(fyr, nextc))
                                                break;
                                }
 
@@ -3961,6 +4179,7 @@ int fy_reader_fetch_plain_scalar_handle(struct fy_reader *fyr, int c, int indent
                        "plain scalar is malformed UTF8");
                goto err_out;
        }
+       ends_with_eof = c == FYUG_EOF && !fy_reader_is_lb(fyr, lastc);
 
        is_multiline = handle->end_mark.line > handle->start_mark.line;
 
@@ -3981,6 +4200,7 @@ int fy_reader_fetch_plain_scalar_handle(struct fy_reader *fyr, int c, int indent
        handle->lb_mode = fy_reader_lb_mode(fyr);
        handle->fws_mode = fy_reader_flow_ws_mode(fyr);
        handle->tabsize = fy_reader_tabsize(fyr);
+       handle->ends_with_eof = ends_with_eof;
 
 #ifdef ATOM_SIZE_CHECK
        tlength = fy_atom_format_text_length(handle);
@@ -4371,13 +4591,27 @@ int fy_fetch_plain_scalar(struct fy_parser *fyp, int c)
        struct fy_atom handle;
        struct fy_simple_key_mark skm;
        struct fy_token *fyt;
-       bool is_multiline, is_complex;
+       bool is_multiline, is_complex, is_tab_start = false;
+       struct fy_mark tab_mark;
        int rc = -1, i;
 
-       /* may not start with blankz */
-       FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
-                       !(fyp->state == FYPS_BLOCK_MAPPING_VALUE && fy_is_tab(c)), err_out,
-                       "invalid tab as indendation in a mapping");
+       /* Extremely bad case, a tab... so, either an indentation or separation space in block mode */
+       if (!fyp->flow && fy_is_tab(c)) {
+
+               fy_get_mark(fyp, &tab_mark);
+               is_tab_start = true;
+
+               /* skip all whitespace now */
+               fy_reader_skip_ws(fyp->reader);
+               c = fy_parse_peek(fyp);
+
+               /* if it's a linebreak or a comment start, just try again */
+               if (fyp_is_lb(fyp, c) || c == '#') {
+                       /* will need to scan more */
+                       fyp->token_activity_counter++;
+                       return 0;
+               }
+       }
 
        /* check indentation */
        FYP_PARSE_ERROR_CHECK(fyp, 0, 1, FYEM_SCAN,
@@ -4409,9 +4643,9 @@ int fy_fetch_plain_scalar(struct fy_parser *fyp, int c)
                return 0;
        }
 
-       if (is_multiline && !fyp->flow_level && !is_complex) {
+       if (!fyp->flow_level && !is_complex && (is_multiline || is_tab_start)) {
                /* due to the weirdness with simple keys scan forward
-               * until a linebreak, ';', or anything else */
+               * until a linebreak, ':', or anything else */
                for (i = 0; ; i++) {
                        c = fy_parse_peek_at(fyp, i);
                        if (c < 0 || (c == ':' && fy_is_blankz_at_offset(fyp, i + 1)) ||
@@ -4421,8 +4655,14 @@ int fy_fetch_plain_scalar(struct fy_parser *fyp, int c)
 
                /* if we're a key, that's invalid */
                if (c == ':') {
-                       FYP_MARK_ERROR(fyp, &handle.start_mark, &handle.end_mark, FYEM_SCAN,
-                                       "invalid multiline plain key");
+
+                       if (is_multiline)
+                               FYP_MARK_ERROR(fyp, &handle.start_mark, &handle.end_mark, FYEM_SCAN,
+                                               "invalid multiline plain key");
+                       else
+                               FYP_MARK_ERROR(fyp, &tab_mark, &tab_mark, FYEM_SCAN,
+                                               "invalid tab as indendation in a mapping");
+
                        goto err_out;
                }
        }
@@ -4476,9 +4716,11 @@ int fy_fetch_tokens(struct fy_parser *fyp)
        fyp_error_check(fyp, !rc, err_out_rc,
                        "fy_scan_to_next_token() failed");
 
-       rc = fy_parse_unroll_indent(fyp, fyp_column(fyp));
-       fyp_error_check(fyp, !rc, err_out_rc,
-                       "fy_parse_unroll_indent() failed");
+       if (fyp_block_mode(fyp)) {
+               rc = fy_parse_unroll_indent(fyp, fyp_column(fyp));
+               fyp_error_check(fyp, !rc, err_out_rc,
+                               "fy_parse_unroll_indent() failed");
+       }
 
        c = fy_parse_peek(fyp);
        if (c < 0 || c == '\0') {
@@ -4798,7 +5040,8 @@ err_out:
        return NULL;
 }
 
-struct fy_token *fy_scan_remove(struct fy_parser *fyp, struct fy_token *fyt)
+static inline struct fy_token *
+fy_scan_remove(struct fy_parser *fyp, struct fy_token *fyt)
 {
        if (!fyp || !fyt)
                return NULL;
@@ -4808,9 +5051,13 @@ struct fy_token *fy_scan_remove(struct fy_parser *fyp, struct fy_token *fyt)
        return fyt;
 }
 
-struct fy_token *fy_scan_remove_peek(struct fy_parser *fyp, struct fy_token *fyt)
+static inline struct fy_token *
+fy_scan_remove_peek(struct fy_parser *fyp, struct fy_token *fyt)
 {
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fy_scan_remove(fyp, fyt));
+       if (fyt != NULL) {
+               (void)fy_scan_remove(fyp, fyt);
+               fy_token_unref_rl(fyp->recycled_token_list, fyt);
+       }
 
        return fy_scan_peek(fyp);
 }
@@ -4853,7 +5100,7 @@ struct fy_token *fy_scan(struct fy_parser *fyp)
 
 void fy_scan_token_free(struct fy_parser *fyp, struct fy_token *fyt)
 {
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyt);
+       fy_token_unref_rl(fyp->recycled_token_list, fyt);
 }
 
 int fy_parse_state_push(struct fy_parser *fyp, enum fy_parser_state state)
@@ -4907,8 +5154,8 @@ fy_parse_node(struct fy_parser *fyp, struct fy_token *fyt, bool is_block)
        struct fy_token *anchor = NULL, *tag = NULL;
        const char *handle;
        size_t handle_size;
-       struct fy_atom atom;
        struct fy_token *fyt_td;
+       struct fy_token *fytn;
 
        fyds = fyp->current_document_state;
        assert(fyds);
@@ -4974,11 +5221,16 @@ fy_parse_node(struct fy_parser *fyp, struct fy_token *fyt, bool is_block)
                fye->sequence_start.anchor = anchor;
                fye->sequence_start.tag = tag;
 
-               atom = fyt->handle;
-               atom.end_mark = atom.start_mark;        /* no extent */
-               fye->sequence_start.sequence_start = fy_token_create_rl(fy_parse_recycled_token(fyp), FYTT_BLOCK_SEQUENCE_START, &atom);
-               fyp_error_check(fyp, fye->sequence_start.sequence_start, err_out,
-                               "fy_token_create_rl() failed!");
+               /* allocate and copy in place */
+               fytn = fy_token_alloc_rl(fyp->recycled_token_list);
+               fyp_error_check(fyp, fytn, err_out,
+                               "fy_token_alloc_rl() failed!");
+               fytn->type = FYTT_BLOCK_SEQUENCE_START;
+               fytn->handle = fyt->handle;
+               fytn->handle.end_mark = fytn->handle.start_mark;        /* no extent */
+               fy_input_ref(fytn->handle.fyi);
+
+               fye->sequence_start.sequence_start = fytn;
 
                fy_parse_state_set(fyp, FYPS_INDENTLESS_SEQUENCE_ENTRY);
                goto return_ok;
@@ -5107,8 +5359,8 @@ return_ok:
        return fyep;
 
 err_out:
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), anchor);
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), tag);
+       fy_token_unref_rl(fyp->recycled_token_list, anchor);
+       fy_token_unref_rl(fyp->recycled_token_list, tag);
        fy_parse_eventp_recycle(fyp, fyep);
 
        return NULL;
@@ -5148,7 +5400,7 @@ int fy_parse_stream_start(struct fy_parser *fyp)
        fy_parse_parse_state_log_list_recycle_all(fyp, &fyp->state_stack);
        fy_parse_flow_list_recycle_all(fyp, &fyp->flow_stack);
 
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyp->stream_end_token);
+       fy_token_unref_rl(fyp->recycled_token_list, fyp->stream_end_token);
        fyp->stream_end_token = NULL;
 
        return 0;
@@ -5156,7 +5408,7 @@ int fy_parse_stream_start(struct fy_parser *fyp)
 
 int fy_parse_stream_end(struct fy_parser *fyp)
 {
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), fyp->stream_end_token);
+       fy_token_unref_rl(fyp->recycled_token_list, fyp->stream_end_token);
        fyp->stream_end_token = NULL;
 
        return 0;
@@ -5172,8 +5424,8 @@ static struct fy_eventp *fy_parse_internal(struct fy_parser *fyp)
        enum fy_parser_state orig_state;
        struct fy_token *version_directive;
        struct fy_token_list tag_directives;
-       struct fy_atom atom;
        const struct fy_mark *fym;
+       struct fy_token *fytn;
        char tbuf[16] __FY_DEBUG_UNUSED__;
        int rc;
 
@@ -5406,6 +5658,8 @@ static struct fy_eventp *fy_parse_internal(struct fy_parser *fyp)
                fyp_error_check(fyp, !rc, err_out,
                                "failed to fy_parse_state_push()");
 
+               // update document state with json mode
+               fyds->json_mode = fyp_json_mode(fyp);
                fye->document_start.document_state = fy_document_state_ref(fyds);
                fye->document_start.implicit = fyds->start_implicit;
 
@@ -5586,11 +5840,17 @@ static struct fy_eventp *fy_parse_internal(struct fy_parser *fyp)
 
                fye->type = FYET_SEQUENCE_END;
                if (orig_state == FYPS_INDENTLESS_SEQUENCE_ENTRY) {
-                       atom = fyt->handle;
-                       atom.end_mark = atom.start_mark;
-                       fye->sequence_end.sequence_end = fy_token_create_rl(fy_parse_recycled_token(fyp), FYTT_BLOCK_END, &atom);
-                       fyp_error_check(fyp, fye->sequence_end.sequence_end, err_out,
-                               "fy_token_create_rl() failed!");
+
+                       /* allocate and copy in place */
+                       fytn = fy_token_alloc_rl(fyp->recycled_token_list);
+                       fyp_error_check(fyp, fytn, err_out,
+                                       "fy_token_alloc_rl() failed!");
+                       fytn->type = FYTT_BLOCK_END;
+                       fytn->handle = fyt->handle;
+                       fytn->handle.end_mark = fytn->handle.start_mark;        /* no extent */
+                       fy_input_ref(fytn->handle.fyi);
+
+                       fye->sequence_end.sequence_end = fytn;
                } else
                        fye->sequence_end.sequence_end = fy_scan_remove(fyp, fyt);
 
@@ -5844,11 +6104,16 @@ static struct fy_eventp *fy_parse_internal(struct fy_parser *fyp)
 
                fye->type = FYET_MAPPING_END;
 
-               atom = fyt->handle;
-               atom.end_mark = atom.start_mark;
-               fye->mapping_end.mapping_end = fy_token_create_rl(fy_parse_recycled_token(fyp), FYTT_BLOCK_END, &atom);
-               fyp_error_check(fyp, fye->mapping_end.mapping_end, err_out,
-                       "fy_token_create_rl() failed!");
+               /* allocate and copy in place */
+               fytn = fy_token_alloc_rl(fyp->recycled_token_list);
+               fyp_error_check(fyp, fytn, err_out,
+                               "fy_token_alloc_rl() failed!");
+               fytn->type = FYTT_BLOCK_END;
+               fytn->handle = fyt->handle;
+               fytn->handle.end_mark = fytn->handle.start_mark;        /* no extent */
+               fy_input_ref(fytn->handle.fyi);
+
+               fye->mapping_end.mapping_end = fytn;
 
                return fyep;
 
@@ -6013,8 +6278,8 @@ static struct fy_eventp *fy_parse_internal(struct fy_parser *fyp)
        }
 
 err_out:
-       fy_token_unref_rl(fy_parse_recycled_token(fyp), version_directive);
-       fy_token_list_unref_all_rl(fy_parse_recycled_token(fyp), &tag_directives);
+       fy_token_unref_rl(fyp->recycled_token_list, version_directive);
+       fy_token_list_unref_all_rl(fyp->recycled_token_list, &tag_directives);
        fy_parse_eventp_recycle(fyp, fyep);
        fyp->stream_error = true;
        return NULL;
@@ -6151,11 +6416,11 @@ int fy_parser_set_input_file(struct fy_parser *fyp, const char *file)
                fyic.type = fyit_stream;
                fyic.stream.name = "stdin";
                fyic.stream.fp = stdin;
-               fyic.stream.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
        } else {
                fyic.type = fyit_file;
                fyic.file.filename = file;
        }
+       fyic.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
 
        /* must not be in the middle of something */
        fyp_error_check(fyp, fyp->state == FYPS_NONE || fyp->state == FYPS_END,
@@ -6258,7 +6523,7 @@ int fy_parser_set_input_fp(struct fy_parser *fyp, const char *name, FILE *fp)
        fyic.type = fyit_stream;
        fyic.stream.name = name ? : "<stream>";
        fyic.stream.fp = fp;
-       fyic.stream.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
+       fyic.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
 
        /* must not be in the middle of something */
        fyp_error_check(fyp, fyp->state == FYPS_NONE || fyp->state == FYPS_END,
@@ -6292,6 +6557,39 @@ int fy_parser_set_input_callback(struct fy_parser *fyp, void *user,
        fyic.type = fyit_callback;
        fyic.userdata = user;
        fyic.callback.input = callback;
+       fyic.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
+
+       /* must not be in the middle of something */
+       fyp_error_check(fyp, fyp->state == FYPS_NONE || fyp->state == FYPS_END,
+                       err_out, "parser cannot be reset at state '%s'",
+                               state_txt[fyp->state]);
+
+       fy_parse_input_reset(fyp);
+
+       rc = fy_parse_input_append(fyp, &fyic);
+       fyp_error_check(fyp, !rc, err_out_rc,
+                       "fy_parse_input_append() failed");
+
+       return 0;
+err_out:
+       rc = -1;
+err_out_rc:
+       return rc;
+}
+
+int fy_parser_set_input_fd(struct fy_parser *fyp, int fd)
+{
+       struct fy_input_cfg fyic;
+       int rc;
+
+       if (!fyp || fd < 0)
+               return -1;
+
+       memset(&fyic, 0, sizeof(fyic));
+
+       fyic.type = fyit_fd;
+       fyic.fd.fd = fd;
+       fyic.ignore_stdio = !!(fyp->cfg.flags & FYPCF_DISABLE_BUFFERING);
 
        /* must not be in the middle of something */
        fyp_error_check(fyp, fyp->state == FYPS_NONE || fyp->state == FYPS_END,
@@ -6357,7 +6655,7 @@ struct fy_event *fy_parser_parse(struct fy_parser *fyp)
                return NULL;
 
        if (fyp->fyc) {
-               ret = fy_composer_process_event(fyp->fyc, fyp, &fyep->e);
+               ret = fy_composer_process_event(fyp->fyc, &fyep->e);
                if (ret == FYCR_ERROR) {
                        fyp->stream_error = true;
                        fy_parse_eventp_recycle(fyp, fyep);
@@ -6392,16 +6690,48 @@ struct fy_document_state *fy_parser_get_document_state(struct fy_parser *fyp)
 }
 
 static enum fy_composer_return
-parse_process_event(struct fy_composer *fyc, struct fy_path *path, struct fy_parser *fyp, struct fy_event *fye)
+parse_process_event(struct fy_composer *fyc, struct fy_path *path, struct fy_event *fye)
 {
-       if (!fyp->fyc_cb)
-               return 0;
+       struct fy_parser *fyp = fy_composer_get_cfg_userdata(fyc);
 
-       return fyp->fyc_cb(fyp, fye, path, fy_composer_get_cfg_userdata(fyc));
+       assert(fyp);
+       assert(fyp->fyc_cb);
+       return fyp->fyc_cb(fyp, fye, path, fyp->fyc_userdata);
+}
+
+struct fy_document_builder *
+parse_create_document_builder(struct fy_composer *fyc)
+{
+       struct fy_parser *fyp = fy_composer_get_cfg_userdata(fyc);
+       struct fy_document_builder *fydb = NULL;
+       struct fy_document_builder_cfg cfg;
+       struct fy_document_state *fyds;
+       int rc;
+
+       memset(&cfg, 0, sizeof(cfg));
+       cfg.parse_cfg = fyp->cfg;
+       cfg.diag = fy_diag_ref(fyp->diag);
+
+       fydb = fy_document_builder_create(&cfg);
+       fyp_error_check(fyp, fydb, err_out,
+                       "fy_document_builder_create() failed\n");
+
+       /* start with this document state */
+       fyds = fy_parser_get_document_state(fyp);
+       rc = fy_document_builder_set_in_document(fydb, fyds, true);
+       fyp_error_check(fyp, !rc, err_out,
+                       "fy_document_builder_set_in_document() failed\n");
+
+       return fydb;
+
+err_out:
+       fy_document_builder_destroy(fydb);
+       return NULL;
 }
 
 static const struct fy_composer_ops parser_composer_ops = {
        .process_event = parse_process_event,
+       .create_document_builder = parse_create_document_builder,
 };
 
 int fy_parse_set_composer(struct fy_parser *fyp, fy_parse_composer_cb cb, void *userdata)
@@ -6423,68 +6753,156 @@ int fy_parse_set_composer(struct fy_parser *fyp, fy_parse_composer_cb cb, void *
                        fyp->fyc = NULL;
                }
                fyp->fyc_cb = NULL;
+               fyp->fyc_userdata = NULL;
                return 0;
        }
 
        /* already exists */
        if (fyp->fyc) {
                fyp->fyc_cb = cb;
+               fyp->fyc_userdata = userdata;
                return 0;
        }
 
        /* prepare the composer configuration */
        memset(&ccfg, 0, sizeof(ccfg));
        ccfg.ops = &parser_composer_ops;
-       ccfg.userdata = userdata;
+       ccfg.userdata = fyp;
        ccfg.diag = fy_parser_get_diag(fyp);
        fyp->fyc = fy_composer_create(&ccfg);
        fyp_error_check(fyp, fyp->fyc, err_out,
                        "fy_composer_create() failed");
 
        fyp->fyc_cb = cb;
+       fyp->fyc_userdata = userdata;
 
        return 0;
 err_out:
        return -1;
 }
 
-int fy_parse_compose(struct fy_parser *fyp, fy_parse_composer_cb cb, void *userdata)
+static enum fy_composer_return fy_parse_compose_internal(struct fy_parser *fyp)
 {
+       struct fy_composer *fyc;
+       struct fy_document_iterator *fydi;
+       struct fy_event *fye;
        struct fy_eventp *fyep;
+       struct fy_document *fyd = NULL;
        enum fy_composer_return ret;
-       int rc;
 
-       if (!fyp || !cb)
-               return -1;
+       assert(fyp);
 
-       /* set the composer callback */
-       rc = fy_parse_set_composer(fyp, cb, userdata);
-       fyp_error_check(fyp, !rc, err_out,
-                       "fy_parse_set_composer() failed\n");
+       fyc = fyp->fyc;
+       assert(fyc);
+
+       /* simple, without resolution */
+       if (!(fyp->cfg.flags & FYPCF_RESOLVE_DOCUMENT)) {
+
+               ret = FYCR_OK_STOP;
+               while ((fyep = fy_parse_private(fyp)) != NULL) {
+                       ret = fy_composer_process_event(fyc, &fyep->e);
+                       fy_parse_eventp_recycle(fyp, fyep);
+                       if (ret != FYCR_OK_CONTINUE)
+                               break;
+               }
+               return ret;
+       }
 
-       /* insane but check anyway */
-       assert(fyp->fyc);
+       fydi = fy_document_iterator_create();
+       fyp_error_check(fyp, fydi, err_out,
+                       "fy_document_iterator_create() failed");
 
-       /* pump events */
-       rc = 0;
-       while ((fyep = fy_parse_private(fyp)) != NULL) {
+       /* stream start event generation and processing */
+       fye = fy_document_iterator_stream_start(fydi);
+       fyp_error_check(fyp, fye, err_out,
+                       "fy_document_iterator_stream_start() failed");
+       ret = fy_composer_process_event(fyc, fye);
+       fy_document_iterator_event_free(fydi, fye);
+       fye = NULL;
+       if (ret != FYCR_OK_CONTINUE)
+               goto out;
 
-               /* call the composer */
-               ret = fy_composer_process_event(fyp->fyc, fyp, &fyep->e);
-               fy_parse_eventp_recycle(fyp, fyep);
+       /* convert to document and then process the generator event stream it */
+       while ((fyd = fy_parse_load_document(fyp)) != NULL) {
+
+               /* document start event generation and processing */
+               fye = fy_document_iterator_document_start(fydi, fyd);
+               fyp_error_check(fyp, fye, err_out,
+                               "fy_document_iterator_document_start() failed");
+               ret = fy_composer_process_event(fyc, fye);
+               fy_document_iterator_event_free(fydi, fye);
+               fye = NULL;
+               if (ret != FYCR_OK_CONTINUE)
+                       goto out;
 
-               /* on error stop */
-               if (ret == FYCR_ERROR) {
-                       fyp->stream_error = true;
-                       rc = -1;
-                       break;
+               /* and now process the body */
+               ret = FYCR_OK_CONTINUE;
+               while ((fye = fy_document_iterator_body_next(fydi)) != NULL) {
+                       ret = fy_composer_process_event(fyc, fye);
+                       fy_document_iterator_event_free(fydi, fye);
+                       fye = NULL;
+                       if (ret != FYCR_OK_CONTINUE)
+                               goto out;
                }
 
-               /* on normal requested stop, stop */
-               if (ret == FYCR_OK_STOP)
-                       break;
+               /* document end event generation and processing */
+               fye = fy_document_iterator_document_end(fydi);
+               fyp_error_check(fyp, fye, err_out,
+                               "fy_document_iterator_document_end() failed");
+               ret = fy_composer_process_event(fyc, fye);
+               fy_document_iterator_event_free(fydi, fye);
+               fye = NULL;
+               if (ret != FYCR_OK_CONTINUE)
+                       goto out;
+
+               /* and destroy the document */
+               fy_parse_document_destroy(fyp, fyd);
+               fyd = NULL;
        }
 
+       /* stream end event generation and processing */
+       fye = fy_document_iterator_stream_end(fydi);
+       fyp_error_check(fyp, fye, err_out,
+                       "fy_document_iterator_stream_end() failed");
+       ret = fy_composer_process_event(fyc, fye);
+       fy_document_iterator_event_free(fydi, fye);
+       fye = NULL;
+       if (ret != FYCR_OK_CONTINUE)
+               goto out;
+
+out:
+       /* NULLs are OK */
+       fy_parse_document_destroy(fyp, fyd);
+       fy_document_iterator_destroy(fydi);
+       return ret;
+
+err_out:
+       ret = FYCR_ERROR;
+       goto out;
+}
+
+int fy_parse_compose(struct fy_parser *fyp, fy_parse_composer_cb cb, void *userdata)
+{
+       enum fy_composer_return ret;
+       int rc, rc_out;
+
+       if (!fyp || !cb)
+               return -1;
+
+       /* set the composer callback */
+       rc = fy_parse_set_composer(fyp, cb, userdata);
+       fyp_error_check(fyp, !rc, err_out,
+                       "fy_parse_set_composer() failed\n");
+
+       /* use the composer to parse */
+       ret = fy_parse_compose_internal(fyp);
+       /* on error set the stream error */
+       if (ret == FYCR_ERROR) {
+               fyp->stream_error = true;
+               rc_out = -1;
+       } else
+               rc_out = 0;
+
        /* reset the parser; the composer clear must always succeed */
        fy_parser_reset(fyp);
 
@@ -6493,7 +6911,7 @@ int fy_parse_compose(struct fy_parser *fyp, fy_parse_composer_cb cb, void *userd
        fyp_error_check(fyp, !rc, err_out,
                        "fy_parse_set_composer() failed\n");
 
-       return rc;
+       return rc_out;
 
 err_out:
        return -1;
index 19ff7dd61f0a73b96958604faaeeb169e014688e..df278fc0e8ede491b4268546b67a2a603a4248ae 100644 (file)
@@ -32,6 +32,7 @@
 #include "fy-event.h"
 #include "fy-docstate.h"
 #include "fy-doc.h"
+#include "fy-docbuilder.h"
 #include "fy-emit.h"
 #include "fy-accel.h"
 #include "fy-emit-accum.h"
@@ -199,10 +200,14 @@ struct fy_parser {
        struct fy_indent_list recycled_indent;
        struct fy_simple_key_list recycled_simple_key;
        struct fy_parse_state_log_list recycled_parse_state_log;
-       struct fy_eventp_list recycled_eventp;
        struct fy_flow_list recycled_flow;
+
+       struct fy_eventp_list recycled_eventp;
        struct fy_token_list recycled_token;
 
+       struct fy_eventp_list *recycled_eventp_list;
+       struct fy_token_list *recycled_token_list;
+
        /* the diagnostic object */
        struct fy_diag *diag;
 
@@ -215,6 +220,7 @@ struct fy_parser {
        /* when using the composer interface */
        struct fy_composer *fyc;
        fy_parse_composer_cb fyc_cb;
+       void *fyc_userdata;
 };
 
 static inline struct fy_input *
@@ -265,6 +271,11 @@ static inline enum fy_flow_ws_mode fyp_fws_mode(const struct fy_parser *fyp)
        return fy_reader_flow_ws_mode(fyp->reader);
 }
 
+static inline bool fyp_block_mode(struct fy_parser *fyp)
+{
+       return !fyp_json_mode(fyp) && !fyp->flow_level;
+}
+
 static inline bool fyp_is_lb(const struct fy_parser *fyp, int c)
 {
        assert(fyp);
@@ -371,14 +382,14 @@ fy_parse_strncmp(struct fy_parser *fyp, const char *str, size_t n)
        return fy_reader_strncmp(fyp->reader, str, n);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_parse_peek_at_offset(struct fy_parser *fyp, size_t offset)
 {
        assert(fyp);
        return fy_reader_peek_at_offset(fyp->reader, offset);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_parse_peek_at_internal(struct fy_parser *fyp, int pos, ssize_t *offsetp)
 {
        assert(fyp);
@@ -406,49 +417,49 @@ fy_is_generic_blankz_at_offset(struct fy_parser *fyp, size_t offset)
        return fy_reader_is_generic_blankz(fyp->reader, fy_reader_peek_at_offset(fyp->reader, offset));
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_parse_peek_at(struct fy_parser *fyp, int pos)
 {
        assert(fyp);
        return fy_reader_peek_at_internal(fyp->reader, pos, NULL);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_parse_peek(struct fy_parser *fyp)
 {
        assert(fyp);
        return fy_reader_peek(fyp->reader);
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_advance(struct fy_parser *fyp, int c)
 {
        assert(fyp);
        fy_reader_advance(fyp->reader, c);
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_advance_ws(struct fy_parser *fyp, int c)
 {
        assert(fyp);
        fy_reader_advance_ws(fyp->reader, c);
 }
 
-static inline void
+static FY_ALWAYS_INLINE inline void
 fy_advance_space(struct fy_parser *fyp)
 {
        assert(fyp);
        fy_reader_advance_space(fyp->reader);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_parse_get(struct fy_parser *fyp)
 {
        assert(fyp);
        return fy_reader_get(fyp->reader);
 }
 
-static inline int
+static FY_ALWAYS_INLINE inline int
 fy_advance_by(struct fy_parser *fyp, int count)
 {
        assert(fyp);
@@ -574,12 +585,6 @@ static inline int fy_document_state_version_compare(struct fy_document_state *fy
        return fy_version_compare(fy_document_state_version(fyds), vb);
 }
 
-static inline struct fy_token_list *
-fy_parse_recycled_token(struct fy_parser *fyp)
-{
-       return fyp && !fyp->suppress_recycling ? &fyp->recycled_token : NULL;
-}
-
 int fy_parse_set_composer(struct fy_parser *fyp, fy_parse_composer_cb cb, void *userdata);
 
 #endif
index 948b1c76c317437c349a20a43666ab3b22c5510b..f9d9f99a41e3a4719a194b218763fc65505b825c 100644 (file)
@@ -131,10 +131,13 @@ void fy_path_component_clear_state(struct fy_path_component *fypc)
                                        fy_document_destroy(fypc->map.complex_key);
                                fypc->map.complex_key = NULL;
                        } else {
-                               fy_token_unref(fypc->map.scalar_key);
-                               fypc->map.scalar_key = NULL;
+                               fy_token_unref(fypc->map.scalar.tag);
+                               fy_token_unref(fypc->map.scalar.key);
+                               fypc->map.scalar.tag = NULL;
+                               fypc->map.scalar.key = NULL;
                        }
                }
+               fypc->map.root = true;
                fypc->map.has_key = false;
                fypc->map.await_key = true;
                fypc->map.is_complex_key = false;
@@ -201,6 +204,7 @@ struct fy_path_component *fy_path_component_create_mapping(struct fy_path *fypp)
 
        fypc->type = FYPCT_MAP;
 
+       fypc->map.root = true;
        fypc->map.await_key = true;
        fypc->map.is_complex_key = false;
        fypc->map.accumulating_complex_key = false;
@@ -240,7 +244,13 @@ int fy_path_component_sequence_get_index(struct fy_path_component *fypc)
 struct fy_token *fy_path_component_mapping_get_scalar_key(struct fy_path_component *fypc)
 {
        return fypc && fypc->type == FYPCT_MAP &&
-              fypc->map.has_key && !fypc->map.is_complex_key ? fypc->map.scalar_key : NULL;
+              fypc->map.has_key && !fypc->map.is_complex_key ? fypc->map.scalar.key : NULL;
+}
+
+struct fy_token *fy_path_component_mapping_get_scalar_key_tag(struct fy_path_component *fypc)
+{
+       return fypc && fypc->type == FYPCT_MAP &&
+              fypc->map.has_key && !fypc->map.is_complex_key ? fypc->map.scalar.tag : NULL;
 }
 
 struct fy_document *fy_path_component_mapping_get_complex_key(struct fy_path_component *fypc)
@@ -254,6 +264,54 @@ bool fy_path_component_is_sequence(struct fy_path_component *fypc)
        return fypc && fypc->type == FYPCT_SEQ;
 }
 
+static int fy_path_component_get_text_internal(struct fy_emit_accum *ea, struct fy_path_component *fypc)
+{
+       char *doctxt;
+       const char *text;
+       size_t len;
+
+       switch (fypc->type) {
+       case FYPCT_NONE:
+               abort();
+
+       case FYPCT_MAP:
+
+               /* we don't handle transitionals */
+               if (!fypc->map.has_key || fypc->map.await_key || fypc->map.root)
+                       return -1;
+
+               if (!fypc->map.is_complex_key && fypc->map.scalar.key) {
+                       text = fy_token_get_text(fypc->map.scalar.key, &len);
+                       if (!text)
+                               return -1;
+
+                       if (fypc->map.scalar.key->type == FYTT_ALIAS)
+                               fy_emit_accum_utf8_put_raw(ea, '*');
+                       fy_emit_accum_utf8_write_raw(ea, text, len);
+
+               } else if (fypc->map.complex_key) {
+                       /* complex key */
+                       doctxt = fy_emit_document_to_string(fypc->map.complex_key,
+                               FYECF_WIDTH_INF | FYECF_INDENT_DEFAULT |
+                               FYECF_MODE_FLOW_ONELINE | FYECF_NO_ENDING_NEWLINE);
+                       fy_emit_accum_utf8_write_raw(ea, doctxt, strlen(doctxt));
+                       free(doctxt);
+               }
+               break;
+
+       case FYPCT_SEQ:
+
+               /* not started filling yet */
+               if (fypc->seq.idx < 0)
+                       return -1;
+
+               fy_emit_accum_utf8_printf_raw(ea, "%d", fypc->seq.idx);
+               break;
+       }
+
+       return 0;
+}
+
 static int fy_path_get_text_internal(struct fy_emit_accum *ea, struct fy_path *fypp)
 {
        struct fy_path_component *fypc;
@@ -283,7 +341,7 @@ static int fy_path_get_text_internal(struct fy_emit_accum *ea, struct fy_path *f
 
                case FYPCT_MAP:
 
-                       if (!fypc->map.has_key)
+                       if (!fypc->map.has_key || fypc->map.root)
                                break;
 
                        /* key reference ? wrap in .key(X)*/
@@ -296,12 +354,12 @@ static int fy_path_get_text_internal(struct fy_emit_accum *ea, struct fy_path *f
 
                        if (!fypc->map.is_complex_key) {
 
-                               if (fypc->map.scalar_key) {
-                                       text = fy_token_get_text(fypc->map.scalar_key, &len);
+                               if (fypc->map.scalar.key) {
+                                       text = fy_token_get_text(fypc->map.scalar.key, &len);
                                        assert(text);
                                        if (!text)
                                                return -1;
-                                       if (fypc->map.scalar_key->type == FYTT_ALIAS)
+                                       if (fypc->map.scalar.key->type == FYTT_ALIAS)
                                                fy_emit_accum_utf8_put_raw(ea, '*');
                                        fy_emit_accum_utf8_write_raw(ea, text, len);
                                } else {
@@ -377,6 +435,32 @@ err_out:
        return path;
 }
 
+char *fy_path_component_get_text(struct fy_path_component *fypc)
+{
+       struct fy_emit_accum ea;        /* use an emit accumulator */
+       char *text = NULL;
+       size_t len;
+       int rc;
+
+       /* no inplace buffer; we will need the malloc'ed contents anyway */
+       fy_emit_accum_init(&ea, NULL, 0, 0, fylb_cr_nl);
+
+       fy_emit_accum_start(&ea, 0, fylb_cr_nl);
+
+       rc = fy_path_component_get_text_internal(&ea, fypc);
+       if (rc)
+               goto err_out;
+
+       fy_emit_accum_make_0_terminated(&ea);
+
+       text = fy_emit_accum_steal(&ea, &len);
+
+err_out:
+       fy_emit_accum_cleanup(&ea);
+
+       return text;
+}
+
 int fy_path_depth(struct fy_path *fypp)
 {
        struct fy_path_component *fypc;
@@ -498,7 +582,7 @@ bool fy_path_in_mapping_value(struct fy_path *fypp)
        return fypc_last->type == FYPCT_MAP && !fypc_last->map.await_key;
 }
 
-bool fy_path_is_collection_root(struct fy_path *fypp)
+bool fy_path_in_collection_root(struct fy_path *fypp)
 {
        struct fy_path_component *fypc_last;
 
@@ -512,6 +596,30 @@ bool fy_path_is_collection_root(struct fy_path *fypp)
        return fy_path_component_is_collection_root(fypc_last);
 }
 
+void *fy_path_get_root_user_data(struct fy_path *fypp)
+{
+       if (!fypp)
+               return NULL;
+
+       if (!fypp->parent)
+               return fypp->user_data;
+
+       return fy_path_get_root_user_data(fypp->parent);
+}
+
+void fy_path_set_root_user_data(struct fy_path *fypp, void *data)
+{
+       if (!fypp)
+               return;
+
+       if (!fypp->parent) {
+               fypp->user_data = data;
+               return;
+       }
+
+       fy_path_set_root_user_data(fypp->parent, data);
+}
+
 void *fy_path_component_get_mapping_user_data(struct fy_path_component *fypc)
 {
        return fypc && fypc->type == FYPCT_MAP ? fypc->user_data : NULL;
index 73157f98dbf4503f318caa3e55e9731d89b7cd8d..22dde9c1b6d70044c1a7375603227b03f8ab3169 100644 (file)
@@ -36,13 +36,17 @@ struct fy_document_builder;
 #define FY_PATH_MAPPING_SHORT_KEY      32
 
 struct fy_path_mapping_state {
+       bool root : 1;          /* no keys, values yet */
        bool await_key : 1;
        bool accumulating_complex_key : 1;
-       bool has_key : 1;       /* has a key */
+       bool has_key : 1;                       /* has a key */
        bool is_complex_key : 1;
        bool complex_key_complete : 1;
        union {
-               struct fy_token *scalar_key;
+               struct {
+                       struct fy_token *tag;
+                       struct fy_token *key;
+               } scalar;
                struct fy_document *complex_key;
        };
        void *key_user_data;
@@ -75,7 +79,7 @@ fy_path_component_is_collection_root(struct fy_path_component *fypc)
        case FYPCT_SEQ:
                return fypc->seq.idx < 0;
        case FYPCT_MAP:
-               return fypc->map.await_key && !fypc->map.has_key && !fypc->map.complex_key_complete;
+               return fypc->map.root;
        }
 
        return false;
@@ -88,6 +92,7 @@ struct fy_path {
        struct fy_path_component_list components;
        struct fy_document_builder *fydb;       /* for complex keys */
        struct fy_path *parent;                 /* when we have a parent */
+       void *user_data;
 };
 FY_TYPE_DECL_LIST(path);
 
index 984fec0a4e110c9ec24033a9301d42cb25f95485..7fa7c0f368dd5a51f906ec5a4087923c087f72d6 100644 (file)
 
 enum fy_scalar_style fy_token_scalar_style(struct fy_token *fyt)
 {
-       if (!fyt || fyt->type != FYTT_SCALAR)
-               return FYSS_PLAIN;
-
-       if (fyt->type == FYTT_SCALAR)
-               return fyt->scalar.style;
-
-       return FYSS_PLAIN;
+       return fy_token_scalar_style_inline(fyt);
 }
 
 enum fy_token_type fy_token_get_type(struct fy_token *fyt)
 {
-       return fyt ? fyt->type : FYTT_NONE;
-}
-
-struct fy_token *fy_token_alloc_rl(struct fy_token_list *fytl)
-{
-       struct fy_token *fyt;
-
-       fyt = NULL;
-       if (fytl) {
-               fyt = fy_token_list_pop(fytl);
-               if (fyt) {
-                       fyt->analyze_flags = 0;
-                       fyt->text_len = 0;
-                       fyt->text = NULL;
-                       fyt->text0 = NULL;
-                       fyt->handle.fyi = NULL;
-                       fyt->comment = NULL;
-               }
-       }
-       if (!fyt) {
-               fyt = malloc(sizeof(*fyt));
-               if (!fyt)
-                       return NULL;
-
-               memset(fyt, 0, sizeof(*fyt));
-       }
-
-       fyt->type = FYTT_NONE;
-       fyt->refs = 1;
-
-       return fyt;
+       return fy_token_get_type_inline(fyt);
 }
 
 void fy_token_clean_rl(struct fy_token_list *fytl, struct fy_token *fyt)
@@ -86,33 +50,39 @@ void fy_token_clean_rl(struct fy_token_list *fytl, struct fy_token *fyt)
 
        /* release reference */
        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;
        }
 
        switch (fyt->type) {
        case FYTT_TAG:
                fy_token_unref(fyt->tag.fyt_td);
-               if (fyt->tag.handle0)
+               fyt->tag.fyt_td = NULL;
+               if (fyt->tag.handle0) {
                        free(fyt->tag.handle0);
-               if (fyt->tag.suffix0)
+                       fyt->tag.handle0 = NULL;
+               }
+               if (fyt->tag.suffix0) {
                        free(fyt->tag.suffix0);
-               fyt->tag.fyt_td = NULL;
-               fyt->tag.handle0 = NULL;
-               fyt->tag.suffix0 = NULL;
+                       fyt->tag.suffix0 = NULL;
+               }
                break;
 
        case FYTT_TAG_DIRECTIVE:
-               if (fyt->tag_directive.prefix0)
+               if (fyt->tag_directive.prefix0) {
                        free(fyt->tag_directive.prefix0);
-               if (fyt->tag_directive.handle0)
+                       fyt->tag_directive.prefix0 = NULL;
+               }
+               if (fyt->tag_directive.handle0) {
                        free(fyt->tag_directive.handle0);
-               fyt->tag_directive.prefix0 = NULL;
-               fyt->tag_directive.handle0 = NULL;
+                       fyt->tag_directive.handle0 = NULL;
+               }
                break;
 
        case FYTT_PE_MAP_KEY:
@@ -121,44 +91,32 @@ void fy_token_clean_rl(struct fy_token_list *fytl, struct fy_token *fyt)
                break;
 
        case FYTT_SCALAR:
-               if (fyt->scalar.path_key_storage)
+               if (fyt->scalar.path_key_storage) {
                        free(fyt->scalar.path_key_storage);
-               fyt->scalar.path_key_storage = NULL;
+                       fyt->scalar.path_key_storage = NULL;
+               }
                break;
 
        case FYTT_ALIAS:
-               if (fyt->alias.expr)
+               if (fyt->alias.expr) {
                        fy_path_expr_free(fyt->alias.expr);
-               fyt->alias.expr = NULL;
+                       fyt->alias.expr = NULL;
+               }
                break;
 
        default:
                break;
        }
 
-       if (fyt->text0)
+       if (fyt->text0) {
                free(fyt->text0);
+               fyt->text0 = NULL;
+       }
 
        fyt->type = FYTT_NONE;
        fyt->analyze_flags = 0;
        fyt->text_len = 0;
        fyt->text = NULL;
-       fyt->text0 = NULL;
-       fyt->handle.fyi = NULL;
-       fyt->comment = NULL;
-}
-
-void fy_token_free_rl(struct fy_token_list *fytl, struct fy_token *fyt)
-{
-       if (!fyt)
-               return;
-
-       fy_token_clean_rl(fytl, fyt);
-
-       if (fytl)
-               fy_token_list_push(fytl, fyt);
-       else
-               free(fyt);
 }
 
 void fy_token_list_unref_all_rl(struct fy_token_list *fytl, struct fy_token_list *fytl_tofree)
@@ -452,17 +410,19 @@ struct fy_token *fy_token_vcreate_rl(struct fy_token_list *fytl, enum fy_token_t
        if (handle)
                fyt->handle = *handle;
        else
-               memset(&fyt->handle, 0, sizeof(fyt->handle));
+               fy_atom_reset(&fyt->handle);
 
        switch (fyt->type) {
        case FYTT_TAG_DIRECTIVE:
                fyt->tag_directive.tag_length = va_arg(ap, unsigned int);
                fyt->tag_directive.uri_length = va_arg(ap, unsigned int);
                fyt->tag_directive.is_default = va_arg(ap, int) ? true : false;
+               fyt->tag_directive.prefix0 = NULL;
+               fyt->tag_directive.handle0 = NULL;
                break;
        case FYTT_SCALAR:
                fyt->scalar.style = va_arg(ap, enum fy_scalar_style);
-               if ((unsigned int)fyt->scalar.style >= FYSS_MAX)
+               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;
@@ -477,6 +437,8 @@ struct fy_token *fy_token_vcreate_rl(struct fy_token_list *fytl, enum fy_token_t
                if (!fyt_td)
                        goto err_out;
                fyt->tag.fyt_td = fy_token_ref(fyt_td);
+               fyt->tag.handle0 = NULL;
+               fyt->tag.suffix0 = NULL;
                break;
 
        case FYTT_VERSION_DIRECTIVE:
@@ -560,7 +522,7 @@ struct fy_token *fy_parse_token_create(struct fy_parser *fyp, enum fy_token_type
                return NULL;
 
        va_start(ap, type);
-       fyt = fy_token_vcreate_rl(&fyp->recycled_token, type, ap);
+       fyt = fy_token_vcreate_rl(fyp->recycled_token_list, type, ap);
        va_end(ap);
 
        return fyt;
index 3281204bab92ac9c3647352212a5ae1d7c0d7950..a4649555058ca306eeda33b18fb91c50553396d3 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <libfyaml.h>
 
+#include "fy-utils.h"
 #include "fy-atom.h"
 
 extern const char *fy_token_type_txt[FYTT_COUNT];
@@ -145,12 +146,51 @@ static inline bool fy_token_text_is_direct(struct fy_token *fyt)
        return fyt->text && fyt->text != fyt->text0;
 }
 
-struct fy_token *fy_token_alloc_rl(struct fy_token_list *fytl);
 void fy_token_clean_rl(struct fy_token_list *fytl, struct fy_token *fyt);
-void fy_token_free_rl(struct fy_token_list *fytl, struct fy_token *fyt);
 void fy_token_list_unref_all_rl(struct fy_token_list *fytl, struct fy_token_list *fytl_tofree);
 
-static inline void
+static inline FY_ALWAYS_INLINE struct fy_token *
+fy_token_alloc_rl(struct fy_token_list *fytl)
+{
+       struct fy_token *fyt;
+
+       fyt = NULL;
+       if (fytl)
+               fyt = fy_token_list_pop(fytl);
+       if (!fyt) {
+               fyt = malloc(sizeof(*fyt));
+               if (!fyt)
+                       return NULL;
+       }
+
+       fyt->type = FYTT_NONE;
+       fyt->refs = 1;
+
+       fyt->analyze_flags = 0;
+       fyt->text_len = 0;
+       fyt->text = NULL;
+       fyt->text0 = NULL;
+       fyt->handle.fyi = NULL;
+       fyt->comment = NULL;
+
+       return fyt;
+}
+
+static inline FY_ALWAYS_INLINE void
+fy_token_free_rl(struct fy_token_list *fytl, struct fy_token *fyt)
+{
+       if (!fyt)
+               return;
+
+       fy_token_clean_rl(fytl, fyt);
+
+       if (fytl)
+               fy_token_list_push(fytl, fyt);
+       else
+               free(fyt);
+}
+
+static inline FY_ALWAYS_INLINE void
 fy_token_unref_rl(struct fy_token_list *fytl, struct fy_token *fyt)
 {
        if (!fyt)
@@ -162,25 +202,25 @@ fy_token_unref_rl(struct fy_token_list *fytl, struct fy_token *fyt)
                fy_token_free_rl(fytl, fyt);
 }
 
-static inline struct fy_token *
+static inline FY_ALWAYS_INLINE struct fy_token *
 fy_token_alloc(void)
 {
        return fy_token_alloc_rl(NULL);
 }
 
-static inline void
+static inline FY_ALWAYS_INLINE void
 fy_token_clean(struct fy_token *fyt)
 {
        return fy_token_clean_rl(NULL, fyt);
 }
 
-static inline void
+static inline FY_ALWAYS_INLINE void
 fy_token_free(struct fy_token *fyt)
 {
        return fy_token_free_rl(NULL, fyt);
 }
 
-static inline struct fy_token *
+static inline FY_ALWAYS_INLINE struct fy_token *
 fy_token_ref(struct fy_token *fyt)
 {
        /* take care of overflow */
@@ -192,7 +232,7 @@ fy_token_ref(struct fy_token *fyt)
        return fyt;
 }
 
-static inline void
+static inline FY_ALWAYS_INLINE void
 fy_token_unref(struct fy_token *fyt)
 {
        return fy_token_unref_rl(NULL, fyt);
@@ -461,4 +501,22 @@ const char *fy_token_get_scalar_path_key0(struct fy_token *fyt);
 
 struct fy_atom *fy_token_comment_handle(struct fy_token *fyt, enum fy_comment_placement placement, bool alloc);
 
+static inline FY_ALWAYS_INLINE enum fy_scalar_style
+fy_token_scalar_style_inline(struct fy_token *fyt)
+{
+       if (!fyt || fyt->type != FYTT_SCALAR)
+               return FYSS_PLAIN;
+
+       if (fyt->type == FYTT_SCALAR)
+               return fyt->scalar.style;
+
+       return FYSS_PLAIN;
+}
+
+static inline FY_ALWAYS_INLINE enum fy_token_type
+fy_token_get_type_inline(struct fy_token *fyt)
+{
+       return fyt ? fyt->type : FYTT_NONE;
+}
+
 #endif
index 3707110442998f594e5490eefc14ed6ccba42db7..8b55ccb7de6d110691289e05c0a2ef3a1036c3d7 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <sys/types.h>
 
 #include "fy-utf8.h"
 #include "fy-ctype.h"
@@ -391,3 +396,239 @@ int fy_tag_scan(const char *data, size_t len, struct fy_tag_scan_info *info)
 
        return 0;
 }
+
+/* simple terminal methods; mainly for getting size of terminal */
+int fy_term_set_raw(int fd, struct termios *oldt)
+{
+       struct termios newt, t;
+       int ret;
+
+       /* must be a terminal */
+       if (!isatty(fd))
+               return -1;
+
+       ret = tcgetattr(fd, &t);
+       if (ret != 0)
+               return ret;
+
+       newt = t;
+
+       cfmakeraw(&newt);
+    
+       ret = tcsetattr(fd, TCSANOW, &newt);
+       if (ret != 0)
+               return ret;
+
+       if (oldt)
+               *oldt = t;
+
+       return 0;
+}
+
+int fy_term_restore(int fd, const struct termios *oldt)
+{
+       /* must be a terminal */
+       if (!isatty(fd))
+               return -1;
+
+       return tcsetattr(fd, TCSANOW, oldt);
+}
+
+ssize_t fy_term_write(int fd, const void *data, size_t count)
+{
+       ssize_t wrn, r;
+
+       if (!isatty(fd))
+               return -1;
+       r = 0;
+       wrn = 0;
+       while (count > 0) {
+               do {
+                       r = write(fd, data, count);
+               } while (r == -1 && errno == EAGAIN);
+               if (r < 0)
+                       break;
+               wrn += r;
+               data += r;
+               count -= r;
+       }
+
+       /* return the amount written, or the last error code */
+       return wrn > 0 ? wrn : r;
+}
+
+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)
+{
+       ssize_t rdn, r;
+       struct timeval tv, tvto, *tvp;
+       fd_set rdfds;
+
+       if (!isatty(fd))
+               return -1;
+
+       FD_ZERO(&rdfds);
+
+       memset(&tvto, 0, sizeof(tvto));
+       memset(&tv, 0, sizeof(tv));
+
+       if (timeout_us >= 0) {
+               tvto.tv_sec = timeout_us / 1000000;
+               tvto.tv_usec = timeout_us % 1000000;
+               tvp = &tv;
+       } else {
+               tvp = NULL;
+       }
+
+       r = 0;
+       rdn = 0;
+       while (count > 0) {
+               do {
+                       FD_SET(fd, &rdfds);
+                       if (tvp)
+                               *tvp = tvto;
+                       r = select(fd + 1, &rdfds, NULL, NULL, tvp);
+               } while (r == -1 && errno == EAGAIN);
+
+               /* select ends, or something weird */
+               if (r <= 0 || !FD_ISSET(fd, &rdfds))
+                       break;
+
+               /* now read */
+               do {
+                       r = read(fd, data, count);
+               } while (r == -1 && errno == EAGAIN);
+               if (r < 0)
+                       break;
+
+               rdn += r;
+               data += r;
+               count -= r;
+       }
+
+       /* return the amount written, or the last error code */
+       return rdn > 0 ? rdn : r;
+}
+
+ssize_t fy_term_read_escape(int fd, void *buf, size_t count)
+{
+       char *p;
+       int r, rdn;
+       char c;
+
+       /* at least 3 characters */
+       if (count < 3)
+               return -1;
+
+       p = buf;
+       rdn = 0;
+
+       /* ESC */
+       r = fy_term_read(fd, &c, 1, 100 * 1000);
+       if (r != 1 || c != '\x1b')
+               return -1;
+       *p++ = c;
+       count--;
+       rdn++;
+
+       /* [ */
+       r = fy_term_read(fd, &c, 1, 100 * 1000);
+       if (r != 1 || c != '[')
+               return rdn;
+       *p++ = c;
+       count--;
+       rdn++;
+
+       /* read until error, out of buffer, or < 0x40 || > 0x7e */
+       r = -1;
+       while (count > 0) {
+               r = fy_term_read(fd, &c, 1, 100 * 1000);
+               if (r != 1)
+                       r = -1;
+               if (r != 1)
+                       break;
+               *p++ = c;
+               count--;
+               rdn++;
+
+               /* end of escape */
+               if (c >= 0x40 && c <= 0x7e)
+                       break;
+       }
+
+       return rdn;
+}
+
+int fy_term_query_size_raw(int fd, int *rows, int *cols)
+{
+       char buf[32];
+       char *s, *e;
+       ssize_t r;
+
+       /* must be a terminal */
+       if (!isatty(fd))
+               return -1;
+
+       *rows = *cols = 0;
+
+       /* query text area */
+       r = fy_term_safe_write(fd, "\x1b[18t", 5);
+       if (r != 0)
+               return r;
+
+       /* read a character */
+       r = fy_term_read_escape(fd, buf, sizeof(buf));
+
+       /* return must be ESC[8;<height>;<width>;t */
+
+       if (r < 8 || r >= (int)sizeof(buf) - 2) /* minimum ESC[8;1;1t */
+               return -1;
+
+       s = buf;
+       e = s + r;
+
+       /* correct response? starts with ESC[8; */
+       if (s[0] != '\x1b' || s[1] != '[' || s[2] != '8' || s[3] != ';')
+               return -1;
+       s += 4;
+
+       /* must end with t */
+       if (e[-1] != 't')
+               return -1;
+       *--e = '\0';    /* remove trailing t, and zero terminate */
+
+       /* scan two ints separated by ; */
+       r = sscanf(s, "%d;%d", rows, cols);
+       if (r != 2)
+               return -1;
+
+       return 0;
+}
+
+int fy_term_query_size(int fd, int *rows, int *cols)
+{
+       struct termios old_term;
+       int ret, r;
+
+       if (!isatty(fd))
+               return -1;
+
+       r = fy_term_set_raw(fd, &old_term);
+       if (r != 0)
+               return -1;
+
+       ret = fy_term_query_size_raw(fd, rows, cols);
+
+       r = fy_term_restore(fd, &old_term);
+       if (r != 0)
+               return -1;
+
+       return ret;
+}
index 484055069855b9fa5b03bbb248324bd0ae45b76c..cf3e3c52222cb6545283848519fba1c557918048 100644 (file)
@@ -15,6 +15,8 @@
 
 #include <stdio.h>
 #include <stdbool.h>
+#include <unistd.h>
+#include <termios.h>
 
 #if defined(__APPLE__) && (_POSIX_C_SOURCE < 200809L)
 FILE *open_memstream(char **ptr, size_t *sizeloc);
@@ -38,4 +40,29 @@ int fy_tag_scan(const char *data, size_t len, struct fy_tag_scan_info *info);
 #define ARRAY_SIZE(x) ((sizeof(x)/sizeof((x)[0])))
 #endif
 
+#if !defined(NDEBUG) && (defined(__GNUC__) && __GNUC__ >= 4)
+#define FY_ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define FY_ALWAYS_INLINE /* nothing */
+#endif
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define FY_UNUSED __attribute__((unused))
+#else
+#define FY_UNUSED /* nothing */
+#endif
+
+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 */
+int fy_term_query_size(int fd, int *rows, int *cols);
+
 #endif
index ad108f1d1702c5c83f8a1bf1a62a9cb95dbc5baf..736704df384eb3f128e348f6d48273f20a3ed3a3 100644 (file)
@@ -1820,7 +1820,7 @@ int fy_path_expr_type_prec(enum fy_path_expr_type type)
        return -1;
 }
 
-static inline void
+static inline FY_UNUSED void
 dump_operand_stack(struct fy_path_parser *fypp)
 {
        return fy_expr_stack_dump(fypp->cfg.diag, &fypp->operands);
@@ -1832,19 +1832,19 @@ push_operand(struct fy_path_parser *fypp, struct fy_path_expr *expr)
        return fy_expr_stack_push(&fypp->operands, expr);
 }
 
-static inline struct fy_path_expr *
+static inline FY_UNUSED struct fy_path_expr *
 peek_operand_at(struct fy_path_parser *fypp, unsigned int pos)
 {
        return fy_expr_stack_peek_at(&fypp->operands, pos);
 }
 
-static inline struct fy_path_expr *
+static inline FY_UNUSED struct fy_path_expr *
 peek_operand(struct fy_path_parser *fypp)
 {
        return fy_expr_stack_peek(&fypp->operands);
 }
 
-static inline struct fy_path_expr *
+static inline FY_UNUSED struct fy_path_expr *
 pop_operand(struct fy_path_parser *fypp)
 {
        return fy_expr_stack_pop(&fypp->operands);
index 0740acb1d879690ce1dd62137aad00fcc5d6ada4..bb46c0a75a9d5216d9b6fc2af21262d089bbc01e 100644 (file)
 #define YPATH_ALIASES_DEFAULT          false
 #define DISABLE_FLOW_MARKERS_DEFAULT   false
 #define DUMP_PATH_DEFAULT              false
+#define DOCUMENT_EVENT_STREAM_DEFAULT  false
+#define COLLECT_ERRORS_DEFAULT         false
+#define ALLOW_DUPLICATE_KEYS_DEFAULT   false
+#define STRIP_EMPTY_KV_DEFAULT         false
 
 #define OPT_DUMP                       1000
 #define OPT_TESTSUITE                  1001
 #define OPT_YPATH_ALIASES              2013
 #define OPT_DISABLE_FLOW_MARKERS       2014
 #define OPT_DUMP_PATH                  2015
+#define OPT_DOCUMENT_EVENT_STREAM      2016
+#define OPT_COLLECT_ERRORS             2017
+#define OPT_ALLOW_DUPLICATE_KEYS       2018
+#define OPT_STRIP_EMPTY_KV             2019
 
 #define OPT_DISABLE_DIAG               3000
 #define OPT_ENABLE_DIAG                        3001
@@ -131,8 +139,12 @@ static struct option lopts[] = {
        {"ypath-aliases",       no_argument,            0,      OPT_YPATH_ALIASES },
        {"disable-flow-markers",no_argument,            0,      OPT_DISABLE_FLOW_MARKERS },
        {"dump-pathexpr",       no_argument,            0,      OPT_DUMP_PATHEXPR },
+       {"document-event-stream",no_argument,           0,      OPT_DOCUMENT_EVENT_STREAM },
        {"noexec",              no_argument,            0,      OPT_NOEXEC },
        {"null-output",         no_argument,            0,      OPT_NULL_OUTPUT },
+       {"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 },
        {"to",                  required_argument,      0,      'T' },
        {"from",                required_argument,      0,      'F' },
        {"quiet",               no_argument,            0,      'q' },
@@ -153,7 +165,7 @@ static void display_usage(FILE *fp, char *progname, int tool_mode)
                                                DEBUG_LEVEL_DEFAULT);
        fprintf(fp, "\t--disable-diag <x>      : Disable diag error module <x>\n");
        fprintf(fp, "\t--enable-diag <x>       : Enable diag error module <x>\n");
-       fprintf(fp, "\t--show-diag-diag <x>    : Show diag option <x>\n");
+       fprintf(fp, "\t--show-diag <x>         : Show diag option <x>\n");
        fprintf(fp, "\t--hide-diag <x>         : Hide diag optione <x>\n");
 
        fprintf(fp, "\t--indent, -i <indent>    : Set dump indent to <indent>"
@@ -207,6 +219,15 @@ 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--collect-errors         : Collect errors instead of outputting directly"
+                                               " (default %s)\n",
+                                               COLLECT_ERRORS_DEFAULT ? "true" : "false");
+       fprintf(fp, "\t--allow-duplicate-keys   : Allow duplicate keys"
+                                               " (default %s)\n",
+                                               ALLOW_DUPLICATE_KEYS_DEFAULT ? "true" : "false");
+       fprintf(fp, "\t--strip-empty-kv         : Strip keys with empty values when emitting (not available in streaming mode)"
+                                               " (default %s)\n",
+                                               STRIP_EMPTY_KV_DEFAULT ? "true" : "false");
        fprintf(fp, "\t--quiet, -q              : Quiet operation, do not "
                                                "output messages (default %s)\n",
                                                QUIET_DEFAULT ? "true" : "false");
@@ -220,12 +241,15 @@ static void display_usage(FILE *fp, char *progname, int tool_mode)
                fprintf(fp, "\t--comment, -c            : Output comments (experimental)"
                                                        " (default %s)\n",
                                                        COMMENT_DEFAULT ? "true" : "false");
-               fprintf(fp, "\t--mode, -m <mode>        : Output mode can be one of original, block, flow, flow-oneline, json, json-tp, json-oneline, dejson"
+               fprintf(fp, "\t--mode, -m <mode>        : Output mode can be one of original, block, flow, flow-oneline, json, json-tp, json-oneline, dejson, pretty|yamlfmt"
                                                        " (default %s)\n",
                                                        MODE_DEFAULT);
                fprintf(fp, "\t--disable-flow-markers   : Disable testsuite's flow-markers"
                                                        " (default %s)\n",
                                                        DISABLE_FLOW_MARKERS_DEFAULT ? "true" : "false");
+               fprintf(fp, "\t--document-event-stream  : Generate a document and then produce the event stream"
+                                                       " (default %s)\n",
+                                                       DOCUMENT_EVENT_STREAM_DEFAULT ? "true" : "false");
                if (tool_mode == OPT_TOOL || tool_mode == OPT_DUMP)
                        fprintf(fp, "\t--streaming              : Use streaming output mode"
                                                                " (default %s)\n",
@@ -365,6 +389,8 @@ static int apply_mode_flags(const char *what, enum fy_emitter_cfg_flags *flagsp)
                { .name = "json-tp",            .value = FYECF_MODE_JSON_TP },
                { .name = "json-oneline",       .value = FYECF_MODE_JSON_ONELINE },
                { .name = "dejson",             .value = FYECF_MODE_DEJSON },
+               { .name = "pretty",             .value = FYECF_MODE_PRETTY },
+               { .name = "yamlfmt",            .value = FYECF_MODE_PRETTY },   /* alias for pretty */
        };
        unsigned int i;
 
@@ -1176,7 +1202,7 @@ compose_process_event(struct fy_parser *fyp, struct fy_event *fye, struct fy_pat
                                fy_path_in_mapping(path) ? 'M' : '-',
                                fy_path_in_mapping_key(path) ? 'K' :
                                        fy_path_in_mapping_value(path) ? 'V' : '-',
-                               fy_path_is_collection_root(path) ? '/' : '-',
+                               fy_path_in_collection_root(path) ? '/' : '-',
                                fy_path_depth(path),
                                fy_path_get_text_alloca(path));
        }
@@ -1395,8 +1421,12 @@ int main(int argc, char *argv[])
        bool stdin_input;
        void *res_iter;
        bool disable_flow_markers = false;
+       bool document_event_stream = DOCUMENT_EVENT_STREAM_DEFAULT;
+       bool collect_errors = COLLECT_ERRORS_DEFAULT;
+       bool allow_duplicate_keys = ALLOW_DUPLICATE_KEYS_DEFAULT;
        struct composer_data cd;
        bool dump_path = DUMP_PATH_DEFAULT;
+       const char *input_arg;
 
        fy_valgrind_check(&argc, &argv);
 
@@ -1668,6 +1698,18 @@ int main(int argc, char *argv[])
                case OPT_DISABLE_FLOW_MARKERS:
                        disable_flow_markers = true;
                        break;
+               case OPT_DOCUMENT_EVENT_STREAM:
+                       document_event_stream = true;
+                       break;
+               case OPT_COLLECT_ERRORS:
+                       collect_errors = true;
+                       break;
+               case OPT_ALLOW_DUPLICATE_KEYS:
+                       allow_duplicate_keys = true;
+                       break;
+               case OPT_STRIP_EMPTY_KV:
+                       emit_flags |= FYECF_STRIP_EMPTY_KV;
+                       break;
                case 'h' :
                default:
                        if (opt != 'h')
@@ -1711,6 +1753,13 @@ int main(int argc, char *argv[])
                goto cleanup;
        }
 
+       /* collect errors, instead of outputting directly */
+       if (collect_errors)
+               fy_diag_set_collect_errors(diag, true);
+
+       if (allow_duplicate_keys)
+               cfg.flags |= FYPCF_ALLOW_DUPLICATE_KEYS;
+
        /* all set, use fy_diag for error reporting, debugging now */
 
        cfg.diag = diag;
@@ -1760,27 +1809,93 @@ int main(int argc, char *argv[])
                        fprintf(stderr, "failed to create token iterator\n");
                        goto cleanup;
                }
-               while ((fyev = fy_parser_parse(fyp)) != NULL) {
+
+               if (!document_event_stream) {
+                       /* regular test suite */
+                       while ((fyev = fy_parser_parse(fyp)) != NULL) {
+                               dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
+                               fy_parser_event_free(fyp, fyev);
+                       }
+               } else {
+                       struct fy_document_iterator *fydi;
+
+                       fydi = fy_document_iterator_create();
+                       assert(fydi);
+
+                       fyev = fy_document_iterator_stream_start(fydi);
+                       if (!fyev) {
+                               fprintf(stderr, "failed to create document iterator's stream start event\n");
+                               goto cleanup;
+                       }
+                       dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
+                       fy_document_iterator_event_free(fydi, fyev);
+
+                       /* convert to document and then process the generator event stream it */
+                       while ((fyd = fy_parse_load_document(fyp)) != NULL) {
+
+                               fyev = fy_document_iterator_document_start(fydi, fyd);
+                               if (!fyev) {
+                                       fprintf(stderr, "failed to create document iterator's document start event\n");
+                                       goto cleanup;
+                               }
+                               dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
+                               fy_document_iterator_event_free(fydi, fyev);
+
+                               while ((fyev = fy_document_iterator_body_next(fydi)) != NULL) {
+                                       dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
+                                       fy_document_iterator_event_free(fydi, fyev);
+                               }
+
+                               fyev = fy_document_iterator_document_end(fydi);
+                               if (!fyev) {
+                                       fprintf(stderr, "failed to create document iterator's stream document end\n");
+                                       goto cleanup;
+                               }
+                               dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
+                               fy_document_iterator_event_free(fydi, fyev);
+
+                               fy_parse_document_destroy(fyp, fyd);
+                               if (rc)
+                                       break;
+
+                       }
+
+                       fyev = fy_document_iterator_stream_end(fydi);
+                       if (!fyev) {
+                               fprintf(stderr, "failed to create document iterator's stream end event\n");
+                               goto cleanup;
+                       }
                        dump_testsuite_event(fyp, fyev, du.colorize, iter, disable_flow_markers);
-                       fy_parser_event_free(fyp, fyev);
+                       fy_document_iterator_event_free(fydi, fyev);
+
+                       fy_document_iterator_destroy(fydi);
+                       fydi = NULL;
                }
+
                fy_token_iter_destroy(iter);
                iter = NULL;
+
                if (fy_parser_get_stream_error(fyp))
                        goto cleanup;
                break;
 
        case OPT_DUMP:
-               if (optind >= argc) {
-                       fprintf(stderr, "missing yaml file to dump\n");
-                       goto cleanup;
-               }
-
                count = 0;
-               for (i = optind; i < argc; i++) {
-                       rc = set_parser_input(fyp, argv[i], false);
+               for (i = optind; ; i++) {
+
+                       if (optind < argc) {
+                               if (i >= argc)
+                                       break;
+                               input_arg = argv[i];
+                       } else {
+                               if (i >= argc + 1)
+                                       break;
+                               input_arg = "-";
+                       }
+
+                       rc = set_parser_input(fyp, input_arg, false);
                        if (rc) {
-                               fprintf(stderr, "failed to set parser input to '%s' for dump\n", argv[i]);
+                               fprintf(stderr, "failed to set parser input to '%s' for dump\n", input_arg);
                                goto cleanup;
                        }
 
@@ -1881,10 +1996,21 @@ int main(int argc, char *argv[])
                }
 
                fyd_join = NULL;
-               for (i = optind; i < argc; i++) {
-                       rc = set_parser_input(fyp, argv[i], false);
+               for (i = optind; ; i++) {
+
+                       if (optind < argc) {
+                               if (i >= argc)
+                                       break;
+                               input_arg = argv[i];
+                       } else {
+                               if (i >= argc + 1)
+                                       break;
+                               input_arg = "-";
+                       }
+
+                       rc = set_parser_input(fyp, input_arg, false);
                        if (rc) {
-                               fprintf(stderr, "failed to set parser input to '%s' for join\n", argv[i]);
+                               fprintf(stderr, "failed to set parser input to '%s' for join\n", input_arg);
                                goto cleanup;
                        }
 
@@ -2168,8 +2294,19 @@ cleanup:
        if (fyp)
                fy_parser_destroy(fyp);
 
-       if (diag)
+       if (diag) {
+               if (collect_errors) {
+                       struct fy_diag_error *err;
+                       void *iter;
+
+                       iter = NULL;
+                       while ((err = fy_diag_errors_iterate(diag, &iter)) != NULL) {
+                               fprintf(stderr, "%s:%d:%d %s\n", err->file, err->line, err->column, err->msg);
+                       }
+
+               }
                fy_diag_destroy(diag);
+       }
 
        return exitcode;
 }
index 0c87edf4f33a813c69ecf388821299482bd6bdb1..8b6802db068fe905bc6b6a3ca4f2b055bea4c1a3 100644 (file)
@@ -30,7 +30,7 @@ if HAVE_COMPATIBLE_CHECK
 check_PROGRAMS = libfyaml-test
 libfyaml_test_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/valgrind/ \
                         -I$(top_srcdir)/src/lib/
-libfyaml_test_LDADD = $(AM_LDADD) $(CHECK_LIBS) $(top_builddir)/src/libfyaml-@MAJOR@.@MINOR@.la
+libfyaml_test_LDADD = $(AM_LDADD) $(CHECK_LIBS) $(top_builddir)/src/libfyaml.la
 libfyaml_test_CFLAGS = $(AM_CFLAGS) $(CHECK_CFLAGS) 
 libfyaml_test_LDFLAGS = $(AM_LDFLAGS) $(CHECK_LDFLAGS)
 
@@ -59,6 +59,9 @@ endif
 # normal JSON testsuite
 TESTS += jsontestsuite.test
 
+# normal YAML testsuite using document event stream
+TESTS += testsuite-evstream.test
+
 testsuite.test: test-suite-data json-test-suite-data
 
 test-suite-data:
index c73b09d7296d0b685bb92b9f6f732c170729736b..265d7e475a49aa0427847ec855a90a00057c79f5 100644 (file)
@@ -99,7 +99,10 @@ host_triplet = @host@
 @HAVE_GIT_TRUE@@HAVE_JQ_TRUE@@HAVE_NETWORK_TRUE@am__append_3 = testsuite-json.test
 
 # normal JSON testsuite
-@HAVE_GIT_TRUE@@HAVE_NETWORK_TRUE@am__append_4 = jsontestsuite.test
+
+# normal YAML testsuite using document event stream
+@HAVE_GIT_TRUE@@HAVE_NETWORK_TRUE@am__append_4 = jsontestsuite.test \
+@HAVE_GIT_TRUE@@HAVE_NETWORK_TRUE@     testsuite-evstream.test
 subdir = test
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_enable_debug.m4 \
@@ -107,7 +110,8 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/ax_check_enable_debug.m4 \
        $(top_srcdir)/m4/ax_pthread.m4 $(top_srcdir)/m4/libtool.m4 \
        $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
        $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/shave.m4 $(top_srcdir)/.libtool-version \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON)
@@ -127,7 +131,7 @@ libfyaml_test_OBJECTS = $(am_libfyaml_test_OBJECTS)
 am__DEPENDENCIES_1 =
 @HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_DEPENDENCIES =  \
 @HAVE_COMPATIBLE_CHECK_TRUE@   $(am__DEPENDENCIES_1) \
-@HAVE_COMPATIBLE_CHECK_TRUE@   $(top_builddir)/src/libfyaml-@MAJOR@.@MINOR@.la
+@HAVE_COMPATIBLE_CHECK_TRUE@   $(top_builddir)/src/libfyaml.la
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
@@ -425,7 +429,6 @@ CXXCPP = @CXXCPP@
 CXXDEPMODE = @CXXDEPMODE@
 CXXFLAGS = @CXXFLAGS@
 CYGPATH_W = @CYGPATH_W@
-DEBVERSION = @DEBVERSION@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
@@ -464,6 +467,7 @@ LIBLTDL = @LIBLTDL@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
+LIBTOOL_VERSION = @LIBTOOL_VERSION@
 LIBYAML_CFLAGS = @LIBYAML_CFLAGS@
 LIBYAML_LIBS = @LIBYAML_LIBS@
 LIPO = @LIPO@
@@ -600,7 +604,7 @@ TESTS = $(am__append_1) $(am__append_2) $(am__append_3) \
 @HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_CPPFLAGS = $(AM_CPPFLAGS) -I$(top_srcdir)/src/valgrind/ \
 @HAVE_COMPATIBLE_CHECK_TRUE@                    -I$(top_srcdir)/src/lib/
 
-@HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_LDADD = $(AM_LDADD) $(CHECK_LIBS) $(top_builddir)/src/libfyaml-@MAJOR@.@MINOR@.la
+@HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_LDADD = $(AM_LDADD) $(CHECK_LIBS) $(top_builddir)/src/libfyaml.la
 @HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_CFLAGS = $(AM_CFLAGS) $(CHECK_CFLAGS) 
 @HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_LDFLAGS = $(AM_LDFLAGS) $(CHECK_LDFLAGS)
 @HAVE_COMPATIBLE_CHECK_TRUE@libfyaml_test_SOURCES = \
diff --git a/test/testsuite-evstream.test b/test/testsuite-evstream.test
new file mode 100755 (executable)
index 0000000..2f35be2
--- /dev/null
@@ -0,0 +1,88 @@
+#!/bin/bash
+
+count=0
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
+               # there must be a test there
+               if [ ! -e "$tst/===" ]; then
+                       continue
+               fi
+               # skip tests that are expected to fail
+               if [ -e "$tst/error" ]; then
+                       continue
+               fi
+               count=`expr $count + 1`
+       done
+done
+
+# output plan
+echo 1..$count
+
+skiplist="2JQS"
+xfaillist=""
+
+i=0
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
+
+               # there must be a test there
+               if [ ! -e "$tst/===" ]; then
+                       continue
+               fi
+
+               # skip tests that are expected to fail
+               if [ -e "$tst/error" ]; then
+                       continue
+               fi
+
+               i=`expr $i + 1`
+
+               # strip trailing /
+               t=${tst%/}
+               # remove test-suite-data/
+               test_subtest_id=`echo $t | cut -d/ -f2-`
+               test_id=`echo $test_subtest_id | cut -d/ -f1`
+               subtest_id=`echo $test_subtest_id | cut -s -d/ -f2`
+
+               desctxt=`cat 2>/dev/null "$tst/==="`
+
+               t=`mktemp`
+
+               directive=""
+               for skip in $skiplist; do
+                       if [ "$test_subtest_id" == "$skip" ]; then
+                               directive=" # skip: duplicate keys in testcase; cannot load as document"
+                               break
+                       fi
+               done
+
+               res="ok"
+               if [ "x$directive" == "x" ]; then
+                       res="not ok"
+                       # run the test using document-event-stream
+                       ${TOP_BUILDDIR}/src/fy-tool --testsuite --document-event-stream "$tst/in.yaml" >"$t"
+                       if [ $? -eq 0 ]; then
+                               diff -u "$tst/test.event" "$t"
+                               if [ $? -eq 0 ]; then
+                                       res="ok"
+                               else
+                                       res="not ok"
+                               fi
+                       else
+                               res="not ok"
+                       fi
+
+                       rm -f "$t"
+
+                       for xfail in $xfaillist; do
+                               if [ "$test_subtest_id" == "$xfail" ]; then
+                                       directive=" # TODO: known failure."
+                                       break
+                               fi
+                       done
+               fi
+
+               echo "$res $i $test_subtest_id - $desctxt$directive"
+       done
+done
index 9b87ecc6498a04b9a5036d266d2a8355447d5867..794d5152fba97f123b8db6febe5d48924ba13521 100755 (executable)
@@ -1,66 +1,92 @@
 #!/bin/bash
 
 count=0
-for file in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/in.json; do
-
-       dir=`dirname $file`
-
-       # ignore tests which are expected to fail
-       if [ -e "$dir/error" ]; then
-               continue
-       fi
-
-       count=`expr $count + 1`
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
+               # there must be a test there
+               if [ ! -e "$tst/===" ]; then
+                       continue
+               fi
+               # ignore tests which are expected to fail
+               if [ -e "$tst/error" ]; then
+                       continue
+               fi
+               # a json file must be there
+               if [ ! -e "$tst/in.json" ]; then
+                       continue
+               fi
+               count=`expr $count + 1`
+       done
 done
 
 # output plan
 echo 1..$count
 
 skiplist="C4HZ"
+xfaillist=""
 
 i=0
-for file in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/in.json; do
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
 
-       dir=`dirname $file`
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
 
-       # ignore tests which are expected to fail
-       if [ -e "$dir/error" ]; then
-               continue
-       fi
+               # ignore tests which are expected to fail
+               if [ -e "$tst/error" ]; then
+                       continue
+               fi
+               # a json file must be there
+               if [ ! -e "$tst/in.json" ]; then
+                       continue
+               fi
 
-       i=`expr $i + 1`
-       desctxt=`cat 2>/dev/null "$dir/==="`
-       tdir=`basename $dir`
+               i=`expr $i + 1`
 
-       skipdirective=""
-       for skip in $skiplist; do
-               if [ "$tdir" == "$skip" ]; then
-                       skipdirective="# skip does not apply to libfyaml"
-                       break
-               fi
-       done
+               # strip trailing /
+               t=${tst%/}
+               # remove test-suite-data/
+               test_subtest_id=`echo $t | cut -d/ -f2-`
+               test_id=`echo $test_subtest_id | cut -d/ -f1`
+               subtest_id=`echo $test_subtest_id | cut -s -d/ -f2`
 
-       res="ok"
+               desctxt=`cat 2>/dev/null "$tst/==="`
 
-       if [ "x$skipdirective" == "x" ]; then
-               t1=`mktemp`
-               t2=`mktemp`
+               directive=""
+               for skip in $skiplist; do
+                       if [ "$test_subtest_id" == "$skip" ]; then
+                               directive="# SKIP: does not apply to libfyaml"
+                               break
+                       fi
+               done
 
-               # output yaml in json format
-               ${TOP_BUILDDIR}/src/fy-tool --dump --strip-labels --strip-tags --strip-doc -r -mjson "$dir/in.yaml" | "${JQ}" --sort-keys . >"$t1"
+               res="ok"
 
-               # do the same with the json input (canonicalize)
-               cat "$dir/in.json" | "${JQ}" --sort-keys . > "$t2"
+               if [ "x$directive" == "x" ]; then
+                       t1=`mktemp`
+                       t2=`mktemp`
 
-               diff -u "$t1" "$t2"
-               if [ $? -eq 0 ]; then
-                       res="ok"
-               else
-                       res="not ok"
-               fi
+                       # output yaml in json format
+                       ${TOP_BUILDDIR}/src/fy-tool --dump --strip-labels --strip-tags --strip-doc -r -mjson "$tst/in.yaml" | "${JQ}" --sort-keys . >"$t1"
+
+                       # do the same with the json input (canonicalize)
+                       cat "$tst/in.json" | "${JQ}" --sort-keys . > "$t2"
 
-               rm -f "$t1" "$t2"
-       fi
+                       diff -u "$t1" "$t2"
+                       if [ $? -eq 0 ]; then
+                               res="ok"
+                       else
+                               res="not ok"
+                       fi
 
-       echo "$res $i $tdir - $desctxt (JSON)$skipdirective"
+                       rm -f "$t1" "$t2"
+
+                       for xfail in $xfaillist; do
+                               if [ "$test_subtest_id" == "$xfail" ]; then
+                                       directive=" # TODO: known failure."
+                                       break
+                               fi
+                       done
+               fi
+
+               echo "$res $i $test_subtest_id - $desctxt (JSON)$directive"
+       done
 done
index d711d4b03b5f9b81a4887803c0786d09999bfbdf..1883d00f9da319e909522691a32cabe7780b33e4 100755 (executable)
@@ -1,54 +1,96 @@
 #!/bin/bash
 
 count=0
-for dir in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
-       count=`expr $count + 1`
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
+               # there must be a test there
+               if [ ! -e "$tst/===" ]; then
+                       continue
+               fi
+               count=`expr $count + 1`
+       done
 done
 
 # output plan
 echo 1..$count
 
+skiplist=""
+xfaillist=""
+
 i=0
-for dir in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+for basetst in test-suite-data/[A-Z0-9][A-Z0-9][A-Z0-9][A-Z0-9]/; do
+
+       for tst in ${basetst} ${basetst}[0-9][0-9]/; do
+
+               # there must be a test there
+               if [ ! -e "$tst/===" ]; then
+                       continue
+               fi
+
+               i=`expr $i + 1`
 
-       i=`expr $i + 1`
-       desctxt=`cat 2>/dev/null "$dir/==="`
-       tdir=`basename $dir`
+               # strip trailing /
+               t=${tst%/}
+               # remove test-suite-data/
+               test_subtest_id=`echo $t | cut -d/ -f2-`
+               test_id=`echo $test_subtest_id | cut -d/ -f1`
+               subtest_id=`echo $test_subtest_id | cut -s -d/ -f2`
 
-       t=`mktemp`
+               desctxt=`cat 2>/dev/null "$tst/==="`
 
-       res="not ok"
+               t=`mktemp`
 
-       pass_yaml=0
-       ${TOP_BUILDDIR}/src/fy-tool --testsuite "$dir/in.yaml" >"$t"
-       if [ $? -eq 0 ]; then
-               pass_yaml=1
-       fi
+               directive=""
+               for skip in $skiplist; do
+                       if [ "$test_subtest_id" == "$skip" ]; then
+                               directive=" # SKIP"
+                               break
+                       fi
+               done
 
-       if [ -e "$dir/error" ]; then
-               # test is expected to fail
-               if [ $pass_yaml == "0" ]; then
-                       res="ok"
-               else
+               res="ok"
+               if [ "x$directive" == "x" ]; then
                        res="not ok"
-               fi
-       else
-               # test is expected to pass
-               if [ $pass_yaml == "1" ]; then
-                       diff_yaml=0
-                       # diff -u "$dir/test.event" "$t" | sed -e 's/^/# /'
-                       diff -u "$dir/test.event" "$t"
+
+                       pass_yaml=0
+                       ${TOP_BUILDDIR}/src/fy-tool --testsuite "$tst/in.yaml" >"$t"
                        if [ $? -eq 0 ]; then
-                               res="ok"
+                               pass_yaml=1
+                       fi
+
+                       if [ -e "$tst/error" ]; then
+                               # test is expected to fail
+                               if [ $pass_yaml == "0" ]; then
+                                       res="ok"
+                               else
+                                       res="not ok"
+                               fi
                        else
-                               res="not ok"
+                               # test is expected to pass
+                               if [ $pass_yaml == "1" ]; then
+                                       diff_yaml=0
+                                       # diff -u "$tst/test.event" "$t" | sed -e 's/^/# /'
+                                       diff -u "$tst/test.event" "$t"
+                                       if [ $? -eq 0 ]; then
+                                               res="ok"
+                                       else
+                                               res="not ok"
+                                       fi
+                               else
+                                       res="not ok"
+                               fi
                        fi
-               else
-                       res="not ok"
-               fi
-       fi
 
-       rm -f "$t"
+                       rm -f "$t"
+
+                       for xfail in $xfaillist; do
+                               if [ "$test_subtest_id" == "$xfail" ]; then
+                                       directive=" # TODO: known failure."
+                                       break
+                               fi
+                       done
+               fi
 
-       echo "$res $i $tdir - $desctxt"
+               echo "$res $i $test_subtest_id - $desctxt$directive"
+       done
 done