From: Jose Luis Blanco Claraco Date: Fri, 14 Jan 2022 21:50:46 +0000 (+0100) Subject: New upstream version 0.7.11 X-Git-Tag: archive/raspbian/0.9.4-1+rpi1~1^2~51^2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4ed2739df80a3a8e6fe7c0558328e32251746b08;p=libfyaml.git New upstream version 0.7.11 --- diff --git a/.libtool-version b/.libtool-version new file mode 100644 index 0000000..a759e95 --- /dev/null +++ b/.libtool-version @@ -0,0 +1 @@ +1:1:0 diff --git a/.tarball-version b/.tarball-version index f38fc53..b4d6d12 100644 --- a/.tarball-version +++ b/.tarball-version @@ -1 +1 @@ -0.7.3 +0.7.11 diff --git a/Makefile.in b/Makefile.in index 239085e..0b7bbc8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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@ diff --git a/README.md b/README.md index 4883f16..72e9c9a 100644 --- 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")); diff --git a/configure b/configure index fa33dd7..a2abd76 100755 --- 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 . # @@ -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 :: +# 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} diff --git a/configure.ac b/configure.ac index 4d198f5..8a495ec 100644 --- a/configure.ac +++ b/configure.ac @@ -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 :: +# 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} diff --git a/doc/Makefile.am b/doc/Makefile.am index d93a491..9902908 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -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 diff --git a/doc/Makefile.in b/doc/Makefile.in index ca57d4b..de17f1f 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -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 index 0000000..d9d4b56 --- /dev/null +++ b/doc/canned-man/fy-tool.1 @@ -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. +. diff --git a/doc/man/fy-tool.rst b/doc/man/fy-tool.rst index 5da4b9e..0d482f1 100644 --- a/doc/man/fy-tool.rst +++ b/doc/man/fy-tool.rst @@ -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 -------- diff --git a/include/libfyaml.h b/include/libfyaml.h index 61ffdb2..bf01077 100644 --- a/include/libfyaml.h +++ b/include/libfyaml.h @@ -1,7 +1,7 @@ /* * libfyaml.h - Main header file of the public interface * - * Copyright (c) 2019 Pantelis Antoniou + * Copyright (c) 2019-2021 Pantelis Antoniou * * 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 diff --git a/libfyaml.pc.in b/libfyaml.pc.in index bf9d8d5..cde577a 100644 --- a/libfyaml.pc.in +++ b/libfyaml.pc.in @@ -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@ diff --git a/src/Makefile.am b/src/Makefile.am index 67688a9..9c06116 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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) diff --git a/src/Makefile.in b/src/Makefile.in index 65e9b36..fd57f09 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -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 diff --git a/src/internal/libfyaml-parser.c b/src/internal/libfyaml-parser.c index 3f8a5c3..a59c071 100644 --- a/src/internal/libfyaml-parser.c +++ b/src/internal/libfyaml-parser.c @@ -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; diff --git a/src/lib/fy-atom.c b/src/lib/fy-atom.c index 9ce4a0d..d6e6086 100644 --- a/src/lib/fy-atom.c +++ b/src/lib/fy-atom.c @@ -25,44 +25,6 @@ #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); diff --git a/src/lib/fy-atom.h b/src/lib/fy-atom.h index 188f200..9041f21 100644 --- a/src/lib/fy-atom.h +++ b/src/lib/fy-atom.h @@ -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); diff --git a/src/lib/fy-composer.c b/src/lib/fy-composer.c index f44db63..3e19017 100644 --- a/src/lib/fy-composer.c +++ b/src/lib/fy-composer.c @@ -23,10 +23,6 @@ #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; -} diff --git a/src/lib/fy-composer.h b/src/lib/fy-composer.h index 4cfea8d..d690f22 100644 --- a/src/lib/fy-composer.h +++ b/src/lib/fy-composer.h @@ -23,16 +23,16 @@ #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 diff --git a/src/lib/fy-diag.c b/src/lib/fy-diag.c index 4820226..a8fc935 100644 --- a/src/lib/fy-diag.c +++ b/src/lib/fy-diag.c @@ -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, diff --git a/src/lib/fy-diag.h b/src/lib/fy-diag.h index 38dd257..2653db5 100644 --- a/src/lib/fy-diag.h +++ b/src/lib/fy-diag.h @@ -50,15 +50,11 @@ #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) \ ({ \ diff --git a/src/lib/fy-doc.c b/src/lib/fy-doc.c index a61d95f..359ea92 100644 --- a/src/lib/fy-doc.c +++ b/src/lib/fy-doc.c @@ -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] : "", - // 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] : ""); - 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 = ""; \ - } 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: != %s\n", __func__, fy_node_get_path_a(fypn2->fyn)); - } - if (!fypn2) { - if (fypn1) - fprintf(stderr, "%s: %s != \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; +} diff --git a/src/lib/fy-doc.h b/src/lib/fy-doc.h index 54b29b1..6c15024 100644 --- a/src/lib/fy-doc.h +++ b/src/lib/fy-doc.h @@ -29,9 +29,16 @@ #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 index 0000000..94f6606 --- /dev/null +++ b/src/lib/fy-docbuilder.c @@ -0,0 +1,540 @@ +/* + * fy-docbuilder.c - YAML document builder methods + * + * Copyright (c) 2022 Pantelis Antoniou + * + * SPDX-License-Identifier: MIT + */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include + +#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 index 0000000..aa506d6 --- /dev/null +++ b/src/lib/fy-docbuilder.h @@ -0,0 +1,98 @@ +/* + * fy-docbuilder.h - YAML document builder internal header file + * + * Copyright (c) 2022 Pantelis Antoniou + * + * SPDX-License-Identifier: MIT + */ +#ifndef FY_DOCBUILDER_H +#define FY_DOCBUILDER_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#include + +#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 diff --git a/src/lib/fy-docstate.c b/src/lib/fy-docstate.c index 554c6f0..e7876e4 100644 --- a/src/lib/fy-docstate.c +++ b/src/lib/fy-docstate.c @@ -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) { diff --git a/src/lib/fy-docstate.h b/src/lib/fy-docstate.h index 80cd43d..380c5f0 100644 --- a/src/lib/fy-docstate.h +++ b/src/lib/fy-docstate.h @@ -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 */ diff --git a/src/lib/fy-emit.c b/src/lib/fy-emit.c index c66b451..36d8d8e 100644 --- a/src/lib/fy-emit.c +++ b/src/lib/fy-emit.c @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -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; } diff --git a/src/lib/fy-emit.h b/src/lib/fy-emit.h index a01ee50..3bbd8b5 100644 --- a/src/lib/fy-emit.h +++ b/src/lib/fy-emit.h @@ -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); diff --git a/src/lib/fy-event.c b/src/lib/fy-event.c index 231ed04..222b87e 100644 --- a/src/lib/fy-event.c +++ b/src/lib/fy-event.c @@ -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); +} diff --git a/src/lib/fy-event.h b/src/lib/fy-event.h index 3153f8c..75f20fb 100644 --- a/src/lib/fy-event.h +++ b/src/lib/fy-event.h @@ -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 diff --git a/src/lib/fy-input.c b/src/lib/fy-input.c index 29b1945..c411408 100644 --- a/src/lib/fy-input.c +++ b/src/lib/fy-input.c @@ -29,6 +29,13 @@ #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, "", 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, "", + ret = asprintf(&fyi->name, "", fyic->memory.data, fyic->memory.data + fyic->memory.size - 1); if (ret == -1) fyi->name = NULL; break; case fyit_alloc: - ret = asprintf(&fyi->name, "", + ret = asprintf(&fyi->name, "", 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; diff --git a/src/lib/fy-input.h b/src/lib/fy-input.h index 61316d2..618f3b8 100644 --- a/src/lib/fy-input.h +++ b/src/lib/fy-input.h @@ -20,6 +20,7 @@ #include +#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; diff --git a/src/lib/fy-parse.c b/src/lib/fy-parse.c index 3f59fe7..3c8618d 100644 --- a/src/lib/fy-parse.c +++ b/src/lib/fy-parse.c @@ -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 ? : ""; 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; diff --git a/src/lib/fy-parse.h b/src/lib/fy-parse.h index 19ff7dd..df278fc 100644 --- a/src/lib/fy-parse.h +++ b/src/lib/fy-parse.h @@ -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 diff --git a/src/lib/fy-path.c b/src/lib/fy-path.c index 948b1c7..f9d9f99 100644 --- a/src/lib/fy-path.c +++ b/src/lib/fy-path.c @@ -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; diff --git a/src/lib/fy-path.h b/src/lib/fy-path.h index 73157f9..22dde9c 100644 --- a/src/lib/fy-path.h +++ b/src/lib/fy-path.h @@ -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); diff --git a/src/lib/fy-token.c b/src/lib/fy-token.c index 984fec0..7fa7c0f 100644 --- a/src/lib/fy-token.c +++ b/src/lib/fy-token.c @@ -33,48 +33,12 @@ 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; diff --git a/src/lib/fy-token.h b/src/lib/fy-token.h index 3281204..a464955 100644 --- a/src/lib/fy-token.h +++ b/src/lib/fy-token.h @@ -19,6 +19,7 @@ #include +#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 diff --git a/src/lib/fy-utils.c b/src/lib/fy-utils.c index 3707110..8b55ccb 100644 --- a/src/lib/fy-utils.c +++ b/src/lib/fy-utils.c @@ -15,6 +15,11 @@ #include #include #include +#include +#include +#include +#include +#include #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;;;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; +} diff --git a/src/lib/fy-utils.h b/src/lib/fy-utils.h index 4840550..cf3e3c5 100644 --- a/src/lib/fy-utils.h +++ b/src/lib/fy-utils.h @@ -15,6 +15,8 @@ #include #include +#include +#include #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 diff --git a/src/lib/fy-walk.c b/src/lib/fy-walk.c index ad108f1..736704d 100644 --- a/src/lib/fy-walk.c +++ b/src/lib/fy-walk.c @@ -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); diff --git a/src/tool/fy-tool.c b/src/tool/fy-tool.c index 0740acb..bb46c0a 100644 --- a/src/tool/fy-tool.c +++ b/src/tool/fy-tool.c @@ -50,6 +50,10 @@ #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 @@ -77,6 +81,10 @@ #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 : Disable diag error module \n"); fprintf(fp, "\t--enable-diag : Enable diag error module \n"); - fprintf(fp, "\t--show-diag-diag : Show diag option \n"); + fprintf(fp, "\t--show-diag : Show diag option \n"); fprintf(fp, "\t--hide-diag : Hide diag optione \n"); fprintf(fp, "\t--indent, -i : Set dump indent to " @@ -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 : Output mode can be one of original, block, flow, flow-oneline, json, json-tp, json-oneline, dejson" + fprintf(fp, "\t--mode, -m : 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; } diff --git a/test/Makefile.am b/test/Makefile.am index 0c87edf..8b6802d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -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: diff --git a/test/Makefile.in b/test/Makefile.in index c73b09d..265d7e4 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -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 index 0000000..2f35be2 --- /dev/null +++ b/test/testsuite-evstream.test @@ -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 diff --git a/test/testsuite-json.test b/test/testsuite-json.test index 9b87ecc..794d515 100755 --- a/test/testsuite-json.test +++ b/test/testsuite-json.test @@ -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 diff --git a/test/testsuite.test b/test/testsuite.test index d711d4b..1883d00 100755 --- a/test/testsuite.test +++ b/test/testsuite.test @@ -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