aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Shafer <phil@FreeBSD.org>2023-01-30 04:10:53 +0000
committerPhil Shafer <phil@FreeBSD.org>2023-01-30 04:10:53 +0000
commit7087c8de43b0d5d27c52da6ba2ba4957b7e336ff (patch)
tree72d4cef4104344468fd5196dd8f0ce4dbe765039
parentb1cbac9ff49d141064601671b4f3af79b4d06ab5 (diff)
downloadsrc-vendor/Juniper/libxo.tar.gz
src-vendor/Juniper/libxo.zip
Vendor import of Juniper libxo at 1.6.0vendor/Juniper/libxo
-rw-r--r--.travis.yml12
-rw-r--r--LICENSE23
-rw-r--r--README.md2
-rw-r--r--configure.ac23
-rw-r--r--doc/_static/basic.css_t657
-rw-r--r--doc/_templates/localtoc.html14
-rw-r--r--doc/api.rst1702
-rw-r--r--doc/conf.py186
-rw-r--r--doc/encoders.rst274
-rw-r--r--doc/example.rst694
-rw-r--r--doc/faq.rst211
-rw-r--r--doc/field-formatting.rst371
-rw-r--r--doc/field-modifiers.rst353
-rw-r--r--doc/field-roles.rst317
-rw-r--r--doc/format-strings.rst47
-rw-r--r--doc/formatting.rst165
-rw-r--r--doc/getting.rst185
-rw-r--r--doc/howto.rst394
-rw-r--r--doc/index.rst54
-rw-r--r--doc/intro.rst90
-rw-r--r--doc/options.rst184
-rw-r--r--doc/xo.rst234
-rw-r--r--doc/xohtml.rst30
-rw-r--r--doc/xolint-errors.rst444
-rw-r--r--doc/xolint.rst40
-rw-r--r--doc/xopo.rst45
-rw-r--r--encoder/test/enc_test.c2
-rw-r--r--libxo/Makefile.am3
-rw-r--r--libxo/gen-wide.sh76
-rw-r--r--libxo/libxo-csv.73
-rw-r--r--libxo/libxo.c514
-rw-r--r--libxo/xo.h25
-rw-r--r--libxo/xo_buf.h32
-rw-r--r--libxo/xo_config.h.in254
-rw-r--r--libxo/xo_emit.329
-rw-r--r--libxo/xo_emit_f.3121
-rw-r--r--libxo/xo_emit_field.3113
-rw-r--r--libxo/xo_humanize.h2
-rw-r--r--libxo/xo_options.7177
-rw-r--r--libxo/xo_syslog.c20
-rw-r--r--packaging/libxo.spec44
-rw-r--r--tests/core/Makefile.am24
-rw-r--r--tests/core/saved/test_01.E.out10
-rw-r--r--tests/core/saved/test_01.H.out2
-rw-r--r--tests/core/saved/test_01.HIPx.out25
-rw-r--r--tests/core/saved/test_01.HP.out25
-rw-r--r--tests/core/saved/test_01.J.out2
-rw-r--r--tests/core/saved/test_01.JP.out14
-rw-r--r--tests/core/saved/test_01.JPu.out14
-rw-r--r--tests/core/saved/test_01.T.out5
-rw-r--r--tests/core/saved/test_01.X.out2
-rw-r--r--tests/core/saved/test_01.XP.out10
-rw-r--r--tests/core/saved/test_01.err (renamed from tests/core/saved/test_13.E.err)0
-rw-r--r--tests/core/saved/test_01.out38
-rw-r--r--tests/core/saved/test_02.err (renamed from tests/core/saved/test_13.H.err)0
-rw-r--r--tests/core/saved/test_02.out38
-rw-r--r--tests/core/saved/test_03.err (renamed from tests/core/saved/test_13.HIPx.err)0
-rw-r--r--tests/core/saved/test_03.out3
-rw-r--r--tests/core/saved/test_10.err (renamed from tests/core/saved/test_13.HP.err)0
-rw-r--r--tests/core/saved/test_10.out38
-rw-r--r--tests/core/saved/test_12.E.out8
-rw-r--r--tests/core/saved/test_12.H.out2
-rw-r--r--tests/core/saved/test_12.HIPx.out10
-rw-r--r--tests/core/saved/test_12.HP.out6
-rw-r--r--tests/core/saved/test_12.J.out2
-rw-r--r--tests/core/saved/test_12.JP.out16
-rw-r--r--tests/core/saved/test_12.JPu.out16
-rw-r--r--tests/core/saved/test_12.T.out1
-rw-r--r--tests/core/saved/test_12.X.out2
-rw-r--r--tests/core/saved/test_12.XP.out12
-rw-r--r--tests/core/saved/test_13.E.out170
-rw-r--r--tests/core/saved/test_13.H.out1
-rw-r--r--tests/core/saved/test_13.HIPx.out236
-rw-r--r--tests/core/saved/test_13.HP.out236
-rw-r--r--tests/core/saved/test_13.J.err0
-rw-r--r--tests/core/saved/test_13.J.out1
-rw-r--r--tests/core/saved/test_13.JP.err0
-rw-r--r--tests/core/saved/test_13.JP.out159
-rw-r--r--tests/core/saved/test_13.JPu.err0
-rw-r--r--tests/core/saved/test_13.JPu.out159
-rw-r--r--tests/core/saved/test_13.T.err0
-rw-r--r--tests/core/saved/test_13.T.out11
-rw-r--r--tests/core/saved/test_13.X.err0
-rw-r--r--tests/core/saved/test_13.X.out1
-rw-r--r--tests/core/saved/test_13.XP.err0
-rw-r--r--tests/core/saved/test_13.XP.out155
-rw-r--r--tests/core/test_01.c10
-rw-r--r--tests/core/test_12.c15
-rw-r--r--tests/core/test_13.c248
-rw-r--r--xo/xo.c7
90 files changed, 7247 insertions, 2653 deletions
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 000000000000..1173578bbd5d
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,12 @@
+language: c
+
+script: printenv && uname -a && ls -l && /bin/sh -x ./bin/setup.sh && cd build && ../configure --enable-warnings && make && sudo make install && make test
+
+notifications:
+ recipients:
+ - libslax-noise@googlegroups.com
+
+branches:
+ only:
+ - master
+ - develop
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 000000000000..874da7b2d8a8
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2014, Juniper Networks
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index 35a34b5726c2..fdba97a001bb 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ xo_emit call:
```
xo_emit(" {:lines/%7ju/%ju} {:words/%7ju/%ju} "
"{:characters/%7ju/%ju}{d:filename/%s}\n",
- line_count, word_count, char_count, file);
+ linect, wordct, charct, file);
```
Output can then be generated in various style, using the "--libxo"
diff --git a/configure.ac b/configure.ac
index ed8b64aa63f3..2f5681d4276f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -82,8 +82,7 @@ AC_CHECK_LIB([util], [humanize_number],
[HAVE_HUMANIZE_NUMBER=$ac_cv_header_libutil_h],
[HAVE_HUMANIZE_NUMBER=no])
-AC_MSG_CHECKING([humanize_number results])
-AC_MSG_RESULT(:${HAVE_HUMANIZE_NUMBER}:${ac_cv_header_libutil_h}:)
+AC_MSG_RESULT(humanize_number results: :${HAVE_HUMANIZE_NUMBER}:${ac_cv_header_libutil_h}:)
if test "$HAVE_HUMANIZE_NUMBER" = "yes"; then
AC_DEFINE([HAVE_HUMANIZE_NUMBER], [1], [humanize_number(3)])
@@ -177,25 +176,6 @@ AC_SUBST(GETTEXT_BINDIR)
AM_CONDITIONAL([HAVE_GETTEXT], [test "$HAVE_GETTEXT" = "yes"])
-dnl on macosx, strings are not in the .text segment, making the call
-dnl to get_etext pointless
-AC_MSG_CHECKING([style of etext])
-AC_LINK_IFELSE([AC_LANG_SOURCE([
- [#include <stdio.h>]
- [extern char etext;]
- [int main() { const char *p = &etext; printf("%p\n", p); return 0; }]])],
- [HAVE_ETEXT=1 ; HAVE_ETEXT_STYLE="symbol"],
- AC_LINK_IFELSE([AC_LANG_SOURCE([
- [#include <stdio.h>]
- [#include <mach-o/getsect.h>]
- [int main() { const char *p = (const char *) get_etext(); printf("%p\n", p); return 0; }]])],
- [HAVE_ETEXT=2 ; HAVE_ETEXT_STYLE="function"],
- [HAVE_ETEXT=0 ; HAVE_ETEXT_STYLE="none"]
- )
-)
-AC_MSG_RESULT(${HAVE_ETEXT_STYLE})
-AC_DEFINE_UNQUOTED([HAVE_ETEXT], [$HAVE_ETEXT], [Style of etext])
-
dnl Looking for how to do thread-local variables
AC_ARG_WITH(threads,
[ --with-threads=[STYLE] Specify style of thread-local support (none)],
@@ -517,5 +497,4 @@ AC_MSG_NOTICE([summary of build options:
thread-local: ${THREAD_LOCAL:-no}
local wcwidth: ${LIBXO_WCWIDTH:-no}
retain size: ${XO_RETAIN_SIZE:-no}
- have etext: ${HAVE_ETEXT:-no} (${HAVE_ETEXT_STYLE})
])
diff --git a/doc/_static/basic.css_t b/doc/_static/basic.css_t
new file mode 100644
index 000000000000..e8ebdc780dbc
--- /dev/null
+++ b/doc/_static/basic.css_t
@@ -0,0 +1,657 @@
+/*
+ * basic.css
+ * ~~~~~~~~~
+ *
+ * Sphinx stylesheet -- basic theme.
+ *
+ * :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
+ * :license: BSD, see LICENSE for details.
+ *
+ */
+
+/* -- main layout ----------------------------------------------------------- */
+
+div.clearer {
+ clear: both;
+}
+
+/* -- relbar ---------------------------------------------------------------- */
+
+div.related {
+ width: 100%;
+ font-size: 90%;
+}
+
+div.related h3 {
+ display: none;
+}
+
+div.related ul {
+ margin: 0;
+ padding: 0 0 0 10px;
+ list-style: none;
+}
+
+div.related li {
+ display: inline;
+}
+
+div.related li.right {
+ float: right;
+ margin-right: 5px;
+}
+
+/* -- sidebar --------------------------------------------------------------- */
+
+div.sphinxsidebarwrapper {
+ padding: 10px 5px 0 10px;
+}
+
+div.sphinxsidebar {
+ float: left;
+ width: {{ theme_sidebarwidth|toint }}px;
+ margin-left: -100%;
+ font-size: 90%;
+ word-wrap: break-word;
+ overflow-wrap : break-word;
+}
+
+div.sphinxsidebar ul {
+ list-style: none;
+}
+
+div.sphinxsidebar ul ul,
+div.sphinxsidebar ul.want-points {
+ margin-left: 20px;
+ list-style: square;
+}
+
+div.sphinxsidebar ul ul {
+ margin-top: 0;
+ margin-bottom: 0;
+}
+
+div.sphinxsidebar form {
+ margin-top: 10px;
+}
+
+div.sphinxsidebar input {
+ border: 1px solid #98dbcc;
+ font-family: sans-serif;
+ font-size: 1em;
+}
+
+div.sphinxsidebar #searchbox input[type="text"] {
+ width: 170px;
+}
+
+img {
+ border: 0;
+ max-width: 100%;
+}
+
+/* -- search page ----------------------------------------------------------- */
+
+ul.search {
+ margin: 10px 0 0 20px;
+ padding: 0;
+}
+
+ul.search li {
+ padding: 5px 0 5px 20px;
+ background-image: url(file.png);
+ background-repeat: no-repeat;
+ background-position: 0 7px;
+}
+
+ul.search li a {
+ font-weight: bold;
+}
+
+ul.search li div.context {
+ color: #888;
+ margin: 2px 0 0 30px;
+ text-align: left;
+}
+
+ul.keywordmatches li.goodmatch a {
+ font-weight: bold;
+}
+
+/* -- index page ------------------------------------------------------------ */
+
+table.contentstable {
+ width: 90%;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+table.contentstable p.biglink {
+ line-height: 150%;
+}
+
+a.biglink {
+ font-size: 1.3em;
+}
+
+span.linkdescr {
+ font-style: italic;
+ padding-top: 5px;
+ font-size: 90%;
+}
+
+/* -- general index --------------------------------------------------------- */
+
+table.indextable {
+ width: 100%;
+}
+
+table.indextable td {
+ text-align: left;
+ vertical-align: top;
+}
+
+table.indextable ul {
+ margin-top: 0;
+ margin-bottom: 0;
+ list-style-type: none;
+}
+
+table.indextable > tbody > tr > td > ul {
+ padding-left: 0em;
+}
+
+table.indextable tr.pcap {
+ height: 10px;
+}
+
+table.indextable tr.cap {
+ margin-top: 10px;
+ background-color: #f2f2f2;
+}
+
+img.toggler {
+ margin-right: 3px;
+ margin-top: 3px;
+ cursor: pointer;
+}
+
+div.modindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+div.genindex-jumpbox {
+ border-top: 1px solid #ddd;
+ border-bottom: 1px solid #ddd;
+ margin: 1em 0 1em 0;
+ padding: 0.4em;
+}
+
+/* -- domain module index --------------------------------------------------- */
+
+table.modindextable td {
+ padding: 2px;
+ border-collapse: collapse;
+}
+
+/* -- general body styles --------------------------------------------------- */
+
+div.body p, div.body dd, div.body li, div.body blockquote {
+ -moz-hyphens: auto;
+ -ms-hyphens: auto;
+ -webkit-hyphens: auto;
+ hyphens: auto;
+}
+
+a.headerlink {
+ visibility: hidden;
+}
+
+h1:hover > a.headerlink,
+h2:hover > a.headerlink,
+h3:hover > a.headerlink,
+h4:hover > a.headerlink,
+h5:hover > a.headerlink,
+h6:hover > a.headerlink,
+dt:hover > a.headerlink,
+caption:hover > a.headerlink,
+p.caption:hover > a.headerlink,
+div.code-block-caption:hover > a.headerlink {
+ visibility: visible;
+}
+
+div.body p.caption {
+ text-align: inherit;
+}
+
+div.body td {
+ text-align: left;
+}
+
+blockquote.epigraph p.attribution {
+ margin-left: 50%;
+}
+
+blockquote.epigraph {
+ background-color: #eee;
+ padding: 0.5em;
+}
+
+.first {
+ margin-top: 0 !important;
+}
+
+p.rubric {
+ margin-top: 30px;
+ font-weight: bold;
+}
+
+img.align-left, .figure.align-left, object.align-left {
+ clear: left;
+ float: left;
+ margin-right: 1em;
+}
+
+img.align-right, .figure.align-right, object.align-right {
+/* clear: right; */
+ float: right;
+ margin-left: 1em;
+}
+
+img.align-center, .figure.align-center, object.align-center {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.align-left {
+ text-align: left;
+}
+
+.align-center {
+ text-align: center;
+}
+
+.align-right {
+ text-align: right;
+}
+
+/* -- sidebars -------------------------------------------------------------- */
+
+div.sidebar {
+ margin: 1em 1em 1em 1em;
+ border: 1px solid #ddb;
+ padding: 7px 7px 0 7px;
+ background-color: #ffe;
+ width: 40%;
+ float: right;
+}
+
+p.sidebar-title {
+ font-weight: bold;
+}
+
+/* -- topics ---------------------------------------------------------------- */
+
+div.topic {
+ border: 1px solid #ccc;
+ padding: 7px 7px 0 7px;
+ margin: 10px 0 10px 0;
+}
+
+p.topic-title {
+ font-size: 1.1em;
+ font-weight: bold;
+ margin-top: 10px;
+}
+
+/* -- admonitions ----------------------------------------------------------- */
+
+div.admonition {
+ margin-top: 10px;
+ margin-bottom: 10px;
+ padding: 7px;
+}
+
+div.admonition dt {
+ font-weight: bold;
+}
+
+div.admonition dl {
+ margin-bottom: 0;
+}
+
+p.admonition-title {
+ margin: 0px 10px 5px 0px;
+ font-weight: bold;
+}
+
+div.body p.centered {
+ text-align: center;
+ margin-top: 25px;
+}
+
+/* -- tables ---------------------------------------------------------------- */
+
+table.docutils {
+ border: 0;
+ border-collapse: collapse;
+}
+
+table caption span.caption-number {
+ font-style: italic;
+}
+
+table caption span.caption-text {
+}
+
+dl.function table.docutils th.field-name {
+ width: 100px;
+}
+
+table.docutils td, table.docutils th {
+ padding: 1px 8px 1px 5px;
+ border-top: 1px solid #aaa;
+ border-left: 1px solid #aaa;
+ border-right: 1px solid #aaa;
+ border-bottom: 1px solid #aaa;
+}
+
+table.docutils th {
+ border-bottom: 2px solid #aaa;
+ background-color: #f2f2f2;
+}
+
+table.footnote td, table.footnote th {
+ border: 0 !important;
+}
+
+th {
+ text-align: left;
+ padding-right: 5px;
+}
+
+table.citation {
+ border-left: solid 1px gray;
+ margin-left: 1px;
+}
+
+table.citation td {
+ border-bottom: none;
+}
+
+/* -- figures --------------------------------------------------------------- */
+
+div.figure {
+ margin: 0.5em;
+ padding: 0.5em;
+}
+
+div.figure p.caption {
+ padding: 0.3em;
+}
+
+div.figure p.caption span.caption-number {
+ font-style: italic;
+}
+
+div.figure p.caption span.caption-text {
+}
+
+/* -- field list styles ----------------------------------------------------- */
+
+table.field-list td, table.field-list th {
+ border: 0 !important;
+}
+
+.field-list ul {
+ margin: 0;
+ padding-left: 1em;
+}
+
+.field-list p {
+ margin: 0;
+}
+
+.field-name {
+ -moz-hyphens: manual;
+ -ms-hyphens: manual;
+ -webkit-hyphens: manual;
+ hyphens: manual;
+}
+
+/* -- other body styles ----------------------------------------------------- */
+
+ol.arabic {
+ list-style: decimal;
+}
+
+ol.loweralpha {
+ list-style: lower-alpha;
+}
+
+ol.upperalpha {
+ list-style: upper-alpha;
+}
+
+ol.lowerroman {
+ list-style: lower-roman;
+}
+
+ol.upperroman {
+ list-style: upper-roman;
+}
+
+dl {
+ margin-bottom: 15px;
+}
+
+dd p {
+ margin-top: 0px;
+}
+
+dd ul, dd table {
+ margin-bottom: 10px;
+}
+
+dd {
+ margin-top: 3px;
+ margin-bottom: 10px;
+ margin-left: 30px;
+}
+
+dt:target, .highlighted {
+ background-color: #fbe54e;
+}
+
+dl.glossary dt {
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.optional {
+ font-size: 1.3em;
+}
+
+.sig-paren {
+ font-size: larger;
+}
+
+.versionmodified {
+ font-style: italic;
+}
+
+.system-message {
+ background-color: #fda;
+ padding: 5px;
+ border: 3px solid red;
+}
+
+.footnote:target {
+ background-color: #ffa;
+}
+
+.line-block {
+ display: block;
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+.line-block .line-block {
+ margin-top: 0;
+ margin-bottom: 0;
+ margin-left: 1.5em;
+}
+
+.guilabel, .menuselection {
+ font-family: sans-serif;
+}
+
+.accelerator {
+ text-decoration: underline;
+}
+
+.classifier {
+ font-style: oblique;
+}
+
+abbr, acronym {
+ border-bottom: dotted 1px;
+ cursor: help;
+}
+
+/* -- code displays --------------------------------------------------------- */
+
+pre {
+ overflow: auto;
+ overflow-y: hidden; /* fixes display issues on Chrome browsers */
+}
+
+span.pre {
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ -webkit-hyphens: none;
+ hyphens: none;
+}
+
+td.linenos pre {
+ padding: 5px 0px;
+ border: 0;
+ background-color: transparent;
+ color: #aaa;
+}
+
+table.highlighttable {
+ margin-left: 0.5em;
+}
+
+table.highlighttable td {
+ padding: 0 0.5em 0 0.5em;
+}
+
+div.code-block-caption {
+ padding: 2px 5px;
+ font-size: small;
+}
+
+div.code-block-caption code {
+ background-color: transparent;
+}
+
+div.code-block-caption + div > div.highlight > pre {
+ margin-top: 0;
+}
+
+div.code-block-caption span.caption-number {
+ padding: 0.1em 0.3em;
+ font-style: italic;
+}
+
+div.code-block-caption span.caption-text {
+}
+
+div.literal-block-wrapper {
+ padding: 1em 1em 0;
+}
+
+div.literal-block-wrapper div.highlight {
+ margin: 0;
+}
+
+code.descname {
+ background-color: transparent;
+ font-weight: bold;
+ font-size: 1.2em;
+}
+
+code.descclassname {
+ background-color: transparent;
+}
+
+code.xref, a code {
+ background-color: transparent;
+ font-weight: bold;
+}
+
+h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
+ background-color: transparent;
+}
+
+.viewcode-link {
+ float: right;
+}
+
+.viewcode-back {
+ float: right;
+ font-family: sans-serif;
+}
+
+div.viewcode-block:target {
+ margin: -1px -10px;
+ padding: 0 10px;
+}
+
+/* -- math display ---------------------------------------------------------- */
+
+img.math {
+ vertical-align: middle;
+}
+
+div.body div.math p {
+ text-align: center;
+}
+
+span.eqno {
+ float: right;
+}
+
+span.eqno a.headerlink {
+ position: relative;
+ left: 0px;
+ z-index: 1;
+}
+
+div.math:hover a.headerlink {
+ visibility: visible;
+}
+
+/* -- printout stylesheet --------------------------------------------------- */
+
+@media print {
+ div.document,
+ div.documentwrapper,
+ div.bodywrapper {
+ margin: 0 !important;
+ width: 100%;
+ }
+
+ div.sphinxsidebar,
+ div.related,
+ div.footer,
+ #top-link {
+ display: none;
+ }
+}
diff --git a/doc/_templates/localtoc.html b/doc/_templates/localtoc.html
new file mode 100644
index 000000000000..14fdb12a53cc
--- /dev/null
+++ b/doc/_templates/localtoc.html
@@ -0,0 +1,14 @@
+{#
+ basic/localtoc.html
+ ~~~~~~~~~~~~~~~~~~~
+
+ Sphinx sidebar template: local table of contents.
+
+ :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
+ :license: BSD, see LICENSE for details.
+#}
+{%- if display_toc %}
+ <h3><a href="{{ pathto(master_doc) }}">{{ _('On This Page') }}</a></h3>
+ {{ toc }}
+ <h3><a href="{{ pathto(master_doc) }}">{{ _('Full Documentation') }}</a></h3>
+{%- endif %}
diff --git a/doc/api.rst b/doc/api.rst
new file mode 100644
index 000000000000..8a9b7bb5cefe
--- /dev/null
+++ b/doc/api.rst
@@ -0,0 +1,1702 @@
+.. index:: API
+
+The libxo API
+=============
+
+This section gives details about the functions in libxo, how to call
+them, and the actions they perform.
+
+.. index:: Handles
+.. _handles:
+
+Handles
+-------
+
+libxo uses "handles" to control its rendering functionality. The
+handle contains state and buffered data, as well as callback functions
+to process data.
+
+Handles give an abstraction for libxo that encapsulates the state of a
+stream of output. Handles have the data type "`xo_handle_t`" and are
+opaque to the caller.
+
+The library has a default handle that is automatically initialized.
+By default, this handle will send text style output (`XO_STYLE_TEXT`) to
+standard output. The xo_set_style and xo_set_flags functions can be
+used to change this behavior.
+
+For the typical command that is generating output on standard output,
+there is no need to create an explicit handle, but they are available
+when needed, e.g., for daemons that generate multiple streams of
+output.
+
+Many libxo functions take a handle as their first parameter; most that
+do not use the default handle. Any function taking a handle can be
+passed NULL to access the default handle. For the convenience of
+callers, the libxo library includes handle-less functions that
+implicitly use the default handle.
+
+For example, the following are equivalent::
+
+ xo_emit("test");
+ xo_emit_h(NULL, "test");
+
+Handles are created using `xo_create` and destroy using
+`xo_destroy`.
+
+.. index:: xo_create
+
+xo_create
+~~~~~~~~~
+
+.. c:function:: xo_handle_t *xo_create (xo_style_t style, xo_xof_flags_t flags)
+
+ The `xo_create` function allocates a new handle which can be passed
+ to further libxo function calls. The `xo_handle_t` structure is
+ opaque.
+
+ :param xo_style_t style: Output style (XO_STYLE\_*)
+ :param xo_xof_flags_t flags: Flags for this handle (XOF\_*)
+ :return: New libxo handle
+ :rtype: xo_handle_t \*
+
+ ::
+
+ EXAMPLE:
+ xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN | XOF_PRETTY);
+ ....
+ xo_emit_h(xop, "testing\n");
+
+ See also :ref:`output-styles` and :ref:`flags`.
+
+.. index:: xo_create_to_file
+.. index:: XOF_CLOSE_FP
+
+xo_create_to_file
+~~~~~~~~~~~~~~~~~
+
+.. c:function::
+ xo_handle_t *xo_create_to_file (FILE *fp, unsigned style, unsigned flags)
+
+ The `xo_create_to_file` function is aconvenience function is
+ provided for situations when output should be written to a different
+ file, rather than the default of standard output.
+
+ The `XOF_CLOSE_FP` flag can be set on the returned handle to trigger a
+ call to fclose() for the FILE pointer when the handle is destroyed,
+ avoiding the need for the caller to perform this task.
+
+ :param fp: FILE to use as base for this handle
+ :type fp: FILE *
+ :param xo_style_t style: Output style (XO_STYLE\_*)
+ :param xo_xof_flags_t flags: Flags for this handle (XOF\_*)
+ :return: New libxo handle
+ :rtype: xo_handle_t \*
+
+.. index:: xo_set_writer
+.. index:: xo_write_func_t
+.. index:: xo_close_func_t
+.. index:: xo_flush_func_t
+
+xo_set_writer
+~~~~~~~~~~~~~
+
+.. c:function::
+ void xo_set_writer (xo_handle_t *xop, void *opaque, \
+ xo_write_func_t write_func, xo_close_func_t close_func, \
+ xo_flush_func_t flush_func)
+
+ The `xo_set_writer` function allows custom functions which can
+ tailor how libxo writes data. The `opaque` argument is recorded and
+ passed back to the functions, allowing the function to acquire
+ context information. The *write_func* function writes data to the
+ output stream. The *close_func* function can release this opaque
+ data and any other resources as needed. The *flush_func* function
+ is called to flush buffered data associated with the opaque object.
+
+ :param xop: Handle to modify (or NULL for default handle)
+ :type xop: xo_handle_t *
+ :param opaque: Pointer to opaque data passed to the given functions
+ :type opaque: void *
+ :param xo_write_func_t write_func: New write function
+ :param xo_close_func_t close_func: New close function
+ :param xo_flush_func_t flush_func: New flush function
+ :returns: void
+
+.. index:: xo_get_style
+
+xo_get_style
+~~~~~~~~~~~~
+
+.. c:function:: xo_style_t xo_get_style(xo_handle_t *xop)
+
+ Use the `xo_get_style` function to find the current output style for
+ a given handle. To use the default handle, pass a `NULL` handle.
+
+ :param xop: Handle to interrogate (or NULL for default handle)
+ :type xop: xo_handle_t *
+ :returns: Output style (XO_STYLE\_*)
+ :rtype: xo_style_t
+
+ ::
+
+ EXAMPLE::
+ style = xo_get_style(NULL);
+
+.. index:: XO_STYLE_TEXT
+.. index:: XO_STYLE_XML
+.. index:: XO_STYLE_JSON
+.. index:: XO_STYLE_HTML
+
+.. _output-styles:
+
+Output Styles (XO_STYLE\_\*)
+++++++++++++++++++++++++++++
+
+The libxo functions accept a set of output styles:
+
+ =============== =========================
+ Flag Description
+ =============== =========================
+ XO_STYLE_TEXT Traditional text output
+ XO_STYLE_XML XML encoded data
+ XO_STYLE_JSON JSON encoded data
+ XO_STYLE_HTML HTML encoded data
+ =============== =========================
+
+The "XML", "JSON", and "HTML" output styles all use the UTF-8
+character encoding. "TEXT" using locale-based encoding.
+
+.. index:: xo_set_style
+
+xo_set_style
+~~~~~~~~~~~~
+
+.. c:function:: void xo_set_style(xo_handle_t *xop, xo_style_t style)
+
+ The `xo_set_style` function is used to change the output style
+ setting for a handle. To use the default handle, pass a `NULL`
+ handle.
+
+ :param xop: Handle to modify
+ :type xop: xo_handle_t *
+ :param xo_style_t style: Output style (XO_STYLE\_*)
+ :returns: void
+
+ ::
+
+ EXAMPLE:
+ xo_set_style(NULL, XO_STYLE_XML);
+
+.. index:: xo_set_style_name
+
+xo_set_style_name
+~~~~~~~~~~~~~~~~~
+
+.. c:function:: int xo_set_style_name (xo_handle_t *xop, const char *style)
+
+ The `xo_set_style_name` function can be used to set the style based
+ on a name encoded as a string: The name can be any of the supported
+ styles: "text", "xml", "json", or "html".
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param style: Text name of the style
+ :type style: const char \*
+ :returns: zero for success, non-zero for error
+ :rtype: int
+
+ ::
+
+ EXAMPLE:
+ xo_set_style_name(NULL, "html");
+
+.. index:: xo_set_flags
+
+xo_set_flags
+~~~~~~~~~~~~
+
+.. c:function:: void xo_set_flags(xo_handle_t *xop, xo_xof_flags_t flags)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param xo_xof_flags_t flags: Flags to add for the handle
+ :returns: void
+
+ Use the `xo_set_flags` function to turn on flags for a given libxo
+ handle. To use the default handle, pass a `NULL` handle.
+
+ ::
+
+ EXAMPLE:
+ xo_set_flags(NULL, XOF_PRETTY | XOF_WARN);
+
+.. index:: Flags; XOF_*
+.. index:: XOF_CLOSE_FP
+.. index:: XOF_COLOR
+.. index:: XOF_COLOR_ALLOWED
+.. index:: XOF_DTRT
+.. index:: XOF_INFO
+.. index:: XOF_KEYS
+.. index:: XOF_NO_ENV
+.. index:: XOF_NO_HUMANIZE
+.. index:: XOF_PRETTY
+.. index:: XOF_UNDERSCORES
+.. index:: XOF_UNITS
+.. index:: XOF_WARN
+.. index:: XOF_WARN_XML
+.. index:: XOF_XPATH
+.. index:: XOF_COLUMNS
+.. index:: XOF_FLUSH
+
+.. _flags:
+
+Flags (XOF\_\*)
++++++++++++++++
+
+The set of valid flags include:
+
+ =================== =========================================
+ Flag Description
+ =================== =========================================
+ XOF_CLOSE_FP Close file pointer on `xo_destroy`
+ XOF_COLOR Enable color and effects in output
+ XOF_COLOR_ALLOWED Allow color/effect for terminal output
+ XOF_DTRT Enable "do the right thing" mode
+ XOF_INFO Display info data attributes (HTML)
+ XOF_KEYS Emit the key attribute (XML)
+ XOF_NO_ENV Do not use the :ref:`libxo-options` env var
+ XOF_NO_HUMANIZE Display humanization (TEXT, HTML)
+ XOF_PRETTY Make "pretty printed" output
+ XOF_UNDERSCORES Replaces hyphens with underscores
+ XOF_UNITS Display units (XML, HMTL)
+ XOF_WARN Generate warnings for broken calls
+ XOF_WARN_XML Generate warnings in XML on stdout
+ XOF_XPATH Emit XPath expressions (HTML)
+ XOF_COLUMNS Force xo_emit to return columns used
+ XOF_FLUSH Flush output after each `xo_emit` call
+ =================== =========================================
+
+The `XOF_CLOSE_FP` flag will trigger the call of the *close_func*
+(provided via `xo_set_writer`) when the handle is destroyed.
+
+The `XOF_COLOR` flag enables color and effects in output regardless
+of output device, while the `XOF_COLOR_ALLOWED` flag allows color
+and effects only if the output device is a terminal.
+
+The `XOF_PRETTY` flag requests "pretty printing", which will trigger
+the addition of indentation and newlines to enhance the readability of
+XML, JSON, and HTML output. Text output is not affected.
+
+The `XOF_WARN` flag requests that warnings will trigger diagnostic
+output (on standard error) when the library notices errors during
+operations, or with arguments to functions. Without warnings enabled,
+such conditions are ignored.
+
+Warnings allow developers to debug their interaction with libxo.
+The function `xo_failure` can used as a breakpoint for a debugger,
+regardless of whether warnings are enabled.
+
+If the style is `XO_STYLE_HTML`, the following additional flags can be
+used:
+
+ =============== =========================================
+ Flag Description
+ =============== =========================================
+ XOF_XPATH Emit "data-xpath" attributes
+ XOF_INFO Emit additional info fields
+ =============== =========================================
+
+The `XOF_XPATH` flag enables the emission of XPath expressions detailing
+the hierarchy of XML elements used to encode the data field, if the
+XPATH style of output were requested.
+
+The `XOF_INFO` flag encodes additional informational fields for HTML
+output. See :ref:`field-information` for details.
+
+If the style is `XO_STYLE_XML`, the following additional flags can be
+used:
+
+ =============== =========================================
+ Flag Description
+ =============== =========================================
+ XOF_KEYS Flag "key" fields for XML
+ =============== =========================================
+
+The `XOF_KEYS` flag adds "key" attribute to the XML encoding for
+field definitions that use the "k" modifier. The key attribute has
+the value "key"::
+
+ xo_emit("{k:name}", item);
+
+ XML:
+ <name key="key">truck</name>
+
+.. index:: xo_clear_flags
+
+xo_clear_flags
+++++++++++++++
+
+.. c:function:: void xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param xo_xof_flags_t flags: Flags to clear for the handle
+ :returns: void
+
+ Use the `xo_clear_flags` function to turn off the given flags in a
+ specific handle. To use the default handle, pass a `NULL` handle.
+
+.. index:: xo_set_options
+
+xo_set_options
+++++++++++++++
+
+.. c:function:: int xo_set_options (xo_handle_t *xop, const char *input)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param input: string containing options to set
+ :type input: const char *
+ :returns: zero for success, non-zero for error
+ :rtype: int
+
+ The `xo_set_options` function accepts a comma-separated list of
+ output styles and modifier flags and enables them for a specific
+ handle. The options are identical to those listed in
+ :ref:`options`. To use the default handle, pass a `NULL` handle.
+
+.. index:: xo_destroy
+
+xo_destroy
+++++++++++
+
+.. c:function:: void xo_destroy(xo_handle_t *xop)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :returns: void
+
+ The `xo_destroy` function releases a handle and any resources it is
+ using. Calling `xo_destroy` with a `NULL` handle will release any
+ resources associated with the default handle.
+
+.. index:: xo_emit
+
+Emitting Content (xo_emit)
+--------------------------
+
+The functions in this section are used to emit output. They use a
+`format` string containing field descriptors as specified in
+:ref:`format-strings`. The use of a handle is optional and `NULL` can
+be passed to access the internal "default" handle. See
+:ref:`handles`.
+
+The remaining arguments to `xo_emit` and `xo_emit_h` are a set of
+arguments corresponding to the fields in the format string. Care must
+be taken to ensure the argument types match the fields in the format
+string, since an inappropriate or missing argument can ruin your day.
+The `vap` argument to `xo_emit_hv` points to a variable argument list
+that can be used to retrieve arguments via `va_arg`.
+
+.. c:function:: xo_ssize_t xo_emit (const char *fmt, ...)
+
+ :param fmt: The format string, followed by zero or more arguments
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+.. c:function:: xo_ssize_t xo_emit_h (xo_handle_t *xop, const char *fmt, ...)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param fmt: The format string, followed by zero or more arguments
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+.. c:function:: xo_ssize_t xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param fmt: The format string
+ :param va_list vap: A set of variadic arguments
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+.. index:: xo_emit_field
+
+Single Field Emitting Functions (xo_emit_field)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The functions in this section emit formatted output similar to
+`xo_emit` but where `xo_emit` uses a single string argument containing
+the description for multiple fields, `xo_emit_field` emits a single
+field using multiple ar- guments to contain the field description.
+`xo_emit_field_h` adds an ex- plicit handle to use instead of the
+default handle, while `xo_emit_field_hv` accepts a va_list for
+additional flexibility.
+
+The arguments `rolmod`, `content`, `fmt`, and `efmt` are detailed in
+:ref:`field-formatting`. Using distinct arguments allows callers to
+pass the field description in pieces, rather than having to use
+something like `snprintf` to build the format string required by
+`xo_emit`. The arguments are each NUL-terminated strings. The `rolmod`
+argument contains the `role` and `modifier` portions of the field
+description, the `content` argument contains the `content` portion, and
+the `fmt` and `efmt` contain the `field-format` and `encoding-format` por-
+tions, respectively.
+
+As with `xo_emit`, the `fmt` and `efmt` values are both optional,
+since the `field-format` string defaults to "%s", and the
+`encoding-format`'s default value is derived from the `field-format`
+per :ref:`field-formatting`. However, care must be taken to avoid
+using a value directly as the format, since characters like '{', '%',
+and '}' will be interpreted as formatting directives, and may cause
+xo_emit_field to dereference arbitrary values off the stack, leading
+to bugs, core files, and gnashing of teeth.
+
+.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *content, const char *fmt, const char *efmt, ...)
+
+ :param rolmod: A comma-separated list of field roles and field modifiers
+ :type rolmod: const char *
+ :param content: The "content" portion of the field description string
+ :type content: const char *
+ :param fmt: Contents format string
+ :type fmt: const char *
+ :param efmt: Encoding format string, followed by additional arguments
+ :type efmt: const char *
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+ ::
+
+ EXAMPLE::
+ xo_emit_field("T", title, NULL, NULL, NULL);
+ xo_emit_field("T", "Host name is ", NULL, NULL);
+ xo_emit_field("V", "host-name", NULL, NULL, host-name);
+ xo_emit_field(",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
+ "gum", 1412);
+
+.. c:function:: xo_ssize_t xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param rolmod: A comma-separated list of field roles and field modifiers
+ :type rolmod: const char *
+ :param contents: The "contents" portion of the field description string
+ :type contents: const char *
+ :param fmt: Content format string
+ :type fmt: const char *
+ :param efmt: Encoding format string, followed by additional arguments
+ :type efmt: const char *
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+.. c:function:: xo_ssize_t xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, va_list vap)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :param rolmod: A comma-separated list of field roles and field modifiers
+ :type rolmod: const char *
+ :param contents: The "contents" portion of the field description string
+ :type contents: const char *
+ :param fmt: Content format string
+ :type fmt: const char *
+ :param efmt: Encoding format string
+ :type efmt: const char *
+ :param va_list vap: A set of variadic arguments
+ :returns: If XOF_COLUMNS is set, the number of columns used; otherwise the number of bytes emitted
+ :rtype: xo_ssize_t
+
+.. index:: xo_attr
+.. _xo_attr:
+
+Attributes (xo_attr)
+~~~~~~~~~~~~~~~~~~~~
+
+The functions in this section emit an XML attribute with the given name
+and value. This only affects the XML output style.
+
+The `name` parameter give the name of the attribute to be encoded. The
+`fmt` parameter gives a printf-style format string used to format the
+value of the attribute using any remaining arguments, or the vap
+parameter passed to `xo_attr_hv`.
+
+All attributes recorded via `xo_attr` are placed on the next
+container, instance, leaf, or leaf list that is emitted.
+
+Since attributes are only emitted in XML, their use should be limited
+to meta-data and additional or redundant representations of data
+already emitted in other form.
+
+.. c:function:: xo_ssize_t xo_attr (const char *name, const char *fmt, ...)
+
+ :param name: Attribute name
+ :type name: const char *
+ :param fmt: Attribute value, as variadic arguments
+ :type fmt: const char *
+ :returns: -1 for error, or the number of bytes in the formatted attribute value
+ :rtype: xo_ssize_t
+
+ ::
+
+ EXAMPLE:
+ xo_attr("seconds", "%ld", (unsigned long) login_time);
+ struct tm *tmp = localtime(login_time);
+ strftime(buf, sizeof(buf), "%R", tmp);
+ xo_emit("Logged in at {:login-time}\n", buf);
+ XML:
+ <login-time seconds="1408336270">00:14</login-time>
+
+
+.. c:function:: xo_ssize_t xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...)
+
+ :param xop: Handle for modify (or NULL for default handle)
+ :type xop: xo_handle_t \*
+
+ The `xo_attr_h` function follows the conventions of `xo_attr` but
+ adds an explicit libxo handle.
+
+.. c:function:: xo_ssize_t xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap)
+
+ The `xo_attr_h` function follows the conventions of `xo_attr_h`
+ but replaced the variadic list with a variadic pointer.
+
+.. index:: xo_flush
+
+Flushing Output (xo_flush)
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. c:function:: xo_ssize_t xo_flush (void)
+
+ :returns: -1 for error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ libxo buffers data, both for performance and consistency, but also
+ to allow for the proper function of various advanced features. At
+ various times, the caller may wish to flush any data buffered within
+ the library. The `xo_flush` call is used for this.
+
+ Calling `xo_flush` also triggers the flush function associated with
+ the handle. For the default handle, this is equivalent to
+ "fflush(stdio);".
+
+.. c:function:: xo_ssize_t xo_flush_h (xo_handle_t *xop)
+
+ :param xop: Handle for flush (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :returns: -1 for error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_flush_h` function follows the conventions of `xo_flush`,
+ but adds an explicit libxo handle.
+
+.. index:: xo_finish
+.. index:: xo_finish_atexit
+.. index:: atexit
+
+Finishing Output (xo_finish)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When the program is ready to exit or close a handle, a call to
+`xo_finish` or `xo_finish_h` is required. This flushes any buffered
+data, closes open libxo constructs, and completes any pending
+operations.
+
+Calling this function is vital to the proper operation of libxo,
+especially for the non-TEXT output styles.
+
+.. c:function:: xo_ssize_t xo_finish (void)
+
+ :returns: -1 on error, or the number of bytes flushed
+ :rtype: xo_ssize_t
+
+.. c:function:: xo_ssize_t xo_finish_h (xo_handle_t *xop)
+
+ :param xop: Handle for finish (or NULL for default handle)
+ :type xop: xo_handle_t \*
+ :returns: -1 on error, or the number of bytes flushed
+ :rtype: xo_ssize_t
+
+.. c:function:: void xo_finish_atexit (void)
+
+ The `xo_finish_atexit` function is suitable for use with
+ :manpage:`atexit(3)` to ensure that `xo_finish` is called
+ on the default handle when the application exits.
+
+.. index:: UTF-8
+.. index:: xo_open_container
+.. index:: xo_close_container
+
+Emitting Hierarchy
+------------------
+
+libxo represents two types of hierarchy: containers and lists. A
+container appears once under a given parent where a list consists of
+instances that can appear multiple times. A container is used to hold
+related fields and to give the data organization and scope.
+
+.. index:: YANG
+
+.. admonition:: YANG Terminology
+
+ libxo uses terminology from YANG (:RFC:`7950`), the data modeling
+ language for NETCONF: container, list, leaf, and leaf-list.
+
+For XML and JSON, individual fields appear inside hierarchies which
+provide context and meaning to the fields. Unfortunately, these
+encoding have a basic disconnect between how lists is similar objects
+are represented.
+
+XML encodes lists as set of sequential elements::
+
+ <user>phil</user>
+ <user>pallavi</user>
+ <user>sjg</user>
+
+JSON encodes lists using a single name and square brackets::
+
+ "user": [ "phil", "pallavi", "sjg" ]
+
+This means libxo needs three distinct indications of hierarchy: one
+for containers of hierarchy appear only once for any specific parent,
+one for lists, and one for each item in a list.
+
+.. index:: Containers
+
+Containers
+~~~~~~~~~~
+
+A "*container*" is an element of a hierarchy that appears only once
+under any specific parent. The container has no value, but serves to
+contain and organize other nodes.
+
+To open a container, call xo_open_container() or
+xo_open_container_h(). The former uses the default handle and the
+latter accepts a specific handle. To close a level, use the
+xo_close_container() or xo_close_container_h() functions.
+
+Each open call must have a matching close call. If the XOF_WARN flag
+is set and the name given does not match the name of the currently open
+container, a warning will be generated.
+
+.. c:function:: xo_ssize_t xo_open_container (const char *name)
+
+ :param name: Name of the container
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `name` parameter gives the name of the container, encoded in
+ UTF-8. Since ASCII is a proper subset of UTF-8, traditional C
+ strings can be used directly.
+
+.. c:function:: xo_ssize_t xo_open_container_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_open_container_h` function adds a `handle` parameter.
+
+.. c:function:: xo_ssize_t xo_close_container (const char *name)
+
+ :param name: Name of the container
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+.. c:function:: xo_ssize_t xo_close_container_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_close_container_h` function adds a `handle` parameter.
+
+Use the :index:`XOF_WARN` flag to generate a warning if the name given
+on the close does not match the current open container.
+
+For TEXT and HTML output, containers are not rendered into output
+text, though for HTML they are used to record an XPath value when the
+:index:`XOF_XPATH` flag is set.
+
+::
+
+ EXAMPLE:
+ xo_open_container("top");
+ xo_open_container("system");
+ xo_emit("{:host-name/%s%s%s}", hostname,
+ domainname ? "." : "", domainname ?: "");
+ xo_close_container("system");
+ xo_close_container("top");
+ TEXT:
+ my-host.example.org
+ XML:
+ <top>
+ <system>
+ <host-name>my-host.example.org</host-name>
+ </system>
+ </top>
+ JSON:
+ "top" : {
+ "system" : {
+ "host-name": "my-host.example.org"
+ }
+ }
+ HTML:
+ <div class="data"
+ data-tag="host-name">my-host.example.org</div>
+
+.. index:: xo_open_instance
+.. index:: xo_close_instance
+.. index:: xo_open_list
+.. index:: xo_close_list
+
+Lists and Instances
+~~~~~~~~~~~~~~~~~~~
+
+A "*list*" is set of one or more instances that appear under the same
+parent. The instances contain details about a specific object. One
+can think of instances as objects or records. A call is needed to
+open and close the list, while a distinct call is needed to open and
+close each instance of the list.
+
+The name given to all calls must be identical, and it is strongly
+suggested that the name be singular, not plural, as a matter of
+style and usage expectations::
+
+ EXAMPLE:
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+ xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+
+Getting the list and instance calls correct is critical to the proper
+generation of XML and JSON data.
+
+Opening Lists
++++++++++++++
+
+.. c:function:: xo_ssize_t xo_open_list (const char *name)
+
+ :param name: Name of the list
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_open_list` function open a list of instances.
+
+.. c:function:: xo_ssize_t xo_open_list_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+Closing Lists
++++++++++++++
+
+.. c:function:: xo_ssize_t xo_close_list (const char *name)
+
+ :param name: Name of the list
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_close_list` function closes a list of instances.
+
+.. c:function:: xo_ssize_t xo_close_list_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_close_container_h` function adds a `handle` parameter.
+
+Opening Instances
++++++++++++++++++
+
+.. c:function:: xo_ssize_t xo_open_instance (const char *name)
+
+ :param name: Name of the instance (same as the list name)
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_open_instance` function open a single instance.
+
+.. c:function:: xo_ssize_t xo_open_instance_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_open_instance_h` function adds a `handle` parameter.
+
+Closing Instances
++++++++++++++++++
+
+.. c:function:: xo_ssize_t xo_close_instance (const char *name)
+
+ :param name: Name of the instance
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_close_instance` function closes an open instance.
+
+.. c:function:: xo_ssize_t xo_close_instance_h (xo_handle_t *xop, const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_close_instance_h` function adds a `handle` parameter.
+
+ ::
+
+ EXAMPLE:
+ xo_open_list("user");
+ for (i = 0; i < num_users; i++) {
+ xo_open_instance("user");
+ xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n",
+ pw[i].pw_name, pw[i].pw_uid,
+ pw[i].pw_gid, pw[i].pw_dir);
+ xo_close_instance("user");
+ }
+ xo_close_list("user");
+ TEXT:
+ phil:1001:1001:/home/phil
+ pallavi:1002:1002:/home/pallavi
+ XML:
+ <user>
+ <name>phil</name>
+ <uid>1001</uid>
+ <gid>1001</gid>
+ <home>/home/phil</home>
+ </user>
+ <user>
+ <name>pallavi</name>
+ <uid>1002</uid>
+ <gid>1002</gid>
+ <home>/home/pallavi</home>
+ </user>
+ JSON:
+ user: [
+ {
+ "name": "phil",
+ "uid": 1001,
+ "gid": 1001,
+ "home": "/home/phil",
+ },
+ {
+ "name": "pallavi",
+ "uid": 1002,
+ "gid": 1002,
+ "home": "/home/pallavi",
+ }
+ ]
+
+Markers
+~~~~~~~
+
+Markers are used to protect and restore the state of open hierarchy
+constructs (containers, lists, or instances). While a marker is open,
+no other open constructs can be closed. When a marker is closed, all
+constructs open since the marker was opened will be closed.
+
+Markers use names which are not user-visible, allowing the caller to
+choose appropriate internal names.
+
+In this example, the code whiffles through a list of fish, calling a
+function to emit details about each fish. The marker "fish-guts" is
+used to ensure that any constructs opened by the function are closed
+properly::
+
+ EXAMPLE:
+ for (i = 0; fish[i]; i++) {
+ xo_open_instance("fish");
+ xo_open_marker("fish-guts");
+ dump_fish_details(i);
+ xo_close_marker("fish-guts");
+ }
+
+.. c:function:: xo_ssize_t xo_open_marker(const char *name)
+
+ :param name: Name of the instance
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_open_marker` function records the current state of open tags
+ in order for `xo_close_marker` to close them at some later point.
+
+.. c:function:: xo_ssize_t xo_open_marker_h(const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_open_marker_h` function adds a `handle` parameter.
+
+.. c:function:: xo_ssize_t xo_close_marker(const char *name)
+
+ :param name: Name of the instance
+ :type name: const char *
+ :returns: -1 on error, or the number of bytes generated
+ :rtype: xo_ssize_t
+
+ The `xo_close_marker` function closes any open containers, lists, or
+ instances as needed to return to the state recorded when
+ `xo_open_marker` was called with the matching name.
+
+.. c:function:: xo_ssize_t xo_close_marker(const char *name)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_close_marker_h` function adds a `handle` parameter.
+
+DTRT Mode
+~~~~~~~~~
+
+Some users may find tracking the names of open containers, lists, and
+instances inconvenient. libxo offers a "Do The Right Thing" mode, where
+libxo will track the names of open containers, lists, and instances so
+the close function can be called without a name. To enable DTRT mode,
+turn on the XOF_DTRT flag prior to making any other libxo output::
+
+ xo_set_flags(NULL, XOF_DTRT);
+
+.. index:: XOF_DTRT
+
+Each open and close function has a version with the suffix "_d", which
+will close the open container, list, or instance::
+
+ xo_open_container_d("top");
+ ...
+ xo_close_container_d();
+
+This also works for lists and instances::
+
+ xo_open_list_d("item");
+ for (...) {
+ xo_open_instance_d("item");
+ xo_emit(...);
+ xo_close_instance_d();
+ }
+ xo_close_list_d();
+
+.. index:: XOF_WARN
+
+Note that the XOF_WARN flag will also cause libxo to track open
+containers, lists, and instances. A warning is generated when the
+name given to the close function and the name recorded do not match.
+
+Support Functions
+-----------------
+
+.. index:: xo_parse_args
+.. _xo_parse_args:
+
+Parsing Command-line Arguments (xo_parse_args)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. c:function:: int xo_parse_args (int argc, char **argv)
+
+ :param int argc: Number of arguments
+ :param argv: Array of argument strings
+ :return: -1 on error, or the number of remaining arguments
+ :rtype: int
+
+ The `xo_parse_args` function is used to process a program's
+ arguments. libxo-specific options are processed and removed from
+ the argument list so the calling application does not need to
+ process them. If successful, a new value for argc is returned. On
+ failure, a message is emitted and -1 is returned::
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(EXIT_FAILURE);
+
+ Following the call to xo_parse_args, the application can process the
+ remaining arguments in a normal manner. See :ref:`options` for a
+ description of valid arguments.
+
+.. index:: xo_set_program
+
+xo_set_program
+~~~~~~~~~~~~~~
+
+.. c:function:: void xo_set_program (const char *name)
+
+ :param name: Name to use as the program name
+ :type name: const char *
+ :returns: void
+
+ The `xo_set_program` function sets the name of the program as
+ reported by functions like `xo_failure`, `xo_warn`, `xo_err`, etc.
+ The program name is initialized by `xo_parse_args`, but subsequent
+ calls to `xo_set_program` can override this value::
+
+ EXAMPLE:
+ xo_set_program(argv[0]);
+
+ Note that the value is not copied, so the memory passed to
+ `xo_set_program` (and `xo_parse_args`) must be maintained by the
+ caller.
+
+.. index:: xo_set_version
+
+xo_set_version
+~~~~~~~~~~~~~~
+
+.. c:function:: void xo_set_version (const char *version)
+
+ :param name: Value to use as the version string
+ :type name: const char *
+ :returns: void
+
+ The `xo_set_version` function records a version number to be emitted
+ as part of the data for encoding styles (XML and JSON). This
+ version number is suitable for tracking changes in the content,
+ allowing a user of the data to discern which version of the data
+ model is in use.
+
+.. c:function:: void xo_set_version_h (xo_handle_t *xop, const char *version)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+
+ The `xo_set_version` function adds a `handle` parameter.
+
+.. index:: --libxo
+.. index:: XOF_INFO
+.. index:: xo_info_t
+
+.. _field-information:
+
+Field Information (xo_info_t)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+HTML data can include additional information in attributes that
+begin with "data-". To enable this, three things must occur:
+
+First the application must build an array of xo_info_t structures,
+one per tag. The array must be sorted by name, since libxo uses a
+binary search to find the entry that matches names from format
+instructions.
+
+Second, the application must inform libxo about this information using
+the `xo_set_info` call::
+
+ typedef struct xo_info_s {
+ const char *xi_name; /* Name of the element */
+ const char *xi_type; /* Type of field */
+ const char *xi_help; /* Description of field */
+ } xo_info_t;
+
+ void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);
+
+Like other libxo calls, passing `NULL` for the handle tells libxo to
+use the default handle.
+
+If the count is -1, libxo will count the elements of infop, but there
+must be an empty element at the end. More typically, the number is
+known to the application::
+
+ xo_info_t info[] = {
+ { "in-stock", "number", "Number of items in stock" },
+ { "name", "string", "Name of the item" },
+ { "on-order", "number", "Number of items on order" },
+ { "sku", "string", "Stock Keeping Unit" },
+ { "sold", "number", "Number of items sold" },
+ };
+ int info_count = (sizeof(info) / sizeof(info[0]));
+ ...
+ xo_set_info(NULL, info, info_count);
+
+Third, the emission of info must be triggered with the `XOF_INFO` flag
+using either the `xo_set_flags` function or the "`--libxo=info`"
+command line argument.
+
+The type and help values, if present, are emitted as the "data-type"
+and "data-help" attributes::
+
+ <div class="data" data-tag="sku" data-type="string"
+ data-help="Stock Keeping Unit">GRO-000-533</div>
+
+.. c:function:: void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count)
+
+ :param xop: Handle to use (or NULL for default handle)
+ :type xop: xo_handle_t *
+ :param infop: Array of information structures
+ :type infop: xo_info_t *
+ :returns: void
+
+.. index:: xo_set_allocator
+.. index:: xo_realloc_func_t
+.. index:: xo_free_func_t
+
+Memory Allocation
+~~~~~~~~~~~~~~~~~
+
+The `xo_set_allocator` function allows libxo to be used in
+environments where the standard :manpage:`realloc(3)` and
+:manpage:`free(3)` functions are not appropriate.
+
+.. c:function:: void xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func)
+
+ :param xo_realloc_func_t realloc_func: Allocation function
+ :param xo_free_func_t free_func: Free function
+
+ *realloc_func* should expect the same arguments as
+ :manpage:`realloc(3)` and return a pointer to memory following the
+ same convention. *free_func* will receive the same argument as
+ :manpage:`free(3)` and should release it, as appropriate for the
+ environment.
+
+By default, the standard :manpage:`realloc(3)` and :manpage:`free(3)`
+functions are used.
+
+.. index:: --libxo
+
+.. _libxo-options:
+
+LIBXO_OPTIONS
+~~~~~~~~~~~~~
+
+The environment variable "LIBXO_OPTIONS" can be set to a subset of
+libxo options, including:
+
+- color
+- flush
+- flush-line
+- no-color
+- no-humanize
+- no-locale
+- no-retain
+- pretty
+- retain
+- underscores
+- warn
+
+For example, warnings can be enabled by::
+
+ % env LIBXO_OPTIONS=warn my-app
+
+Since environment variables are inherited, child processes will have
+the same options, which may be undesirable, making the use of the
+"`--libxo`" command-line option preferable in most situations.
+
+.. index:: xo_warn
+.. index:: xo_err
+.. index:: xo_errx
+.. index:: xo_message
+
+Errors, Warnings, and Messages
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Many programs make use of the standard library functions
+:manpage:`err(3)` and :manpage:`warn(3)` to generate errors and
+warnings for the user. libxo wants to pass that information via the
+current output style, and provides compatible functions to allow
+this::
+
+ void xo_warn (const char *fmt, ...);
+ void xo_warnx (const char *fmt, ...);
+ void xo_warn_c (int code, const char *fmt, ...);
+ void xo_warn_hc (xo_handle_t *xop, int code,
+ const char *fmt, ...);
+ void xo_err (int eval, const char *fmt, ...);
+ void xo_errc (int eval, int code, const char *fmt, ...);
+ void xo_errx (int eval, const char *fmt, ...);
+
+::
+
+ void xo_message (const char *fmt, ...);
+ void xo_message_c (int code, const char *fmt, ...);
+ void xo_message_hc (xo_handle_t *xop, int code,
+ const char *fmt, ...);
+ void xo_message_hcv (xo_handle_t *xop, int code,
+ const char *fmt, va_list vap);
+
+These functions display the program name, a colon, a formatted message
+based on the arguments, and then optionally a colon and an error
+message associated with either *errno* or the *code* parameter::
+
+ EXAMPLE:
+ if (open(filename, O_RDONLY) < 0)
+ xo_err(1, "cannot open file '%s'", filename);
+
+.. index:: xo_error
+.. index:: xo_error_h
+.. index:: xo_error_hv
+.. index:: xo_errorn
+.. index:: xo_errorn_h
+.. index:: xo_errorn_hv
+
+xo_error
+~~~~~~~~
+
+.. c:function:: void xo_error (const char *fmt, ...)
+
+ :param fmt: Format string
+ :type fmt: const char *
+ :returns: void
+
+.. c:function:: void xo_error_h (xo_handle_t *xop, const char *fmt, ...)
+
+ :param xop: libxo handle pointer
+ :type xop: xo_handle_t *
+ :param fmt: Format string
+ :type fmt: const char *
+ :returns: void
+
+.. c:function:: void xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
+
+ :param xop: libxo handle pointer
+ :type xop: xo_handle_t *
+ :param fmt: Format string
+ :type fmt: const char *
+ :param vap: variadic arguments
+ :type xop: va_list
+ :returns: void
+
+.. c:function:: void xo_errorn (const char *fmt, ...)
+
+ :param fmt: Format string
+ :type fmt: const char *
+ :returns: void
+
+.. c:function:: void xo_errorn_h (xo_handle_t *xop, const char *fmt, ...)
+
+ :param xop: libxo handle pointer
+ :type xop: xo_handle_t *
+ :param fmt: Format string
+ :type fmt: const char *
+ :returns: void
+
+.. c:function:: void xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap)
+
+ :param xop: libxo handle pointer
+ :type xop: xo_handle_t *
+ :param need_newline: boolean indicating need for trailing newline
+ :type need_newline: int
+ :param fmt: Format string
+ :type fmt: const char *
+ :param vap: variadic arguments
+ :type xop: va_list
+ :returns: void
+
+ The `xo_error` function can be used for generic errors that should
+ be reported over the handle, rather than to stderr. The `xo_error`
+ function behaves like `xo_err` for TEXT and HTML output styles, but
+ puts the error into XML or JSON elements::
+
+ EXAMPLE::
+ xo_error("Does not %s", "compute");
+ XML::
+ <error><message>Does not compute</message></error>
+ JSON::
+ "error": { "message": "Does not compute" }
+
+ The `xo_error_h` and `xo_error_hv` add a handle object and a
+ variadic-ized parameter to the signature, respectively.
+
+ The `xo_errorn` function supplies a newline at the end the error
+ message if the format string does not include one. The
+ `xo_errorn_h` and `xo_errorn_hv` functions add a handle object and
+ a variadic-ized parameter to the signature, respectively. The
+ `xo_errorn_hv` function also adds a boolean to indicate the need for
+ a trailing newline.
+
+.. index:: xo_no_setlocale
+.. index:: Locale
+
+xo_no_setlocale
+~~~~~~~~~~~~~~~
+
+.. c:function:: void xo_no_setlocale (void)
+
+ libxo automatically initializes the locale based on setting of the
+ environment variables LC_CTYPE, LANG, and LC_ALL. The first of this
+ list of variables is used and if none of the variables, the locale
+ defaults to "UTF-8". The caller may wish to avoid this behavior,
+ and can do so by calling the `xo_no_setlocale` function.
+
+Emitting syslog Messages
+------------------------
+
+syslog is the system logging facility used throughout the unix world.
+Messages are sent from commands, applications, and daemons to a
+hierarchy of servers, where they are filtered, saved, and forwarded
+based on configuration behaviors.
+
+syslog is an older protocol, originally documented only in source
+code. By the time :RFC:`3164` published, variation and mutation left the
+leading "<pri>" string as only common content. :RFC:`5424` defines a new
+version (version 1) of syslog and introduces structured data into the
+messages. Structured data is a set of name/value pairs transmitted
+distinctly alongside the traditional text message, allowing filtering
+on precise values instead of regular expressions.
+
+These name/value pairs are scoped by a two-part identifier; an
+enterprise identifier names the party responsible for the message
+catalog and a name identifying that message. `Enterprise IDs`_ are
+defined by IANA, the Internet Assigned Numbers Authority.
+
+.. _Enterprise IDs:
+ https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+
+Use the `xo_set_syslog_enterprise_id` function to set the Enterprise
+ID, as needed.
+
+The message name should follow the conventions in
+:ref:`good-field-names`\ , as should the fields within the message::
+
+ /* Both of these calls are optional */
+ xo_set_syslog_enterprise_id(32473);
+ xo_open_log("my-program", 0, LOG_DAEMON);
+
+ /* Generate a syslog message */
+ xo_syslog(LOG_ERR, "upload-failed",
+ "error <%d> uploading file '{:filename}' "
+ "as '{:target/%s:%s}'",
+ code, filename, protocol, remote);
+
+ xo_syslog(LOG_INFO, "poofd-invalid-state",
+ "state {:current/%u} is invalid {:connection/%u}",
+ state, conn);
+
+The developer should be aware that the message name may be used in the
+future to allow access to further information, including
+documentation. Care should be taken to choose quality, descriptive
+names.
+
+.. _syslog-details:
+
+Priority, Facility, and Flags
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The `xo_syslog`, `xo_vsyslog`, and `xo_open_log` functions
+accept a set of flags which provide the priority of the message, the
+source facility, and some additional features. These values are OR'd
+together to create a single integer argument::
+
+ xo_syslog(LOG_ERR | LOG_AUTH, "login-failed",
+ "Login failed; user '{:user}' from host '{:address}'",
+ user, addr);
+
+These values are defined in <syslog.h>.
+
+The priority value indicates the importance and potential impact of
+each message:
+
+ ============= =======================================================
+ Priority Description
+ ============= =======================================================
+ LOG_EMERG A panic condition, normally broadcast to all users
+ LOG_ALERT A condition that should be corrected immediately
+ LOG_CRIT Critical conditions
+ LOG_ERR Generic errors
+ LOG_WARNING Warning messages
+ LOG_NOTICE Non-error conditions that might need special handling
+ LOG_INFO Informational messages
+ LOG_DEBUG Developer-oriented messages
+ ============= =======================================================
+
+The facility value indicates the source of message, in fairly generic
+terms:
+
+ =============== =======================================================
+ Facility Description
+ =============== =======================================================
+ LOG_AUTH The authorization system (e.g. :manpage:`login(1)`)
+ LOG_AUTHPRIV As LOG_AUTH, but logged to a privileged file
+ LOG_CRON The cron daemon: :manpage:`cron(8)`
+ LOG_DAEMON System daemons, not otherwise explicitly listed
+ LOG_FTP The file transfer protocol daemons
+ LOG_KERN Messages generated by the kernel
+ LOG_LPR The line printer spooling system
+ LOG_MAIL The mail system
+ LOG_NEWS The network news system
+ LOG_SECURITY Security subsystems, such as :manpage:`ipfw(4)`
+ LOG_SYSLOG Messages generated internally by :manpage:`syslogd(8)`
+ LOG_USER Messages generated by user processes (default)
+ LOG_UUCP The uucp system
+ LOG_LOCAL0..7 Reserved for local use
+ =============== =======================================================
+
+In addition to the values listed above, xo_open_log accepts a set of
+addition flags requesting specific logging behaviors:
+
+ ============ ====================================================
+ Flag Description
+ ============ ====================================================
+ LOG_CONS If syslogd fails, attempt to write to /dev/console
+ LOG_NDELAY Open the connection to :manpage:`syslogd(8)` immediately
+ LOG_PERROR Write the message also to standard error output
+ LOG_PID Log the process id with each message
+ ============ ====================================================
+
+.. index:: xo_syslog
+
+xo_syslog
+~~~~~~~~~
+
+.. c:function:: void xo_syslog (int pri, const char *name, const char *fmt, ...)
+
+ :param int pri: syslog priority
+ :param name: Name of the syslog event
+ :type name: const char *
+ :param fmt: Format string, followed by arguments
+ :type fmt: const char *
+ :returns: void
+
+ Use the `xo_syslog` function to generate syslog messages by calling
+ it with a log priority and facility, a message name, a format
+ string, and a set of arguments. The priority/facility argument are
+ discussed above, as is the message name.
+
+ The format string follows the same conventions as `xo_emit`'s format
+ string, with each field being rendered as an SD-PARAM pair::
+
+ xo_syslog(LOG_ERR, "poofd-missing-file",
+ "'{:filename}' not found: {:error/%m}", filename);
+
+ ... [poofd-missing-file@32473 filename="/etc/poofd.conf"
+ error="Permission denied"] '/etc/poofd.conf' not
+ found: Permission denied
+
+Support functions
+~~~~~~~~~~~~~~~~~
+
+.. index:: xo_vsyslog
+
+xo_vsyslog
+++++++++++
+
+.. c:function:: void xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)
+
+ :param int pri: syslog priority
+ :param name: Name of the syslog event
+ :type name: const char *
+ :param fmt: Format string
+ :type fmt: const char *
+ :param va_list vap: Variadic argument list
+ :returns: void
+
+ xo_vsyslog is identical in function to xo_syslog, but takes the set of
+ arguments using a va_list::
+
+ EXAMPLE:
+ void
+ my_log (const char *name, const char *fmt, ...)
+ {
+ va_list vap;
+ va_start(vap, fmt);
+ xo_vsyslog(LOG_ERR, name, fmt, vap);
+ va_end(vap);
+ }
+
+.. index:: xo_open_log
+
+xo_open_log
++++++++++++
+
+.. c:function:: void xo_open_log (const char *ident, int logopt, int facility)
+
+ :param indent:
+ :type indent: const char *
+ :param int logopt: Bit field containing logging options
+ :param int facility:
+ :returns: void
+
+ xo_open_log functions similar to :manpage:`openlog(3)`, allowing
+ customization of the program name, the log facility number, and the
+ additional option flags described in :ref:`syslog-details`.
+
+.. index:: xo_close_log
+
+xo_close_log
+++++++++++++
+
+.. c:function:: void xo_close_log (void)
+
+ The `xo_close_log` function is similar to :manpage:`closelog(3)`,
+ closing the log file and releasing any associated resources.
+
+.. index:: xo_set_logmask
+
+xo_set_logmask
+++++++++++++++
+
+.. c:function:: int xo_set_logmask (int maskpri)
+
+ :param int maskpri: the log priority mask
+ :returns: The previous log priority mask
+
+ The `xo_set_logmask` function is similar to :manpage:`setlogmask(3)`,
+ restricting the set of generated log event to those whose associated
+ bit is set in maskpri. Use `LOG_MASK(pri)` to find the appropriate bit,
+ or `LOG_UPTO(toppri)` to create a mask for all priorities up to and
+ including toppri::
+
+ EXAMPLE:
+ setlogmask(LOG_UPTO(LOG_WARN));
+
+.. index:: xo_set_syslog_enterprise_id
+
+xo_set_syslog_enterprise_id
++++++++++++++++++++++++++++
+
+.. c:function:: void xo_set_syslog_enterprise_id (unsigned short eid)
+
+ Use the `xo_set_syslog_enterprise_id` to supply a platform- or
+ application-specific enterprise id. This value is used in any future
+ syslog messages.
+
+ Ideally, the operating system should supply a default value via the
+ "kern.syslog.enterprise_id" sysctl value. Lacking that, the
+ application should provide a suitable value.
+
+Enterprise IDs are administered by IANA, the Internet Assigned Number
+Authority. The complete list is EIDs on their web site::
+
+ https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
+
+New EIDs can be requested from IANA using the following page::
+
+ http://pen.iana.org/pen/PenApplication.page
+
+Each software development organization that defines a set of syslog
+messages should register their own EID and use that value in their
+software to ensure that messages can be uniquely identified by the
+combination of EID + message name.
+
+Creating Custom Encoders
+------------------------
+
+The number of encoding schemes in current use is staggering, with new
+and distinct schemes appearing daily. While libxo provide XML, JSON,
+HMTL, and text natively, there are requirements for other encodings.
+
+Rather than bake support for all possible encoders into libxo, the API
+allows them to be defined externally. libxo can then interfaces with
+these encoding modules using a simplistic API. libxo processes all
+functions calls, handles state transitions, performs all formatting,
+and then passes the results as operations to a customized encoding
+function, which implements specific encoding logic as required. This
+means your encoder doesn't need to detect errors with unbalanced
+open/close operations but can rely on libxo to pass correct data.
+
+By making a simple API, libxo internals are not exposed, insulating the
+encoder and the library from future or internal changes.
+
+The three elements of the API are:
+
+- loading
+- initialization
+- operations
+
+The following sections provide details about these topics.
+
+.. index:: CBOR
+
+libxo source contains an encoder for Concise Binary Object
+Representation, aka CBOR (:RFC:`7049`), which can be used as an
+example for the API for other encoders.
+
+Loading Encoders
+~~~~~~~~~~~~~~~~
+
+Encoders can be registered statically or discovered dynamically.
+Applications can choose to call the `xo_encoder_register` function
+to explicitly register encoders, but more typically they are built as
+shared libraries, placed in the libxo/extensions directory, and loaded
+based on name. libxo looks for a file with the name of the encoder
+and an extension of ".enc". This can be a file or a symlink to the
+shared library file that supports the encoder::
+
+ % ls -1 lib/libxo/extensions/*.enc
+ lib/libxo/extensions/cbor.enc
+ lib/libxo/extensions/test.enc
+
+Encoder Initialization
+~~~~~~~~~~~~~~~~~~~~~~
+
+Each encoder must export a symbol used to access the library, which
+must have the following signature::
+
+ int xo_encoder_library_init (XO_ENCODER_INIT_ARGS);
+
+`XO_ENCODER_INIT_ARGS` is a macro defined in "xo_encoder.h" that defines
+an argument called "arg", a pointer of the type
+`xo_encoder_init_args_t`. This structure contains two fields:
+
+- `xei_version` is the version number of the API as implemented
+ within libxo. This version is currently as 1 using
+ `XO_ENCODER_VERSION`. This number can be checked to ensure
+ compatibility. The working assumption is that all versions should
+ be backward compatible, but each side may need to accurately know
+ the version supported by the other side. `xo_encoder_library_init`
+ can optionally check this value, and must then set it to the version
+ number used by the encoder, allowing libxo to detect version
+ differences and react accordingly. For example, if version 2 adds
+ new operations, then libxo will know that an encoding library that
+ set `xei_version` to 1 cannot be expected to handle those new
+ operations.
+
+- xei_handler must be set to a pointer to a function of type
+ `xo_encoder_func_t`, as defined in "xo_encoder.h". This function
+ takes a set of parameters:
+ - xop is a pointer to the opaque `xo_handle_t` structure
+ - op is an integer representing the current operation
+ - name is a string whose meaning differs by operation
+ - value is a string whose meaning differs by operation
+ - private is an opaque structure provided by the encoder
+
+Additional arguments may be added in the future, so handler functions
+should use the `XO_ENCODER_HANDLER_ARGS` macro. An appropriate
+"extern" declaration is provided to help catch errors.
+
+Once the encoder initialization function has completed processing, it
+should return zero to indicate that no error has occurred. A non-zero
+return code will cause the handle initialization to fail.
+
+Operations
+~~~~~~~~~~
+
+The encoder API defines a set of operations representing the
+processing model of libxo. Content is formatted within libxo, and
+callbacks are made to the encoder's handler function when data is
+ready to be processed:
+
+ ======================= =======================================
+ Operation Meaning (Base function)
+ ======================= =======================================
+ XO_OP_CREATE Called when the handle is created
+ XO_OP_OPEN_CONTAINER Container opened (xo_open_container)
+ XO_OP_CLOSE_CONTAINER Container closed (xo_close_container)
+ XO_OP_OPEN_LIST List opened (xo_open_list)
+ XO_OP_CLOSE_LIST List closed (xo_close_list)
+ XO_OP_OPEN_LEAF_LIST Leaf list opened (xo_open_leaf_list)
+ XO_OP_CLOSE_LEAF_LIST Leaf list closed (xo_close_leaf_list)
+ XO_OP_OPEN_INSTANCE Instance opened (xo_open_instance)
+ XO_OP_CLOSE_INSTANCE Instance closed (xo_close_instance)
+ XO_OP_STRING Field with Quoted UTF-8 string
+ XO_OP_CONTENT Field with content
+ XO_OP_FINISH Finish any pending output
+ XO_OP_FLUSH Flush any buffered output
+ XO_OP_DESTROY Clean up resources
+ XO_OP_ATTRIBUTE An attribute name/value pair
+ XO_OP_VERSION A version string
+ ======================= =======================================
+
+For all the open and close operations, the name parameter holds the
+name of the construct. For string, content, and attribute operations,
+the name parameter is the name of the field and the value parameter is
+the value. "string" are differentiated from "content" to allow differing
+treatment of true, false, null, and numbers from real strings, though
+content values are formatted as strings before the handler is called.
+For version operations, the value parameter contains the version.
+
+All strings are encoded in UTF-8.
diff --git a/doc/conf.py b/doc/conf.py
new file mode 100644
index 000000000000..62935cf4e43d
--- /dev/null
+++ b/doc/conf.py
@@ -0,0 +1,186 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# JuniperStory documentation build configuration file, created by
+# sphinx-quickstart on Tue Oct 10 10:18:55 2017.
+#
+# This file is execfile()d with the current directory set to its
+# containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+# import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+import subprocess
+
+#
+# Instead of hardcoding the version number here, we read it from the
+# project's configure script
+#
+vers_cmd = "grep AC_INIT ../configure.ac | awk '{ print substr($2, 2, length($2) - 3);}'"
+version = subprocess.check_output(vers_cmd, shell=True).decode("utf-8")
+
+# -- General configuration ------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#
+# needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix(es) of source filenames.
+# You can specify multiple suffix as a list of string:
+#
+# source_suffix = ['.rst', '.md']
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = 'libxo'
+copyright = '2017-2019, Juniper Networks Inc'
+author = 'Phil Shafer'
+default_role = 'code'
+primary_domain = 'c'
+smart_quotes = False
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+#version = 'develop'
+# The full version, including alpha/beta/rc tags.
+release = version
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#
+# This is also used if you do content translation via gettext catalogs.
+# Usually you set "language" from the command line for these cases.
+language = None
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This patterns also effect to html_static_path and html_extra_path
+exclude_patterns = []
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# If true, `todo` and `todoList` produce output, else they produce nothing.
+todo_include_todos = False
+
+
+# -- Options for HTML output ----------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinxdoc'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#
+# html_theme_options = {}
+html_theme_options = {
+ "sidebarwidth": 320,
+}
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# Custom sidebar templates, must be a dictionary that maps document names
+# to template names.
+#
+# This is required for the alabaster theme
+# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
+alabaster_html_sidebars = {
+ '**': [
+ 'about.html',
+ 'navigation.html',
+ 'relations.html', # needs 'show_related': True theme option to display
+ 'searchbox.html',
+ 'donate.html',
+ ]
+}
+
+
+# -- Options for HTMLHelp output ------------------------------------------
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'libxo-manual'
+
+
+# -- Options for LaTeX output ---------------------------------------------
+
+latex_elements = {
+ # The paper size ('letterpaper' or 'a4paper').
+ #
+ # 'papersize': 'letterpaper',
+
+ # The font size ('10pt', '11pt' or '12pt').
+ #
+ # 'pointsize': '10pt',
+
+ # Additional stuff for the LaTeX preamble.
+ #
+ # 'preamble': '',
+
+ # Latex figure (float) alignment
+ #
+ # 'figure_align': 'htbp',
+}
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title,
+# author, documentclass [howto, manual, or own class]).
+latex_documents = [
+ (master_doc, 'libxo.tex', 'libxo Documentation',
+ 'Phil Shafer', 'manual'),
+]
+
+
+# -- Options for manual page output ---------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ (master_doc, 'libxo', 'libxo Documentation',
+ [author], 1)
+]
+
+
+# -- Options for Texinfo output -------------------------------------------
+
+# Grouping the document tree into Texinfo files. List of tuples
+# (source start file, target name, title, author,
+# dir menu entry, description, category)
+texinfo_documents = [
+ (master_doc, 'libxo', 'libxo Documentation',
+ author, 'libxo', 'A Library for Generating Text, XML, JSON, and HTML Output',
+ 'Miscellaneous'),
+]
+
+
+
diff --git a/doc/encoders.rst b/doc/encoders.rst
new file mode 100644
index 000000000000..dfd0316bfb97
--- /dev/null
+++ b/doc/encoders.rst
@@ -0,0 +1,274 @@
+.. index:: encoder
+
+Encoders
+========
+
+This section gives an overview of encoders, details on the encoders
+that ship with libxo, and documentation for developers of future
+encoders.
+
+Overview
+--------
+
+The libxo library contains software to generate four "built-in"
+formats: text, XML, JSON, and HTML. These formats are common and
+useful, but there are other common and useful formats that users will
+want, and including them all in the libxo software would be difficult
+and cumbersome.
+
+To allow support for additional encodings, libxo includes a
+"pluggable" extension mechanism for dynamically loading new encoders.
+libxo-based applications can automatically use any installed encoder.
+
+Use the "encoder=XXX" option to access encoders. The following
+example uses the "cbor" encoder, saving the output into a file::
+
+ df --libxo encoder=cbor > df-output.cbor
+
+Encoders can support specific options that can be accessed by
+following the encoder name with a colon (':') or a plus sign ('+') and
+one of more options, separated by the same character::
+
+ df --libxo encoder=csv+path=filesystem+leaf=name+no-header
+ df --libxo encoder=csv:path=filesystem:leaf=name:no-header
+
+These examples instructs libxo to load the "csv" encoder and pass the
+following options::
+
+ path=filesystem
+ leaf=name
+ no-header
+
+Each of these option is interpreted by the encoder, and all such
+options names and semantics are specific to the particular encoder.
+Refer to the intended encoder for documentation on its options.
+
+The string "@" can be used in place of the string "encoder=".
+
+ df --libxo @csv:no-header
+
+.. _csv_encoder:
+
+CSV - Comma Separated Values
+----------------------------
+
+libxo ships with a custom encoder for "CSV" files, a common format for
+comma separated values. The output of the CSV encoder can be loaded
+directly into spreadsheets or similar applications.
+
+A standard for CSV files is provided in :RFC:`4180`, but since the
+format predates that standard by decades, there are many minor
+differences in CSV file consumers and their expectations. The CSV
+encoder has a number of options to tailor output to those
+expectations.
+
+Consider the following XML::
+
+ % list-items --libxo xml,pretty
+ <top>
+ <data test="value">
+ <item test2="value2">
+ <sku test3="value3" key="key">GRO-000-415</sku>
+ <name key="key">gum</name>
+ <sold>1412</sold>
+ <in-stock>54</in-stock>
+ <on-order>10</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">HRD-000-212</sku>
+ <name key="key">rope</name>
+ <sold>85</sold>
+ <in-stock>4</in-stock>
+ <on-order>2</on-order>
+ </item>
+ <item>
+ <sku test3="value3" key="key">HRD-000-517</sku>
+ <name key="key">ladder</name>
+ <sold>0</sold>
+ <in-stock>2</in-stock>
+ <on-order>1</on-order>
+ </item>
+ </data>
+ </top>
+
+This output is a list of `instances` (named "item"), each containing a
+set of `leafs` ("sku", "name", etc).
+
+The CSV encoder will emit the leaf values in this output as `fields`
+inside a CSV `record`, which is a line containing a set of
+comma-separated values::
+
+ % list-items --libxo encoder=csv
+ sku,name,sold,in-stock,on-order
+ GRO-000-415,gum,1412,54,10
+ HRD-000-212,rope,85,4,2
+ HRD-000-517,ladder,0,2,1
+
+Be aware that since the CSV encoder looks for data instances, when
+used with :ref:`xo`, the `--instance` option will be needed::
+
+ % xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route"
+ product,status
+ stereo,in route
+
+.. _csv_path:
+
+The `path` Option
+~~~~~~~~~~~~~~~~~
+
+By default, the CSV encoder will attempt to emit any list instance
+generated by the application. In some cases, this may be
+unacceptable, and a specific list may be desired.
+
+Use the "path" option to limit the processing of output to a specific
+hierarchy. The path should be one or more names of containers or
+lists.
+
+For example, if the "list-items" application generates other lists,
+the user can give "path=top/data/item" as a path::
+
+ % list-items --libxo encoder=csv:path=top/data/item
+ sku,name,sold,in-stock,on-order
+ GRO-000-415,gum,1412,54,10
+ HRD-000-212,rope,85,4,2
+ HRD-000-517,ladder,0,2,1
+
+Paths are "relative", meaning they need not be a complete set
+of names to the list. This means that "path=item" may be sufficient
+for the above example.
+
+.. _csv_leafs:
+
+The `leafs` Option
+~~~~~~~~~~~~~~~~~~
+
+The CSV encoding requires that all lines of output have the same
+number of fields with the same order. In contrast, XML and JSON allow
+any order (though libxo forces key leafs to appear before other
+leafs).
+
+To maintain a consistent set of fields inside the CSV file, the same
+set of leafs must be selected from each list item. By default, the
+CSV encoder records the set of leafs that appear in the first list
+instance it processes, and extract only those leafs from future
+instances. If the first instance is missing a leaf that is desired by
+the consumer, the "leaf" option can be used to ensure that an empty
+value is recorded for instances that lack a particular leaf.
+
+The "leafs" option can also be used to exclude leafs, limiting the
+output to only those leafs provided.
+
+In addition, the order of the output fields follows the order in which
+the leafs are listed. "leafs=one.two" and "leafs=two.one" give
+distinct output.
+
+So the "leafs" option can be used to expand, limit, and order the set
+of leafs.
+
+The value of the leafs option should be one or more leaf names,
+separated by a period (".")::
+
+ % list-items --libxo encoder=csv:leafs=sku.on-order
+ sku,on-order
+ GRO-000-415,10
+ HRD-000-212,2
+ HRD-000-517,1
+ % list-items -libxo encoder=csv:leafs=on-order.sku
+ on-order,sku
+ 10,GRO-000-415
+ 2,HRD-000-212
+ 1,HRD-000-517
+
+Note that since libxo uses terminology from YANG (:RFC:`7950`), the
+data modeling language for NETCONF (:RFC:`6241`), which uses "leafs"
+as the plural form of "leaf". libxo follows that convention.
+
+.. _csv_no_header:
+
+The `no-header` Option
+~~~~~~~~~~~~~~~~~~~~~~
+
+CSV files typical begin with a line that defines the fields included
+in that file, in an attempt to make the contents self-defining::
+
+ sku,name,sold,in-stock,on-order
+ GRO-000-415,gum,1412,54,10
+ HRD-000-212,rope,85,4,2
+ HRD-000-517,ladder,0,2,1
+
+There is no reliable mechanism for determining whether this header
+line is included, so the consumer must make an assumption.
+
+The csv encoder defaults to producing the header line, but the
+"no-header" option can be included to avoid the header line.
+
+.. _csv_no_quotes:
+
+The `no-quotes` Option
+~~~~~~~~~~~~~~~~~~~~~~
+
+:RFC:`4180` specifies that fields containing spaces should be quoted, but
+many CSV consumers do not handle quotes. The "no-quotes" option
+instruct the CSV encoder to avoid the use of quotes.
+
+.. _csv_dos:
+
+The `dos` Option
+~~~~~~~~~~~~~~~~
+
+:RFC:`4180` defines the end-of-line marker as a carriage return
+followed by a newline. This `CRLF` convention dates from the distant
+past, but its use was anchored in the 1980s by the `DOS` operating
+system.
+
+The CSV encoder defaults to using the standard Unix end-of-line
+marker, a simple newline. Use the "dos" option to use the `CRLF`
+convention.
+
+The Encoder API
+---------------
+
+The encoder API consists of three distinct phases:
+
+- loading the encoder
+- initializing the encoder
+- feeding operations to the encoder
+
+To load the encoder, libxo will open a shared library named:
+
+ ${prefix}/lib/libxo/encoder/${name}.enc
+
+This file is typically a symbolic link to a dynamic library, suitable
+for `dlopen`(). libxo looks for a symbol called
+`xo_encoder_library_init` inside that library and calls it with the
+arguments defined in the header file "xo_encoder.h". This function
+should look as follows::
+
+ int
+ xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
+ {
+ arg->xei_version = XO_ENCODER_VERSION;
+ arg->xei_handler = test_handler;
+
+ return 0;
+ }
+
+Several features here allow for future compatibility: the macro
+XO_ENCODER_INIT_ARGS allows the arguments to this function change over
+time, and the XO_ENCODER_VERSION allows the library to tell libxo
+which version of the API it was compiled with.
+
+The function places in xei_handler should be have the signature::
+
+ static int
+ test_handler (XO_ENCODER_HANDLER_ARGS)
+ {
+ ...
+
+This function will be called with the "op" codes defined in
+"xo_encoder.h". Each op code represents a distinct event in the libxo
+processing model. For example OP_OPEN_CONTAINER tells the encoder
+that a new container has been opened, and the encoder can behave in an
+appropriate manner.
+
+
diff --git a/doc/example.rst b/doc/example.rst
new file mode 100644
index 000000000000..2975ddeb1b59
--- /dev/null
+++ b/doc/example.rst
@@ -0,0 +1,694 @@
+
+Examples
+========
+
+Unit Test
+---------
+
+Here is one of the unit tests as an example::
+
+ int
+ main (int argc, char **argv)
+ {
+ static char base_grocery[] = "GRO";
+ static char base_hardware[] = "HRD";
+ struct item {
+ const char *i_title;
+ int i_sold;
+ int i_instock;
+ int i_onorder;
+ const char *i_sku_base;
+ int i_sku_num;
+ };
+ struct item list[] = {
+ { "gum", 1412, 54, 10, base_grocery, 415 },
+ { "rope", 85, 4, 2, base_hardware, 212 },
+ { "ladder", 0, 2, 1, base_hardware, 517 },
+ { "bolt", 4123, 144, 42, base_hardware, 632 },
+ { "water", 17, 14, 2, base_grocery, 2331 },
+ { NULL, 0, 0, 0, NULL, 0 }
+ };
+ struct item list2[] = {
+ { "fish", 1321, 45, 1, base_grocery, 533 },
+ };
+ struct item *ip;
+ xo_info_t info[] = {
+ { "in-stock", "number", "Number of items in stock" },
+ { "name", "string", "Name of the item" },
+ { "on-order", "number", "Number of items on order" },
+ { "sku", "string", "Stock Keeping Unit" },
+ { "sold", "number", "Number of items sold" },
+ { NULL, NULL, NULL },
+ };
+ int info_count = (sizeof(info) / sizeof(info[0])) - 1;
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ exit(EXIT_FAILURE);
+
+ xo_set_info(NULL, info, info_count);
+
+ xo_open_container_h(NULL, "top");
+
+ xo_open_container("data");
+ xo_open_list("item");
+
+ for (ip = list; ip->i_title; ip++) {
+ xo_open_instance("item");
+
+ xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title);
+ xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
+ ip->i_sold, ip->i_sold ? ".0" : "");
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
+ ip->i_instock);
+ xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
+ ip->i_onorder);
+ xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
+ ip->i_sku_base, ip->i_sku_num);
+
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_open_container("data");
+ xo_open_list("item");
+
+ for (ip = list2; ip->i_title; ip++) {
+ xo_open_instance("item");
+
+ xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
+ xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
+ ip->i_sold, ip->i_sold ? ".0" : "");
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
+ ip->i_instock);
+ xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
+ ip->i_onorder);
+ xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
+ ip->i_sku_base, ip->i_sku_num);
+
+ xo_close_instance("item");
+ }
+
+ xo_close_list("item");
+ xo_close_container("data");
+
+ xo_close_container_h(NULL, "top");
+
+ return 0;
+ }
+
+Text output::
+
+ % ./testxo --libxo text
+ Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+ Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+ Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+ Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+ Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+ Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
+
+JSON output::
+
+ % ./testxo --libxo json,pretty
+ "top": {
+ "data": {
+ "item": [
+ {
+ "name": "gum",
+ "sold": 1412.0,
+ "in-stock": 54,
+ "on-order": 10,
+ "sku": "GRO-000-415"
+ },
+ {
+ "name": "rope",
+ "sold": 85.0,
+ "in-stock": 4,
+ "on-order": 2,
+ "sku": "HRD-000-212"
+ },
+ {
+ "name": "ladder",
+ "sold": 0,
+ "in-stock": 2,
+ "on-order": 1,
+ "sku": "HRD-000-517"
+ },
+ {
+ "name": "bolt",
+ "sold": 4123.0,
+ "in-stock": 144,
+ "on-order": 42,
+ "sku": "HRD-000-632"
+ },
+ {
+ "name": "water",
+ "sold": 17.0,
+ "in-stock": 14,
+ "on-order": 2,
+ "sku": "GRO-000-2331"
+ }
+ ]
+ },
+ "data": {
+ "item": [
+ {
+ "name": "fish",
+ "sold": 1321.0,
+ "in-stock": 45,
+ "on-order": 1,
+ "sku": "GRO-000-533"
+ }
+ ]
+ }
+ }
+
+XML output::
+
+ % ./testxo --libxo pretty,xml
+ <top>
+ <data>
+ <item>
+ <name>gum</name>
+ <sold>1412.0</sold>
+ <in-stock>54</in-stock>
+ <on-order>10</on-order>
+ <sku>GRO-000-415</sku>
+ </item>
+ <item>
+ <name>rope</name>
+ <sold>85.0</sold>
+ <in-stock>4</in-stock>
+ <on-order>2</on-order>
+ <sku>HRD-000-212</sku>
+ </item>
+ <item>
+ <name>ladder</name>
+ <sold>0</sold>
+ <in-stock>2</in-stock>
+ <on-order>1</on-order>
+ <sku>HRD-000-517</sku>
+ </item>
+ <item>
+ <name>bolt</name>
+ <sold>4123.0</sold>
+ <in-stock>144</in-stock>
+ <on-order>42</on-order>
+ <sku>HRD-000-632</sku>
+ </item>
+ <item>
+ <name>water</name>
+ <sold>17.0</sold>
+ <in-stock>14</in-stock>
+ <on-order>2</on-order>
+ <sku>GRO-000-2331</sku>
+ </item>
+ </data>
+ <data>
+ <item>
+ <name>fish</name>
+ <sold>1321.0</sold>
+ <in-stock>45</in-stock>
+ <on-order>1</on-order>
+ <sku>GRO-000-533</sku>
+ </item>
+ </data>
+ </top>
+
+HMTL output::
+
+ % ./testxo --libxo pretty,html
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">gum</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">1412.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">54</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">10</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">GRO-000-415</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">rope</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">85.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">4</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">HRD-000-212</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">ladder</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">1</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">HRD-000-517</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">bolt</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">4123.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">144</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">42</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">HRD-000-632</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">water</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">17.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">14</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">GRO-000-2331</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name">fish</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold">1321.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">45</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order">1</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku">GRO-000-533</div>
+ </div>
+
+HTML output with xpath and info flags::
+
+ % ./testxo --libxo pretty,html,xpath,info
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">gum</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">1412.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">54</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">10</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">GRO-000-415</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">rope</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">85.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">4</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">HRD-000-212</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">ladder</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">1</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">HRD-000-517</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">bolt</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">4123.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">144</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">42</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">HRD-000-632</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">water</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">17.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">14</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">2</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">GRO-000-2331</div>
+ </div>
+ <div class="line">
+ <div class="label">Item</div>
+ <div class="text"> '</div>
+ <div class="data" data-tag="name"
+ data-xpath="/top/data/item/name" data-type="string"
+ data-help="Name of the item">fish</div>
+ <div class="text">':</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">Total sold</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sold"
+ data-xpath="/top/data/item/sold" data-type="number"
+ data-help="Number of items sold">1321.0</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock" data-type="number"
+ data-help="Number of items in stock">45</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">On order</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="on-order"
+ data-xpath="/top/data/item/on-order" data-type="number"
+ data-help="Number of items on order">1</div>
+ </div>
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">SKU</div>
+ <div class="text">: </div>
+ <div class="data" data-tag="sku"
+ data-xpath="/top/data/item/sku" data-type="string"
+ data-help="Stock Keeping Unit">GRO-000-533</div>
+ </div>
diff --git a/doc/faq.rst b/doc/faq.rst
new file mode 100644
index 000000000000..5232a7271681
--- /dev/null
+++ b/doc/faq.rst
@@ -0,0 +1,211 @@
+
+FAQs
+====
+
+This section contains the set of questions that users typically ask,
+along with answers that might be helpful.
+
+General
+-------
+
+Can you share the history of libxo?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In 2001, we added an XML API to the JUNOS operating system, which is
+built on top of FreeBSD_. Eventually this API became standardized as
+the NETCONF API (:RFC:`6241`). As part of this effort, we modified many
+FreeBSD utilities to emit XML, typically via a "-X" switch. The
+results were mixed. The cost of maintaining this code, updating it,
+and carrying it were non-trivial, and contributed to our expense (and
+the associated delay) with upgrading the version of FreeBSD on which
+each release of JUNOS is based.
+
+.. _FreeBSD: https://www.freebsd.org
+
+A recent (2014) effort within JUNOS aims at removing our modifications
+to the underlying FreeBSD code as a means of reducing the expense and
+delay in tracking HEAD. JUNOS is structured to have system components
+generate XML that is rendered by the CLI (think: login shell) into
+human-readable text. This allows the API to use the same plumbing as
+the CLI, and ensures that all components emit XML, and that it is
+emitted with knowledge of the consumer of that XML, yielding an API
+that have no incremental cost or feature delay.
+
+libxo is an effort to mix the best aspects of the JUNOS strategy into
+FreeBSD in a seemless way, allowing commands to make printf-like
+output calls with a single code path.
+
+Did the complex semantics of format strings evolve over time?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The history is both long and short: libxo's functionality is based
+on what JUNOS does in a data modeling language called ODL (output
+definition language). In JUNOS, all subcomponents generate XML,
+which is feed to the CLI, where data from the ODL files tell is
+how to render that XML into text. ODL might had a set of tags
+like::
+
+ tag docsis-state {
+ help "State of the DOCSIS interface";
+ type string;
+ }
+
+ tag docsis-mode {
+ help "DOCSIS mode (2.0/3.0) of the DOCSIS interface";
+ type string;
+ }
+
+ tag docsis-upstream-speed {
+ help "Operational upstream speed of the interface";
+ type string;
+ }
+
+ tag downstream-scanning {
+ help "Result of scanning in downstream direction";
+ type string;
+ }
+
+ tag ranging {
+ help "Result of ranging action";
+ type string;
+ }
+
+ tag signal-to-noise-ratio {
+ help "Signal to noise ratio for all channels";
+ type string;
+ }
+
+ tag power {
+ help "Operational power of the signal on all channels";
+ type string;
+ }
+
+ format docsis-status-format {
+ picture "
+ State : @, Mode: @, Upstream speed: @
+ Downstream scanning: @, Ranging: @
+ Signal to noise ratio: @
+ Power: @
+ ";
+ line {
+ field docsis-state;
+ field docsis-mode;
+ field docsis-upstream-speed;
+ field downstream-scanning;
+ field ranging;
+ field signal-to-noise-ratio;
+ field power;
+ }
+ }
+
+These tag definitions are compiled into field definitions
+that are triggered when matching XML elements are seen. ODL
+also supports other means of defining output.
+
+The roles and modifiers describe these details.
+
+In moving these ideas to bsd, two things had to happen: the
+formatting had to happen at the source since BSD won't have
+a JUNOS-like CLI to do the rendering, and we can't depend on
+external data models like ODL, which was seen as too hard a
+sell to the BSD community.
+
+The results were that the xo_emit strings are used to encode the
+roles, modifiers, names, and formats. They are dense and a bit
+cryptic, but not so unlike printf format strings that developers will
+be lost.
+
+libxo is a new implementation of these ideas and is distinct from
+the previous implementation in JUNOS.
+
+.. index:: XOF_UNDERSCORES
+
+.. _good-field-names:
+
+What makes a good field name?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+To make useful, consistent field names, follow these guidelines:
+
+Use lower case, even for TLAs
+ Lower case is more civilized. Even TLAs should be lower case
+ to avoid scenarios where the differences between "XPath" and
+ "Xpath" drive your users crazy. Using "xpath" is simpler and better.
+
+Use hyphens, not underscores
+ Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
+ flag can be used to generate underscores in JSON, if desired.
+ But the raw field name should use hyphens.
+
+Use full words
+ Don't abbreviate especially when the abbreviation is not obvious or
+ not widely used. Use "data-size", not "dsz" or "dsize". Use
+ "interface" instead of "ifname", "if-name", "iface", "if", or "intf".
+
+Use <verb>-<units>
+ Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in
+ making consistent, useful names, avoiding the situation where one app
+ uses "sent-packet" and another "packets-sent" and another
+ "packets-we-have-sent". The <units> can be dropped when it is
+ obvious, as can obvious words in the classification.
+ Use "receive-after-window-packets" instead of
+ "received-packets-of-data-after-window".
+
+Reuse existing field names
+ Nothing's worse than writing expressions like::
+
+ if ($src1/process[pid == $pid]/name ==
+ $src2/proc-table/proc-list
+ /prc-entry[prcss-id == $pid]/proc-name) {
+ ...
+ }
+
+ Find someone else who is expressing similar data and follow their
+ fields and hierarchy. Remember the quote is not "Consistency is the
+ hobgoblin of little minds", but "A *foolish* consistency is the
+ hobgoblin of little minds". Consistency rocks!
+
+Use containment as scoping
+ In the previous example, all the names are prefixed with "proc-",
+ which is redundant given that they are nested under the process table.
+
+Think about your users
+ Have empathy for your users, choosing clear and useful fields that
+ contain clear and useful data. You may need to augment the display
+ content with xo_attr() calls (:ref:`xo_attr`) or "{e:}"
+ fields (:ref:`encoding-modifier`) to make the data useful.
+
+Don't use an arbitrary number postfix
+ What does "errors2" mean? No one will know. "errors-after-restart"
+ would be a better choice. Think of your users, and think of the
+ future. If you make "errors2", the next guy will happily make
+ "errors3" and before you know it, someone will be asking what's the
+ difference between errors37 and errors63.
+
+Be consistent, uniform, unsurprising, and predictable
+ Think of your field vocabulary as an API. You want it useful,
+ expressive, meaningful, direct, and obvious. You want the client
+ application's programmer to move between without the need to
+ understand a variety of opinions on how fields are named. They
+ should see the system as a single cohesive whole, not a sack of
+ cats.
+
+Field names constitute the means by which client programmers interact
+with our system. By choosing wise names now, you are making their
+lives better.
+
+After using `xolint` to find errors in your field descriptors, use
+"`xolint -V`" to spell check your field names and to help you detect
+different names for the same data. "dropped-short" and
+"dropped-too-short" are both reasonable names, but using them both
+will lead users to ask the difference between the two fields. If
+there is no difference, use only one of the field names. If there is
+a difference, change the names to make that difference more obvious.
+
+What does this message mean?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. toctree::
+ :maxdepth: 2
+
+ xolint-errors.rst
diff --git a/doc/field-formatting.rst b/doc/field-formatting.rst
new file mode 100644
index 000000000000..1a4a29af6e64
--- /dev/null
+++ b/doc/field-formatting.rst
@@ -0,0 +1,371 @@
+
+.. index:: Field Formatting
+.. _field-formatting:
+
+Field Formatting
+----------------
+
+The field format is similar to the format string for printf(3). Its
+use varies based on the role of the field, but generally is used to
+format the field's contents.
+
+If the format string is not provided for a value field, it defaults to
+"%s".
+
+Note a field definition can contain zero or more printf-style
+'directives', which are sequences that start with a '%' and end with
+one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive
+is matched by one of more arguments to the xo_emit function.
+
+The format string has the form::
+
+ '%' format-modifier * format-character
+
+The format-modifier can be:
+
+- a '#' character, indicating the output value should be prefixed
+ with '0x', typically to indicate a base 16 (hex) value.
+- a minus sign ('-'), indicating the output value should be padded on
+ the right instead of the left.
+- a leading zero ('0') indicating the output value should be padded on the
+ left with zeroes instead of spaces (' ').
+- one or more digits ('0' - '9') indicating the minimum width of the
+ argument. If the width in columns of the output value is less than
+ the minimum width, the value will be padded to reach the minimum.
+- a period followed by one or more digits indicating the maximum
+ number of bytes which will be examined for a string argument, or the maximum
+ width for a non-string argument. When handling ASCII strings this
+ functions as the field width but for multi-byte characters, a single
+ character may be composed of multiple bytes.
+ xo_emit will never dereference memory beyond the given number of bytes.
+- a second period followed by one or more digits indicating the maximum
+ width for a string argument. This modifier cannot be given for non-string
+ arguments.
+- one or more 'h' characters, indicating shorter input data.
+- one or more 'l' characters, indicating longer input data.
+- a 'z' character, indicating a 'size_t' argument.
+- a 't' character, indicating a 'ptrdiff_t' argument.
+- a ' ' character, indicating a space should be emitted before
+ positive numbers.
+- a '+' character, indicating sign should emitted before any number.
+
+Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
+removed eventually.
+
+The format character is described in the following table:
+
+ ===== ================= ======================
+ Ltr Argument Type Format
+ ===== ================= ======================
+ d int base 10 (decimal)
+ i int base 10 (decimal)
+ o int base 8 (octal)
+ u unsigned base 10 (decimal)
+ x unsigned base 16 (hex)
+ X unsigned long base 16 (hex)
+ D long base 10 (decimal)
+ O unsigned long base 8 (octal)
+ U unsigned long base 10 (decimal)
+ e double [-]d.ddde+-dd
+ E double [-]d.dddE+-dd
+ f double [-]ddd.ddd
+ F double [-]ddd.ddd
+ g double as 'e' or 'f'
+ G double as 'E' or 'F'
+ a double [-]0xh.hhhp[+-]d
+ A double [-]0Xh.hhhp[+-]d
+ c unsigned char a character
+ C wint_t a character
+ s char \* a UTF-8 string
+ S wchar_t \* a unicode/WCS string
+ p void \* '%#lx'
+ ===== ================= ======================
+
+The 'h' and 'l' modifiers affect the size and treatment of the
+argument:
+
+ ===== ============= ====================
+ Mod d, i o, u, x, X
+ ===== ============= ====================
+ hh signed char unsigned char
+ h short unsigned short
+ l long unsigned long
+ ll long long unsigned long long
+ j intmax_t uintmax_t
+ t ptrdiff_t ptrdiff_t
+ z size_t size_t
+ q quad_t u_quad_t
+ ===== ============= ====================
+
+.. index:: UTF-8
+.. index:: Locale
+
+.. _utf-8:
+
+UTF-8 and Locale Strings
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+For strings, the 'h' and 'l' modifiers affect the interpretation of
+the bytes pointed to argument. The default '%s' string is a 'char \*'
+pointer to a string encoded as UTF-8. Since UTF-8 is compatible with
+ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a
+'wchar_t \*' pointer to a wide-character string, encoded as a 32-bit
+Unicode values. '%hs' expects a 'char \*' pointer to a multi-byte
+string encoded with the current locale, as given by the LC_CTYPE,
+LANG, or LC_ALL environment varibles. The first of this list of
+variables is used and if none of the variables are set, the locale
+defaults to "UTF-8".
+
+libxo will convert these arguments as needed to either UTF-8 (for XML,
+JSON, and HTML styles) or locale-based strings for display in text
+style::
+
+ xo_emit("All strings are utf-8 content {:tag/%ls}",
+ L"except for wide strings");
+
+ ======== ================== ===============================
+ Format Argument Type Argument Contents
+ ======== ================== ===============================
+ %s const char \* UTF-8 string
+ %S const char \* UTF-8 string (alias for '%ls')
+ %ls const wchar_t \* Wide character UNICODE string
+ %hs const char * locale-based string
+ ======== ================== ===============================
+
+.. admonition:: "Long", not "locale"
+
+ The "*l*" in "%ls" is for "*long*", following the convention of "%ld".
+ It is not "*locale*", a common mis-mnemonic. "%S" is equivalent to
+ "%ls".
+
+For example, the following function is passed a locale-base name, a
+hat size, and a time value. The hat size is formatted in a UTF-8
+(ASCII) string, and the time value is formatted into a wchar_t
+string::
+
+ void print_order (const char *name, int size,
+ struct tm *timep) {
+ char buf[32];
+ const char *size_val = "unknown";
+
+ if (size > 0)
+ snprintf(buf, sizeof(buf), "%d", size);
+ size_val = buf;
+ }
+
+ wchar_t when[32];
+ wcsftime(when, sizeof(when), L"%d%b%y", timep);
+
+ xo_emit("The hat for {:name/%hs} is {:size/%s}.\n",
+ name, size_val);
+ xo_emit("It was ordered on {:order-time/%ls}.\n",
+ when);
+ }
+
+It is important to note that xo_emit will perform the conversion
+required to make appropriate output. Text style output uses the
+current locale (as described above), while XML, JSON, and HTML use
+UTF-8.
+
+UTF-8 and locale-encoded strings can use multiple bytes to encode one
+column of data. The traditional "precision'" (aka "max-width") value
+for "%s" printf formatting becomes overloaded since it specifies both
+the number of bytes that can be safely referenced and the maximum
+number of columns to emit. xo_emit uses the precision as the former,
+and adds a third value for specifying the maximum number of columns.
+
+In this example, the name field is printed with a minimum of 3 columns
+and a maximum of 6. Up to ten bytes of data at the location given by
+'name' are in used in filling those columns::
+
+ xo_emit("{:name/%3.10.6s}", name);
+
+Characters Outside of Field Definitions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Characters in the format string that are not part of a field
+definition are copied to the output for the TEXT style, and are
+ignored for the JSON and XML styles. For HTML, these characters are
+placed in a <div> with class "text"::
+
+ EXAMPLE:
+ xo_emit("The hat is {:size/%s}.\n", size_val);
+ TEXT:
+ The hat is extra small.
+ XML:
+ <size>extra small</size>
+ JSON:
+ "size": "extra small"
+ HTML:
+ <div class="text">The hat is </div>
+ <div class="data" data-tag="size">extra small</div>
+ <div class="text">.</div>
+
+.. index:: errno
+
+"%m" Is Supported
+~~~~~~~~~~~~~~~~~
+
+libxo supports the '%m' directive, which formats the error message
+associated with the current value of "errno". It is the equivalent
+of "%s" with the argument strerror(errno)::
+
+ xo_emit("{:filename} cannot be opened: {:error/%m}", filename);
+ xo_emit("{:filename} cannot be opened: {:error/%s}",
+ filename, strerror(errno));
+
+"%n" Is Not Supported
+~~~~~~~~~~~~~~~~~~~~~
+
+libxo does not support the '%n' directive. It's a bad idea and we
+just don't do it.
+
+The Encoding Format (eformat)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The "eformat" string is the format string used when encoding the field
+for JSON and XML. If not provided, it defaults to the primary format
+with any minimum width removed. If the primary is not given, both
+default to "%s".
+
+Content Strings
+~~~~~~~~~~~~~~~
+
+For padding and labels, the content string is considered the content,
+unless a format is given.
+
+.. index:: printf-like
+
+Argument Validation
+~~~~~~~~~~~~~~~~~~~
+
+Many compilers and tool chains support validation of printf-like
+arguments. When the format string fails to match the argument list,
+a warning is generated. This is a valuable feature and while the
+formatting strings for libxo differ considerably from printf, many of
+these checks can still provide build-time protection against bugs.
+
+libxo provide variants of functions that provide this ability, if the
+"--enable-printflike" option is passed to the "configure" script.
+These functions use the "_p" suffix, like "xo_emit_p()",
+xo_emit_hp()", etc.
+
+The following are features of libxo formatting strings that are
+incompatible with printf-like testing:
+
+- implicit formats, where "{:tag}" has an implicit "%s";
+- the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to
+ ten bytes of data can be inspected to fill a minimum of 4 columns and
+ a maximum of 6;
+- percent signs in strings, where "{:filled}%" makes a single,
+ trailing percent sign;
+- the "l" and "h" modifiers for strings, where "{:tag/%hs}" means
+ locale-based string and "{:tag/%ls}" means a wide character string;
+- distinct encoding formats, where "{:tag/#%s/%s}" means the display
+ styles (text and HTML) will use "#%s" where other styles use "%s";
+
+If none of these features are in use by your code, then using the "_p"
+variants might be wise:
+
+ ================== ========================
+ Function printf-like Equivalent
+ ================== ========================
+ xo_emit_hv xo_emit_hvp
+ xo_emit_h xo_emit_hp
+ xo_emit xo_emit_p
+ xo_emit_warn_hcv xo_emit_warn_hcvp
+ xo_emit_warn_hc xo_emit_warn_hcp
+ xo_emit_warn_c xo_emit_warn_cp
+ xo_emit_warn xo_emit_warn_p
+ xo_emit_warnx xo_emit_warnx_p
+ xo_emit_err xo_emit_err_p
+ xo_emit_errx xo_emit_errx_p
+ xo_emit_errc xo_emit_errc_p
+ ================== ========================
+
+.. index:: performance
+.. index:: XOEF_RETAIN
+
+.. _retain:
+
+Retaining Parsed Format Information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+libxo can retain the parsed internal information related to the given
+format string, allowing subsequent xo_emit calls, the retained
+information is used, avoiding repetitive parsing of the format string::
+
+ SYNTAX:
+ int xo_emit_f(xo_emit_flags_t flags, const char fmt, ...);
+ EXAMPLE:
+ xo_emit_f(XOEF_RETAIN, "{:some/%02d}{:thing/%-6s}{:fancy}\n",
+ some, thing, fancy);
+
+To retain parsed format information, use the XOEF_RETAIN flag to the
+xo_emit_f() function. A complete set of xo_emit_f functions exist to
+match all the xo_emit function signatures (with handles, varadic
+argument, and printf-like flags):
+
+ ================== ========================
+ Function Flags Equivalent
+ ================== ========================
+ xo_emit_hv xo_emit_hvf
+ xo_emit_h xo_emit_hf
+ xo_emit xo_emit_f
+ xo_emit_hvp xo_emit_hvfp
+ xo_emit_hp xo_emit_hfp
+ xo_emit_p xo_emit_fp
+ ================== ========================
+
+The format string must be immutable across multiple calls to xo_emit_f(),
+since the library retains the string. Typically this is done by using
+static constant strings, such as string literals. If the string is not
+immutable, the XOEF_RETAIN flag must not be used.
+
+The functions xo_retain_clear() and xo_retain_clear_all() release
+internal information on either a single format string or all format
+strings, respectively. Neither is required, but the library will
+retain this information until it is cleared or the process exits::
+
+ const char *fmt = "{:name} {:count/%d}\n";
+ for (i = 0; i < 1000; i++) {
+ xo_open_instance("item");
+ xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
+ }
+ xo_retain_clear(fmt);
+
+The retained information is kept as thread-specific data.
+
+Example
+~~~~~~~
+
+In this example, the value for the number of items in stock is emitted::
+
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
+ instock);
+
+This call will generate the following output::
+
+ TEXT:
+ In stock: 144
+ XML:
+ <in-stock>144</in-stock>
+ JSON:
+ "in-stock": 144,
+ HTML:
+ <div class="line">
+ <div class="padding"> </div>
+ <div class="label">In stock</div>
+ <div class="decoration">:</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="in-stock">144</div>
+ </div>
+
+Clearly HTML wins the verbosity award, and this output does
+not include XOF_XPATH or XOF_INFO data, which would expand the
+penultimate line to::
+
+ <div class="data" data-tag="in-stock"
+ data-xpath="/top/data/item/in-stock"
+ data-type="number"
+ data-help="Number of items in stock">144</div>
diff --git a/doc/field-modifiers.rst b/doc/field-modifiers.rst
new file mode 100644
index 000000000000..ba2073bbdb68
--- /dev/null
+++ b/doc/field-modifiers.rst
@@ -0,0 +1,353 @@
+
+.. index:: Field Modifiers
+.. _field-modifiers:
+
+Field Modifiers
+~~~~~~~~~~~~~~~
+
+Field modifiers are flags which modify the way content emitted for
+particular output styles:
+
+ === =============== ===================================================
+ M Name Description
+ === =============== ===================================================
+ a argument The content appears as a 'const char \*' argument
+ c colon A colon (":") is appended after the label
+ d display Only emit field for display styles (text/HTML)
+ e encoding Only emit for encoding styles (XML/JSON)
+ g gettext Call gettext on field's render content
+ h humanize (hn) Format large numbers in human-readable style
+ \ hn-space Humanize: Place space between numeric and unit
+ \ hn-decimal Humanize: Add a decimal digit, if number < 10
+ \ hn-1000 Humanize: Use 1000 as divisor instead of 1024
+ k key Field is a key, suitable for XPath predicates
+ l leaf-list Field is a leaf-list
+ n no-quotes Do not quote the field when using JSON style
+ p plural Gettext: Use comma-separated plural form
+ q quotes Quote the field when using JSON style
+ t trim Trim leading and trailing whitespace
+ w white A blank (" ") is appended after the label
+ === =============== ===================================================
+
+Roles and modifiers can also use more verbose names, when preceded by
+a comma. For example, the modifier string "Lwc" (or "L,white,colon")
+means the field has a label role (text that describes the next field)
+and should be followed by a colon ('c') and a space ('w'). The
+modifier string "Vkq" (or ":key,quote") means the field has a value
+role (the default role), that it is a key for the current instance,
+and that the value should be quoted when encoded for JSON.
+
+.. index:: Field Modifiers; Argument
+.. _argument-modifier:
+
+The Argument Modifier ({a:})
+++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Argument
+
+The argument modifier indicates that the content of the field
+descriptor will be placed as a UTF-8 string (const char \*) argument
+within the xo_emit parameters::
+
+ EXAMPLE:
+ xo_emit("{La:} {a:}\n", "Label text", "label", "value");
+ TEXT:
+ Label text value
+ JSON:
+ "label": "value"
+ XML:
+ <label>value</label>
+
+The argument modifier allows field names for value fields to be passed
+on the stack, avoiding the need to build a field descriptor using
+snprintf. For many field roles, the argument modifier is not needed,
+since those roles have specific mechanisms for arguments, such as
+"{C:fg-%s}".
+
+.. index:: Field Modifiers; Colon
+.. _colon-modifier:
+
+The Colon Modifier ({c:})
++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Colon
+
+The colon modifier appends a single colon to the data value::
+
+ EXAMPLE:
+ xo_emit("{Lc:Name}{:name}\n", "phil");
+ TEXT:
+ Name:phil
+
+The colon modifier is only used for the TEXT and HTML output
+styles. It is commonly combined with the space modifier ('{w:}').
+It is purely a convenience feature.
+
+.. index:: Field Modifiers; Display
+.. _display-modifier:
+
+The Display Modifier ({d:})
++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Display
+
+The display modifier indicated the field should only be generated for
+the display output styles, TEXT and HTML::
+
+ EXAMPLE:
+ xo_emit("{Lcw:Name}{d:name} {:id/%d}\n", "phil", 1);
+ TEXT:
+ Name: phil 1
+ XML:
+ <id>1</id>
+
+The display modifier is the opposite of the encoding modifier, and
+they are often used to give to distinct views of the underlying data.
+
+.. index:: Field Modifiers; Encoding
+.. _encoding-modifier:
+
+The Encoding Modifier ({e:})
+++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Encoding
+
+The display modifier indicated the field should only be generated for
+the display output styles, TEXT and HTML::
+
+ EXAMPLE:
+ xo_emit("{Lcw:Name}{:name} {e:id/%d}\n", "phil", 1);
+ TEXT:
+ Name: phil
+ XML:
+ <name>phil</name><id>1</id>
+
+The encoding modifier is the opposite of the display modifier, and
+they are often used to give to distinct views of the underlying data.
+
+.. index:: Field Modifiers; Gettext
+.. _gettext-modifier:
+
+The Gettext Modifier ({g:})
++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Gettext
+.. index:: gettext
+
+The gettext modifier is used to translate individual fields using the
+gettext domain (typically set using the "`{G:}`" role) and current
+language settings. Once libxo renders the field value, it is passed
+to gettext(3), where it is used as a key to find the native language
+translation.
+
+In the following example, the strings "State" and "full" are passed
+to gettext() to find locale-based translated strings::
+
+ xo_emit("{Lgwc:State}{g:state}\n", "full");
+
+See :ref:`gettext-role`, :ref:`plural-modifier`, and
+:ref:`i18n` for additional details.
+
+.. index:: Field Modifiers; Humanize
+.. _humanize-modifier:
+
+The Humanize Modifier ({h:})
+++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Humanize
+
+The humanize modifier is used to render large numbers as in a
+human-readable format. While numbers like "44470272" are completely
+readable to computers and savants, humans will generally find "44M"
+more meaningful.
+
+"hn" can be used as an alias for "humanize".
+
+The humanize modifier only affects display styles (TEXT and HMTL).
+The "`no-humanize`" option (See :ref:`options`) will block
+the function of the humanize modifier.
+
+There are a number of modifiers that affect details of humanization.
+These are only available in as full names, not single characters. The
+"`hn-space`" modifier places a space between the number and any
+multiplier symbol, such as "M" or "K" (ex: "44 K"). The
+"`hn-decimal`" modifier will add a decimal point and a single tenths
+digit when the number is less than 10 (ex: "4.4K"). The "`hn-1000`"
+modifier will use 1000 as divisor instead of 1024, following the
+JEDEC-standard instead of the more natural binary powers-of-two
+tradition::
+
+ EXAMPLE:
+ xo_emit("{h:input/%u}, {h,hn-space:output/%u}, "
+ "{h,hn-decimal:errors/%u}, {h,hn-1000:capacity/%u}, "
+ "{h,hn-decimal:remaining/%u}\n",
+ input, output, errors, capacity, remaining);
+ TEXT:
+ 21, 57 K, 96M, 44M, 1.2G
+
+In the HTML style, the original numeric value is rendered in the
+"data-number" attribute on the <div> element::
+
+ <div class="data" data-tag="errors"
+ data-number="100663296">96M</div>
+
+.. index:: Field Modifiers; Key
+.. _key-modifier:
+
+The Key Modifier ({k:})
++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Key
+
+The key modifier is used to indicate that a particular field helps
+uniquely identify an instance of list data::
+
+ EXAMPLE:
+ xo_open_list("user");
+ for (i = 0; i < num_users; i++) {
+ xo_open_instance("user");
+ xo_emit("User {k:name} has {:count} tickets\n",
+ user[i].u_name, user[i].u_tickets);
+ xo_close_instance("user");
+ }
+ xo_close_list("user");
+
+.. index:: XOF_XPATH
+
+Currently the key modifier is only used when generating XPath value
+for the HTML output style when XOF_XPATH is set, but other uses are
+likely in the near future.
+
+.. index:: Field Modifiers; Leaf-List
+.. _leaf-list:
+
+The Leaf-List Modifier ({l:})
++++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Leaf-List
+
+The leaf-list modifier is used to distinguish lists where each
+instance consists of only a single value. In XML, these are
+rendered as single elements, where JSON renders them as arrays::
+
+ EXAMPLE:
+ for (i = 0; i < num_users; i++) {
+ xo_emit("Member {l:user}\n", user[i].u_name);
+ }
+ XML:
+ <user>phil</user>
+ <user>pallavi</user>
+ JSON:
+ "user": [ "phil", "pallavi" ]
+
+The name of the field must match the name of the leaf list.
+
+.. index:: Field Modifiers; No-Quotes
+.. _no-quotes-modifier:
+
+The No-Quotes Modifier ({n:})
++++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; No-Quotes
+
+The no-quotes modifier (and its twin, the 'quotes' modifier) affect
+the quoting of values in the JSON output style. JSON uses quotes for
+string value, but no quotes for numeric, boolean, and null data.
+xo_emit applies a simple heuristic to determine whether quotes are
+needed, but often this needs to be controlled by the caller::
+
+ EXAMPLE:
+ const char *bool = is_true ? "true" : "false";
+ xo_emit("{n:fancy/%s}", bool);
+ JSON:
+ "fancy": true
+
+.. index:: Field Modifiers; Plural
+.. _plural-modifier:
+
+The Plural Modifier ({p:})
+++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Plural
+.. index:: gettext
+
+The plural modifier selects the appropriate plural form of an
+expression based on the most recent number emitted and the current
+language settings. The contents of the field should be the singular
+and plural English values, separated by a comma::
+
+ xo_emit("{:bytes} {Ngp:byte,bytes}\n", bytes);
+
+The plural modifier is meant to work with the gettext modifier ({g:})
+but can work independently. See :ref:`gettext-modifier`.
+
+When used without the gettext modifier or when the message does not
+appear in the message catalog, the first token is chosen when the last
+numeric value is equal to 1; otherwise the second value is used,
+mimicking the simple pluralization rules of English.
+
+When used with the gettext modifier, the ngettext(3) function is
+called to handle the heavy lifting, using the message catalog to
+convert the singular and plural forms into the native language.
+
+.. index:: Field Modifiers; Quotes
+.. _quotes-modifier:
+
+The Quotes Modifier ({q:})
+++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Quotes
+
+The quotes modifier (and its twin, the 'no-quotes' modifier) affect
+the quoting of values in the JSON output style. JSON uses quotes for
+string value, but no quotes for numeric, boolean, and null data.
+xo_emit applies a simple heuristic to determine whether quotes are
+needed, but often this needs to be controlled by the caller::
+
+ EXAMPLE:
+ xo_emit("{q:time/%d}", 2014);
+ JSON:
+ "year": "2014"
+
+The heuristic is based on the format; if the format uses any of the
+following conversion specifiers, then no quotes are used::
+
+ d i o u x X D O U e E f F g G a A c C p
+
+.. index:: Field Modifiers; Trim
+.. _trim-modifier:
+
+The Trim Modifier ({t:})
+++++++++++++++++++++++++
+
+.. index:: Field Modifiers; Trim
+
+The trim modifier removes any leading or trailing whitespace from
+the value::
+
+ EXAMPLE:
+ xo_emit("{t:description}", " some input ");
+ JSON:
+ "description": "some input"
+
+.. index:: Field Modifiers; White Space
+.. _white-space-modifier:
+
+The White Space Modifier ({w:})
++++++++++++++++++++++++++++++++
+
+.. index:: Field Modifiers; White Space
+
+The white space modifier appends a single space to the data value::
+
+ EXAMPLE:
+ xo_emit("{Lw:Name}{:name}\n", "phil");
+ TEXT:
+ Name phil
+
+The white space modifier is only used for the TEXT and HTML output
+styles. It is commonly combined with the colon modifier ('{c:}').
+It is purely a convenience feature.
+
+Note that the sense of the 'w' modifier is reversed for the units role
+({Uw:}); a blank is added before the contents, rather than after it.
diff --git a/doc/field-roles.rst b/doc/field-roles.rst
new file mode 100644
index 000000000000..3499aea81aba
--- /dev/null
+++ b/doc/field-roles.rst
@@ -0,0 +1,317 @@
+
+.. index:: Field Roles
+.. _field-roles:
+
+Field Roles
+~~~~~~~~~~~
+
+Field roles are optional, and indicate the role and formatting of the
+content. The roles are listed below; only one role is permitted:
+
+ === ============== =================================================
+ R Name Description
+ === ============== =================================================
+ C color Field has color and effect controls
+ D decoration Field is non-text (e.g., colon, comma)
+ E error Field is an error message
+ G gettext Call gettext(3) on the format string
+ L label Field is text that prefixes a value
+ N note Field is text that follows a value
+ P padding Field is spaces needed for vertical alignment
+ T title Field is a title value for headings
+ U units Field is the units for the previous value field
+ V value Field is the name of field (the default)
+ W warning Field is a warning message
+ [ start-anchor Begin a section of anchored variable-width text
+ ] stop-anchor End a section of anchored variable-width text
+ === ============== =================================================
+
+::
+
+ EXAMPLE:
+ xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n",
+ free_blocks);
+
+When a role is not provided, the "*value*" role is used as the default.
+
+Roles and modifiers can also use more verbose names, when preceded by
+a comma::
+
+ EXAMPLE:
+ xo_emit("{,label:Free}{,decoration::}{,padding: }"
+ "{,value:free/%u} {,units:Blocks}\n",
+ free_blocks);
+
+.. index:: Field Roles; Color
+.. _color-role:
+
+The Color Role ({C:})
++++++++++++++++++++++
+
+Colors and effects control how text values are displayed; they are
+used for display styles (TEXT and HTML)::
+
+ xo_emit("{C:bold}{:value}{C:no-bold}\n", value);
+
+Colors and effects remain in effect until modified by other "C"-role
+fields::
+
+ xo_emit("{C:bold}{C:inverse}both{C:no-bold}only inverse\n");
+
+If the content is empty, the "*reset*" action is performed::
+
+ xo_emit("{C:both,underline}{:value}{C:}\n", value);
+
+The content should be a comma-separated list of zero or more colors or
+display effects::
+
+ xo_emit("{C:bold,inverse}Ugly{C:no-bold,no-inverse}\n");
+
+The color content can be either static, when placed directly within
+the field descriptor, or a printf-style format descriptor can be used,
+if preceded by a slash ("/"):
+
+ xo_emit("{C:/%s%s}{:value}{C:}", need_bold ? "bold" : "",
+ need_underline ? "underline" : "", value);
+
+Color names are prefixed with either "fg-" or "bg-" to change the
+foreground and background colors, respectively::
+
+ xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
+ fg_color, bg_color, cost);
+
+The following table lists the supported effects:
+
+ =============== =================================================
+ Name Description
+ =============== =================================================
+ bg-XXXXX Change background color
+ bold Start bold text effect
+ fg-XXXXX Change foreground color
+ inverse Start inverse (aka reverse) text effect
+ no-bold Stop bold text effect
+ no-inverse Stop inverse (aka reverse) text effect
+ no-underline Stop underline text effect
+ normal Reset effects (only)
+ reset Reset colors and effects (restore defaults)
+ underline Start underline text effect
+ =============== =================================================
+
+The following color names are supported:
+
+ ========= ============================================
+ Name Description
+ ========= ============================================
+ black
+ blue
+ cyan
+ default Default color for foreground or background
+ green
+ magenta
+ red
+ white
+ yellow
+ ========= ============================================
+
+When using colors, the developer should remember that users will
+change the foreground and background colors of terminal session
+according to their own tastes, so assuming that "blue" looks nice is
+never safe, and is a constant annoyance to your dear author. In
+addition, a significant percentage of users (1 in 12) will be color
+blind. Depending on color to convey critical information is not a
+good idea. Color should enhance output, but should not be used as the
+sole means of encoding information.
+
+.. index:: Field Roles; Decoration
+.. _decoration-role:
+
+The Decoration Role ({D:})
+++++++++++++++++++++++++++
+
+Decorations are typically punctuation marks such as colons,
+semi-colons, and commas used to decorate the text and make it simpler
+for human readers. By marking these distinctly, HTML usage scenarios
+can use CSS to direct their display parameters::
+
+ xo_emit("{D:((}{:name}{D:))}\n", name);
+
+.. index:: Field Roles; Gettext
+.. _gettext-role:
+
+The Gettext Role ({G:})
++++++++++++++++++++++++
+
+libxo supports internationalization (i18n) through its use of
+gettext(3). Use the "{G:}" role to request that the remaining part of
+the format string, following the "{G:}" field, be handled using
+gettext().
+
+Since gettext() uses the string as the key into the message catalog,
+libxo uses a simplified version of the format string that removes
+unimportant field formatting and modifiers, stopping minor formatting
+changes from impacting the expensive translation process. A developer
+change such as changing "/%06d" to "/%08d" should not force hand
+inspection of all .po files.
+
+The simplified version can be generated for a single message using the
+"`xopo -s $text`" command, or an entire .pot can be translated using
+the "`xopo -f $input -o $output`" command.
+
+ xo_emit("{G:}Invalid token\n");
+
+The {G:} role allows a domain name to be set. gettext calls will
+continue to use that domain name until the current format string
+processing is complete, enabling a library function to emit strings
+using it's own catalog. The domain name can be either static as the
+content of the field, or a format can be used to get the domain name
+from the arguments.
+
+ xo_emit("{G:libc}Service unavailable in restricted mode\n");
+
+See :ref:`i18n` for additional details.
+
+.. index:: Field Roles; Label
+.. _label-role:
+
+The Label Role ({L:})
++++++++++++++++++++++
+
+Labels are text that appears before a value::
+
+ xo_emit("{Lwc:Cost}{:cost/%u}\n", cost);
+
+If a label needs to include a slash, it must be escaped using two
+backslashes, one for the C compiler and one for libxo::
+
+ xo_emit("{Lc:Low\\/warn level}{:level/%s}\n", level);
+
+.. index:: Field Roles; Note
+.. _note-role:
+
+The Note Role ({N:})
+++++++++++++++++++++
+
+Notes are text that appears after a value::
+
+ xo_emit("{:cost/%u} {N:per year}\n", cost);
+
+.. index:: Field Roles; Padding
+.. _padding-role:
+
+The Padding Role ({P:})
++++++++++++++++++++++++
+
+Padding represents whitespace used before and between fields.
+
+The padding content can be either static, when placed directly within
+the field descriptor, or a printf-style format descriptor can be used,
+if preceded by a slash ("/")::
+
+ xo_emit("{P: }{Lwc:Cost}{:cost/%u}\n", cost);
+ xo_emit("{P:/%30s}{Lwc:Cost}{:cost/%u}\n", "", cost);
+
+.. index:: Field Roles; Title
+.. _title-role:
+
+The Title Role ({T:})
++++++++++++++++++++++
+
+Title are heading or column headers that are meant to be displayed to
+the user. The title can be either static, when placed directly within
+the field descriptor, or a printf-style format descriptor can be used,
+if preceded by a slash ("/")::
+
+ xo_emit("{T:Interface Statistics}\n");
+ xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost");
+
+Title fields have an extra convenience feature; if both content and
+format are specified, instead of looking to the argument list for a
+value, the content is used, allowing a mixture of format and content
+within the field descriptor::
+
+ xo_emit("{T:Name/%20s}{T:Count/%6s}\n");
+
+Since the incoming argument is a string, the format must be "%s" or
+something suitable.
+
+.. index:: Field Roles; Units
+.. index:: XOF_UNITS
+.. _units-role:
+
+The Units Role ({U:})
++++++++++++++++++++++
+
+Units are the dimension by which values are measured, such as degrees,
+miles, bytes, and decibels. The units field carries this information
+for the previous value field::
+
+ xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\n", miles);
+
+Note that the sense of the 'w' modifier is reversed for units;
+a blank is added before the contents, rather than after it.
+
+When the XOF_UNITS flag is set, units are rendered in XML as the
+"units" attribute::
+
+ <distance units="miles">50</distance>
+
+Units can also be rendered in HTML as the "data-units" attribute::
+
+ <div class="data" data-tag="distance" data-units="miles"
+ data-xpath="/top/data/distance">50</div>
+
+.. index:: Field Roles; Value
+.. _value-role:
+
+The Value Role ({V:} and {:})
++++++++++++++++++++++++++++++
+
+The value role is used to represent the a data value that is
+interesting for the non-display output styles (XML and JSON). Value
+is the default role; if no other role designation is given, the field
+is a value. The field name must appear within the field descriptor,
+followed by one or two format descriptors. The first format
+descriptor is used for display styles (TEXT and HTML), while the
+second one is used for encoding styles (XML and JSON). If no second
+format is given, the encoding format defaults to the first format,
+with any minimum width removed. If no first format is given, both
+format descriptors default to "%s"::
+
+ xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\n",
+ length, width, height);
+ xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n,
+ author, poem, year);
+
+.. index:: Field Roles; Anchor
+.. _anchor-role:
+
+The Anchor Roles ({[:} and {]:})
+++++++++++++++++++++++++++++++++
+
+The anchor roles allow a set of strings by be padded as a group,
+but still be visible to xo_emit as distinct fields. Either the start
+or stop anchor can give a field width and it can be either directly in
+the descriptor or passed as an argument. Any fields between the start
+and stop anchor are padded to meet the minimum width given.
+
+To give a width directly, encode it as the content of the anchor tag::
+
+ xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\n", min, max);
+
+To pass a width as an argument, use "%d" as the format, which must
+appear after the "/". Note that only "%d" is supported for widths.
+Using any other value could ruin your day::
+
+ xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\n", width, min, max);
+
+If the width is negative, padding will be added on the right, suitable
+for left justification. Otherwise the padding will be added to the
+left of the fields between the start and stop anchors, suitable for
+right justification. If the width is zero, nothing happens. If the
+number of columns of output between the start and stop anchors is less
+than the absolute value of the given width, nothing happens.
+
+.. index:: XOF_WARN
+
+Widths over 8k are considered probable errors and not supported. If
+XOF_WARN is set, a warning will be generated.
diff --git a/doc/format-strings.rst b/doc/format-strings.rst
new file mode 100644
index 000000000000..44e02abd41e7
--- /dev/null
+++ b/doc/format-strings.rst
@@ -0,0 +1,47 @@
+
+.. index:: Format Strings
+.. _format-strings:
+
+Format Strings
+--------------
+
+libxo uses format strings to control the rendering of data into the
+various output styles. Each format string contains a set of zero or
+more field descriptions, which describe independent data fields. Each
+field description contains a set of modifiers, a content string, and
+zero, one, or two format descriptors. The modifiers tell libxo what
+the field is and how to treat it, while the format descriptors are
+formatting instructions using printf-style format strings, telling
+libxo how to format the field. The field description is placed inside
+a set of braces, with a colon (":") after the modifiers and a slash
+("/") before each format descriptors. Text may be intermixed with
+field descriptions within the format string.
+
+The field description is given as follows::
+
+ '{' [ role | modifier ]* [',' long-names ]* ':' [ content ]
+ [ '/' field-format [ '/' encoding-format ]] '}'
+
+The role describes the function of the field, while the modifiers
+enable optional behaviors. The contents, field-format, and
+encoding-format are used in varying ways, based on the role. These
+are described in the following sections.
+
+In the following example, three field descriptors appear. The first
+is a padding field containing three spaces of padding, the second is a
+label ("In stock"), and the third is a value field ("in-stock"). The
+in-stock field has a "%u" format that will parse the next argument
+passed to the xo_emit function as an unsigned integer::
+
+ xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 65);
+
+This single line of code can generate text (" In stock: 65\n"), XML
+("<in-stock>65</in-stock>"), JSON ('"in-stock": 6'), or HTML (too
+lengthy to be listed here).
+
+While roles and modifiers typically use single character for brevity,
+there are alternative names for each which allow more verbose
+formatting strings. These names must be preceded by a comma, and may
+follow any single-character values::
+
+ xo_emit("{L,white,colon:In stock}{,key:in-stock/%u}\n", 65);
diff --git a/doc/formatting.rst b/doc/formatting.rst
new file mode 100644
index 000000000000..dbbdd24dfcc8
--- /dev/null
+++ b/doc/formatting.rst
@@ -0,0 +1,165 @@
+
+Formatting with libxo
+=====================
+
+Most unix commands emit text output aimed at humans. It is designed
+to be parsed and understood by a user. Humans are gifted at
+extracting details and pattern matching in such output. Often
+programmers need to extract information from this human-oriented
+output. Programmers use tools like grep, awk, and regular expressions
+to ferret out the pieces of information they need. Such solutions are
+fragile and require maintenance when output contents change or evolve,
+along with testing and validation.
+
+Modern tool developers favor encoding schemes like XML and JSON,
+which allow trivial parsing and extraction of data. Such formats are
+simple, well understood, hierarchical, easily parsed, and often
+integrate easier with common tools and environments. Changes to
+content can be done in ways that do not break existing users of the
+data, which can reduce maintenance costs and increase feature velocity.
+
+In addition, modern reality means that more output ends up in web
+browsers than in terminals, making HTML output valuable.
+
+libxo allows a single set of function calls in source code to generate
+traditional text output, as well as XML and JSON formatted data. HTML
+can also be generated; "<div>" elements surround the traditional text
+output, with attributes that detail how to render the data.
+
+A single libxo function call in source code is all that's required::
+
+ xo_emit("Connecting to {:host}.{:domain}...\n", host, domain);
+
+ TEXT:
+ Connecting to my-box.example.com...
+ XML:
+ <host>my-box</host>
+ <domain>example.com</domain>
+ JSON:
+ "host": "my-box",
+ "domain": "example.com"
+ HTML:
+ <div class="line">
+ <div class="text">Connecting to </div>
+ <div class="data" data-tag="host"
+ data-xpath="/top/host">my-box</div>
+ <div class="text">.</div>
+ <div class="data" data-tag="domain"
+ data-xpath="/top/domain">example.com</div>
+ <div class="text">...</div>
+ </div>
+
+Encoding Styles
+---------------
+
+There are four encoding styles supported by libxo:
+
+- TEXT output can be display on a terminal session, allowing
+ compatibility with traditional command line usage.
+- XML output is suitable for tools like XPath and protocols like
+ NETCONF.
+- JSON output can be used for RESTful APIs and integration with
+ languages like Javascript and Python.
+- HTML can be matched with a small CSS file to permit rendering in any
+ HTML5 browser.
+
+In general, XML and JSON are suitable for encoding data, while TEXT is
+suited for terminal output and HTML is suited for display in a web
+browser (see :ref:`xohtml`).
+
+Text Output
+~~~~~~~~~~~
+
+Most traditional programs generate text output on standard output,
+with contents like::
+
+ 36 ./src
+ 40 ./bin
+ 90 .
+
+In this example (taken from *du* source code), the code to generate this
+data might look like::
+
+ printf("%d\t%s\n", num_blocks, path);
+
+Simple, direct, obvious. But it's only making text output. Imagine
+using a single code path to make TEXT, XML, JSON or HTML, deciding at
+run time which to generate.
+
+libxo expands on the idea of printf format strings to make a single
+format containing instructions for creating multiple output styles::
+
+ xo_emit("{:blocks/%d}\t{:path/%s}\n", num_blocks, path);
+
+This line will generate the same text output as the earlier printf
+call, but also has enough information to generate XML, JSON, and HTML.
+
+The following sections introduce the other formats.
+
+XML Output
+~~~~~~~~~~
+
+XML output consists of a hierarchical set of elements, each encoded
+with a start tag and an end tag. The element should be named for data
+value that it is encoding::
+
+ <item>
+ <blocks>36</blocks>
+ <path>./src</path>
+ </item>
+ <item>
+ <blocks>40</blocks>
+ <path>./bin</path>
+ </item>
+ <item>
+ <blocks>90</blocks>
+ <path>.</path>
+ </item>
+
+`XML`_ is the W3C standard for encoding data.
+
+.. _XML: https://w3c.org/TR/xml
+
+JSON Output
+~~~~~~~~~~~
+
+JSON output consists of a hierarchical set of objects and lists, each
+encoded with a quoted name, a colon, and a value. If the value is a
+string, it must be quoted, but numbers are not quoted. Objects are
+encoded using braces; lists are encoded using square brackets.
+Data inside objects and lists is separated using commas::
+
+ items: [
+ { "blocks": 36, "path" : "./src" },
+ { "blocks": 40, "path" : "./bin" },
+ { "blocks": 90, "path" : "./" }
+ ]
+
+HTML Output
+~~~~~~~~~~~
+
+HTML output is designed to allow the output to be rendered in a web
+browser with minimal effort. Each piece of output data is rendered
+inside a <div> element, with a class name related to the role of the
+data. By using a small set of class attribute values, a CSS
+stylesheet can render the HTML into rich text that mirrors the
+traditional text content.
+
+Additional attributes can be enabled to provide more details about the
+data, including data type, description, and an XPath location::
+
+ <div class="line">
+ <div class="data" data-tag="blocks">36</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="path">./src</div>
+ </div>
+ <div class="line">
+ <div class="data" data-tag="blocks">40</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="path">./bin</div>
+ </div>
+ <div class="line">
+ <div class="data" data-tag="blocks">90</div>
+ <div class="padding"> </div>
+ <div class="data" data-tag="path">./</div>
+ </div>
diff --git a/doc/getting.rst b/doc/getting.rst
new file mode 100644
index 000000000000..1511aada5a1e
--- /dev/null
+++ b/doc/getting.rst
@@ -0,0 +1,185 @@
+
+.. index:: Getting libxo
+
+Getting libxo
+=============
+
+libxo now ships as part of the FreeBSD Operating System (as of Release
+11).
+
+libxo source code lives on github:
+
+ https://github.com/Juniper/libxo
+
+The latest release of libxo is available at:
+
+ https://github.com/Juniper/libxo/releases
+
+We're using `Semantic Versioning`_ to number our releases. libxo is
+open source, distributed under the BSD license. We follow the
+branching scheme from `A Successful Git Branching Model`_:
+we do development under the "*develop*" branch, and release from
+the "*master*" branch. To clone a developer tree, run the following
+command::
+
+ git clone https://github.com/Juniper/libxo.git -b develop
+
+.. _Semantic Versioning: http://semver.org/spec/v2.0.0.html
+.. _A Successful Git Branching Model:
+ http://nvie.com/posts/a-successful-git-branching-model
+
+Issues, problems, and bugs should be directly to the issues page on
+our github site.
+
+Downloading libxo Source Code
+-----------------------------
+
+You can retrieve the source for libxo in two ways:
+
+A. Use a "distfile" for a specific release. We use github to maintain
+ our releases. Visit the `release page`_ to see the list of
+ releases. To download the latest, look for the release witeh the
+ green "Latest release" button and the green "libxo-RELEASE.tar.gz"
+ button under that section.
+
+.. _release page: https://github.com/Juniper/libxo/releases
+
+ After downloading that release's distfile, untar it as follows::
+
+ tar -zxf libxo-RELEASE.tar.gz
+ cd libxo-RELEASE
+
+ .. admonition:: Solaris Users
+
+ Note: for Solaris users, your "`tar`" command lacks the "-z" flag,
+ so you'll need to substitute "`gzip -dc $file | tar xf -`" instead
+ of "`tar -zxf $file`".
+
+B. Use the current build from github. This gives you the most recent
+ source code, which might be less stable than a specific release. To
+ build libxo from the git repo::
+
+ git clone https://github.com/Juniper/libxo.git
+ cd libxo
+
+ .. admonition:: Be Aware
+
+ The github repository does **not** contain the files generated by
+ "*autoreconf*", with the notable exception of the "*m4*" directory.
+ Since these files (depcomp, configure, missing, install-sh, etc) are
+ generated files, we keep them out of the source code repository.
+
+ This means that if you download the a release distfile, these files
+ will be ready and you'll just need to run "configure", but if you
+ download the source code from svn, then you'll need to run
+ "*autoreconf*" by hand. This step is done for you by the "*setup.sh*"
+ script, described in the next section.
+
+.. _building:
+
+Building libxo
+--------------
+
+To build libxo, you'll need to set up the build, run the "*configure*"
+script, run the "*make*" command, and run the regression tests.
+
+The following is a summary of the commands needed. These commands are
+explained in detail in the rest of this section::
+
+ sh bin/setup.sh
+ cd build
+ ../configure
+ make
+ make test
+ sudo make install
+
+The following sections will walk through each of these steps with
+additional details and options, but the above directions should be all
+that's needed.
+
+Setting up the build
+~~~~~~~~~~~~~~~~~~~~
+
+.. admonition: Note
+
+ If you downloaded a distfile, you can skip this step.
+
+Run the "*setup.sh*" script to set up the build. This script runs the
+"*autoreconf*" command to generate the "*configure*" script and other
+generated files::
+
+ sh bin/setup.sh
+
+Note: We're are currently using autoreconf version 2.69.
+
+Running the "configure" Script
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Configure (and autoconf in general) provides a means of building
+software in diverse environments. Our configure script supports
+a set of options that can be used to adjust to your operating
+environment. Use "`configure --help`" to view these options.
+
+We use the "*build*" directory to keep object files and generated files
+away from the source tree.
+
+To run the configure script, change into the "*build*" directory, and
+run the "*configure*" script. Add any required options to the
+"`../configure`" command line::
+
+ cd build
+ ../configure
+
+Expect to see the "*configure*" script generate the following error::
+
+ /usr/bin/rm: cannot remove `libtoolT': No such file or directory
+
+This error is harmless and can be safely ignored.
+
+By default, libxo installs architecture-independent files, including
+extension library files, in the /usr/local directories. To specify an
+installation prefix other than /usr/local for all installation files,
+include the --prefix=prefix option and specify an alternate
+location. To install just the extension library files in a different,
+user-defined location, include the "*--with-extensions-dir=dir*" option
+and specify the location where the extension libraries will live::
+
+ cd build
+ ../configure [OPTION]... [VAR=VALUE]...
+
+Running the "make" Command
+++++++++++++++++++++++++++
+
+Once the "*configure*" script is run, build the images using the
+"`make`" command::
+
+ make
+
+Running the Regression Tests
+++++++++++++++++++++++++++++
+
+libxo includes a set of regression tests that can be run to ensure
+the software is working properly. These test are optional, but will
+help determine if there are any issues running libxo on your
+machine. To run the regression tests::
+
+ make test
+
+Installing libxo
+~~~~~~~~~~~~~~~~
+
+Once the software is built, you'll need to install libxo using the
+"`make install`" command. If you are the root user, or the owner of
+the installation directory, simply issue the command::
+
+ make install
+
+If you are not the "*root*" user and are using the "*sudo*" package, use::
+
+ sudo make install
+
+Verify the installation by viewing the output of "`xo --version`"::
+
+ % xo --version
+ libxo version 0.3.5-git-develop
+ xo version 0.3.5-git-develop
diff --git a/doc/howto.rst b/doc/howto.rst
new file mode 100644
index 000000000000..513572355bbc
--- /dev/null
+++ b/doc/howto.rst
@@ -0,0 +1,394 @@
+
+Howtos: Focused Directions
+==========================
+
+This section provides task-oriented instructions for selected tasks.
+If you have a task that needs instructions, please open a request as
+an enhancement issue on github.
+
+Howto: Report bugs
+------------------
+
+libxo uses github to track bugs or request enhancements. Please use
+the following URL:
+
+ https://github.com/Juniper/libxo/issues
+
+Howto: Install libxo
+--------------------
+
+libxo is open source, under a new BSD license. Source code is
+available on github, as are recent releases. To get the most
+current release, please visit:
+
+ https://github.com/Juniper/libxo/releases
+
+After downloading and untarring the source code, building involves the
+following steps::
+
+ sh bin/setup.sh
+ cd build
+ ../configure
+ make
+ make test
+ sudo make install
+
+libxo uses a distinct "*build*" directory to keep generated files
+separated from source files.
+
+.. index:: configure
+
+Use "`../configure --help`" to display available configuration
+options, which include the following::
+
+ --enable-warnings Turn on compiler warnings
+ --enable-debug Turn on debugging
+ --enable-text-only Turn on text-only rendering
+ --enable-printflike Enable use of GCC __printflike attribute
+ --disable-libxo-options Turn off support for LIBXO_OPTIONS
+ --with-gettext=PFX Specify location of gettext installation
+ --with-libslax-prefix=PFX Specify location of libslax config
+
+Compiler warnings are a very good thing, but recent compiler version
+have added some very pedantic checks. While every attempt is made to
+keep libxo code warning-free, warnings are now optional. If you are
+doing development work on libxo, it is required that you
+use --enable-warnings to keep the code warning free, but most users
+need not use this option.
+
+.. index:: --enable-text-only
+
+libxo provides the `--enable-text-only` option to reduce the
+footprint of the library for smaller installations. XML, JSON, and
+HTML rendering logic is removed.
+
+.. index:: --with-gettext
+
+The gettext library does not provide a simple means of learning its
+location, but libxo will look for it in /usr and /opt/local. If
+installed elsewhere, the installer will need to provide this
+information using the "`--with-gettext=/dir/path`" option.
+
+.. index:: libslax
+
+libslax is not required by libxo; it contains the "oxtradoc" program
+used to format documentation.
+
+For additional information, see :ref:`building`.
+
+Howto: Convert command line applications
+----------------------------------------
+
+Common question: How do I convert an existing command line application?
+
+There are four basic steps for converting command line application to
+use libxo::
+
+- Setting up the context
+- Converting printf calls
+- Creating hierarchy
+- Converting error functions
+
+Setting up the context
+~~~~~~~~~~~~~~~~~~~~~~
+
+To use libxo, you'll need to include the "xo.h" header file in your
+source code files::
+
+ #include <libxo/xo.h>
+
+In your main() function, you'll need to call xo_parse_args to handling
+argument parsing (:ref:`xo_parse_args`). This function removes
+libxo-specific arguments the program's argv and returns either the
+number of remaining arguments or -1 to indicate an error::
+
+ int
+ main (int argc, char **argv)
+ {
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ return argc;
+ ....
+ }
+
+.. index:: atexit
+.. index:: xo_finish_atexit
+
+At the bottom of your main(), you'll need to call xo_finish() to
+complete output processing for the default handle (:ref:`handles`). This
+is required to flush internal information buffers. libxo provides the
+xo_finish_atexit function that is suitable for use with the
+:manpage:`atexit(3)` function::
+
+ atexit(xo_finish_atexit);
+
+Converting printf Calls
+~~~~~~~~~~~~~~~~~~~~~~~
+
+The second task is inspecting code for :manpage:`printf(3)` calls and
+replacing them with xo_emit() calls. The format strings are similar
+in task, but libxo format strings wrap output fields in braces. The
+following two calls produce identical text output::
+
+ OLD::
+ printf("There are %d %s events\n", count, etype);
+
+ NEW::
+ xo_emit("There are {:count/%d} {:event} events\n", count, etype);
+
+"count" and "event" are used as names for JSON and XML output. The
+"count" field uses the format "%d" and "event" uses the default "%s"
+format. Both are "value" roles, which is the default role.
+
+Since text outside of output fields is passed verbatim, other roles
+are less important, but their proper use can help make output more
+useful. The "note" and "label" roles allow HTML output to recognize
+the relationship between text and the associated values, allowing
+appropriate "hover" and "onclick" behavior. Using the "units" role
+allows the presentation layer to perform conversions when needed. The
+"warning" and "error" roles allows use of color and font to draw
+attention to warnings. The "padding" role makes the use of vital
+whitespace more clear (:ref:`padding-role`).
+
+The "*title*" role indicates the headings of table and sections. This
+allows HTML output to use CSS to make this relationship more obvious::
+
+ OLD::
+ printf("Statistics:\n");
+
+ NEW::
+ xo_emit("{T:Statistics}:\n");
+
+The "*color*" roles controls foreground and background colors, as well
+as effects like bold and underline (see :ref:`color-role`)::
+
+ NEW::
+ xo_emit("{C:bold}required{C:}\n");
+
+Finally, the start- and stop-anchor roles allow justification and
+padding over multiple fields (see :ref:`anchor-role`)::
+
+ OLD::
+ snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max);
+ printf("%30s", buf);
+
+ NEW::
+ xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}",
+ min, ave, max);
+
+Creating Hierarchy
+~~~~~~~~~~~~~~~~~~
+
+Text output doesn't have any sort of hierarchy, but XML and JSON
+require this. Typically applications use indentation to represent
+these relationship::
+
+ OLD::
+ printf("table %d\n", tnum);
+ for (i = 0; i < tmax; i++) {
+ printf(" %s %d\n", table[i].name, table[i].size);
+ }
+
+ NEW::
+ xo_emit("{T:/table %d}\n", tnum);
+ xo_open_list("table");
+ for (i = 0; i < tmax; i++) {
+ xo_open_instance("table");
+ xo_emit("{P: }{k:name} {:size/%d}\n",
+ table[i].name, table[i].size);
+ xo_close_instance("table");
+ }
+ xo_close_list("table");
+
+The open and close list functions are used before and after the list,
+and the open and close instance functions are used before and after
+each instance with in the list.
+
+Typically these developer looks for a "for" loop as an indication of
+where to put these calls.
+
+In addition, the open and close container functions allow for
+organization levels of hierarchy::
+
+ OLD::
+ printf("Paging information:\n");
+ printf(" Free: %lu\n", free);
+ printf(" Active: %lu\n", active);
+ printf(" Inactive: %lu\n", inactive);
+
+ NEW::
+ xo_open_container("paging-information");
+ xo_emit("{P: }{L:Free: }{:free/%lu}\n", free);
+ xo_emit("{P: }{L:Active: }{:active/%lu}\n", active);
+ xo_emit("{P: }{L:Inactive: }{:inactive/%lu}\n", inactive);
+ xo_close_container("paging-information");
+
+Converting Error Functions
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+libxo provides variants of the standard error and warning functions,
+:manpage:`err(3)` and :manpage:`warn(3)`. There are two variants, one
+for putting the errors on standard error, and the other writes the
+errors and warnings to the handle using the appropriate encoding
+style::
+
+ OLD::
+ err(1, "cannot open output file: %s", file);
+
+ NEW::
+ xo_err(1, "cannot open output file: %s", file);
+ xo_emit_err(1, "cannot open output file: {:filename}", file);
+
+.. index:: xo_finish
+
+Call xo_finish
+~~~~~~~~~~~~~~
+
+One important item: call `xo_finish` at the end of your program so
+ensure that all buffered data is written out. You can call it
+explicitly call it, or use :manpage:`atexit(3)` to have
+`xo_finish_atexit` called implicitly on exit::
+
+ OLD::
+ exit(0);
+
+ NEW::
+ xo_finish();
+ exit(0);
+
+Howto: Use "xo" in Shell Scripts
+--------------------------------
+
+.. admonition:: Needed
+
+ Documentation is needed for this area.
+
+.. index:: Internationalization (i18n)
+.. index:: gettext
+.. index:: xopo
+
+.. _i18n:
+
+Howto: Internationalization (i18n)
+-----------------------------------------------
+
+ How do I use libxo to support internationalization?
+
+libxo allows format and field strings to be used a keys into message
+catalogs to enable translation into a user's native language by
+invoking the standard :manpage:`gettext(3)` functions.
+
+gettext setup is a bit complicated: text strings are extracted from
+source files into "*portable object template*" (.pot) files using the
+`xgettext` command. For each language, this template file is used as
+the source for a message catalog in the "*portable object*" (.po)
+format, which are translated by hand and compiled into "*machine
+object*" (.mo) files using the `msgfmt` command. The .mo files are
+then typically installed in the /usr/share/locale or
+/opt/local/share/locale directories. At run time, the user's language
+settings are used to select a .mo file which is searched for matching
+messages. Text strings in the source code are used as keys to look up
+the native language strings in the .mo file.
+
+Since the xo_emit format string is used as the key into the message
+catalog, libxo removes unimportant field formatting and modifiers from
+the format string before use so that minor formatting changes will not
+impact the expensive translation process. We don't want a developer
+change such as changing "/%06d" to "/%08d" to force hand inspection of
+all .po files. The simplified version can be generated for a single
+message using the `xopo -s $text` command, or an entire .pot can be
+translated using the `xopo -f $input -o $output` command::
+
+ EXAMPLE:
+ % xopo -s "There are {:count/%u} {:event/%.6s} events\n"
+ There are {:count} {:event} events\n
+
+ Recommended workflow:
+ # Extract text messages
+ xgettext --default-domain=foo --no-wrap \
+ --add-comments --keyword=xo_emit --keyword=xo_emit_h \
+ --keyword=xo_emit_warn -C -E -n --foreign-user \
+ -o foo.pot.raw foo.c
+
+ # Simplify format strings for libxo
+ xopo -f foo.pot.raw -o foo.pot
+
+ # For a new language, just copy the file
+ cp foo.pot po/LC/my_lang/foo.po
+
+ # For an existing language:
+ msgmerge --no-wrap po/LC/my_lang/foo.po \
+ foo.pot -o po/LC/my_lang/foo.po.new
+
+ # Now the hard part: translate foo.po using tools
+ # like poedit or emacs' po-mode
+
+ # Compile the finished file; Use of msgfmt's "-v" option is
+ # strongly encouraged, so that "fuzzy" entries are reported.
+ msgfmt -v -o po/my_lang/LC_MESSAGES/foo.mo po/my_lang/foo.po
+
+ # Install the .mo file
+ sudo cp po/my_lang/LC_MESSAGES/foo.mo \
+ /opt/local/share/locale/my_lang/LC_MESSAGE/
+
+Once these steps are complete, you can use the `gettext` command to
+test the message catalog::
+
+ gettext -d foo -e "some text"
+
+i18n and xo_emit
+~~~~~~~~~~~~~~~~
+
+There are three features used in libxo used to support i18n:
+
+- The "{G:}" role looks for a translation of the format string.
+- The "{g:}" modifier looks for a translation of the field.
+- The "{p:}" modifier looks for a pluralized version of the field.
+
+Together these three flags allows a single function call to give
+native language support, as well as libxo's normal XML, JSON, and HTML
+support::
+
+ printf(gettext("Received %zu %s from {g:server} server\n"),
+ counter, ngettext("byte", "bytes", counter),
+ gettext("web"));
+
+ xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} "
+ "from {g:server} server\n", counter, "web");
+
+libxo will see the "{G:}" role and will first simplify the format
+string, removing field formats and modifiers::
+
+ "Received {:received} {N:byte,bytes} from {:server} server\n"
+
+libxo calls :manpage:`gettext(3)` with that string to get a localized
+version. If your language were *Pig Latin*, the result might look
+like::
+
+ "Eceivedray {:received} {N:byte,bytes} omfray "
+ "{:server} erversay\n"
+
+Note the field names do not change and they should not be translated.
+The contents of the note ("byte,bytes") should also not be translated,
+since the "g" modifier will need the untranslated value as the key for
+the message catalog.
+
+The field "{g:server}" requests the rendered value of the field be
+translated using :manpage:`gettext(3)`. In this example, "web" would
+be used.
+
+The field "{Ngp:byte,bytes}" shows an example of plural form using the
+"{p:}" modifier with the "{g:}" modifier. The base singular and plural
+forms appear inside the field, separated by a comma. At run time,
+libxo uses the previous field's numeric value to decide which form to
+use by calling :manpage:`ngettext(3)`.
+
+If a domain name is needed, it can be supplied as the content of the
+{G:} role. Domain names remain in use throughout the format string
+until cleared with another domain name::
+
+ printf(dgettext("dns", "Host %s not found: %d(%s)\n"),
+ name, errno, dgettext("strerror", strerror(errno)));
+
+ xo_emit("{G:dns}Host {:hostname} not found: "
+ "%d({G:strerror}{g:%m})\n", name, errno);
diff --git a/doc/index.rst b/doc/index.rst
new file mode 100644
index 000000000000..116be40533ea
--- /dev/null
+++ b/doc/index.rst
@@ -0,0 +1,54 @@
+.. #
+ # Copyright (c) 2014, Juniper Networks, Inc.
+ # All rights reserved.
+ # This SOFTWARE is licensed under the LICENSE provided in the
+ # ../Copyright file. By downloading, installing, copying, or
+ # using the SOFTWARE, you agree to be bound by the terms of that
+ # LICENSE.
+ # Phil Shafer, July 2014
+ #
+
+.. default-role:: code
+
+libxo - A Library for Generating Text, XML, JSON, and HTML Output
+===================================================================
+
+The libxo library allows an application to generate text, XML, JSON,
+and HTML output, suitable for both command line use and for web
+applications. The application decides at run time which output style
+should be produced. By using libxo, a single source code path can
+emit multiple styles of output using command line options to select
+the style, along with optional behaviors. libxo includes support for
+multiple output streams, pluralization, color, syslog,
+:manpage:`humanized(3)` output, internationalization, and UTF-8. The
+library aims to minimize the cost of migrating code to libxo.
+
+libxo ships as part of FreeBSD.
+
+.. toctree::
+ :maxdepth: 3
+ :caption: Documentation Contents:
+
+ intro
+ getting
+ formatting
+ options
+ format-strings
+ field-roles
+ field-modifiers
+ field-formatting
+ api
+ encoders
+ xo
+ xolint
+ xohtml
+ xopo
+ faq
+ howto
+ example
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`search`
diff --git a/doc/intro.rst b/doc/intro.rst
new file mode 100644
index 000000000000..40b3a4f4a5de
--- /dev/null
+++ b/doc/intro.rst
@@ -0,0 +1,90 @@
+
+Introducing libxo
+=================
+
+The libxo library allows an application to generate text, XML, JSON,
+and HTML output using a common set of function calls. The application
+decides at run time which output style should be produced. The
+application calls a function "xo_emit" to product output that is
+described in a format string. A "field descriptor" tells libxo what
+the field is and what it means. Each field descriptor is placed in
+braces with printf-like :ref:`format-strings`::
+
+ xo_emit(" {:lines/%7ju} {:words/%7ju} "
+ "{:characters/%7ju} {d:filename/%s}\n",
+ linect, wordct, charct, file);
+
+Each field can have a role, with the 'value' role being the default,
+and the role tells libxo how and when to render that field (see
+:ref:`field-roles` for details). Modifiers change how the field is
+rendered in different output styles (see :ref:`field-modifiers` for
+details. Output can then be generated in various style, using the
+"--libxo" option::
+
+ % wc /etc/motd
+ 25 165 1140 /etc/motd
+ % wc --libxo xml,pretty,warn /etc/motd
+ <wc>
+ <file>
+ <lines>25</lines>
+ <words>165</words>
+ <characters>1140</characters>
+ <filename>/etc/motd</filename>
+ </file>
+ </wc>
+ % wc --libxo json,pretty,warn /etc/motd
+ {
+ "wc": {
+ "file": [
+ {
+ "lines": 25,
+ "words": 165,
+ "characters": 1140,
+ "filename": "/etc/motd"
+ }
+ ]
+ }
+ }
+ % wc --libxo html,pretty,warn /etc/motd
+ <div class="line">
+ <div class="text"> </div>
+ <div class="data" data-tag="lines"> 25</div>
+ <div class="text"> </div>
+ <div class="data" data-tag="words"> 165</div>
+ <div class="text"> </div>
+ <div class="data" data-tag="characters"> 1140</div>
+ <div class="text"> </div>
+ <div class="data" data-tag="filename">/etc/motd</div>
+ </div>
+
+Same code path, same format strings, same information, but it's
+rendered in distinct styles based on run-time flags.
+
+.. admonition:: Tale of Two Code Paths
+
+ You want to prepare for the future, but you need to live in the
+ present. You'd love a flying car, but need to get work done today.
+ You want to support features like XML, JSON, and HTML rendering to
+ allow integration with NETCONF, REST, and web browsers, but you need
+ to make text output for command line users.
+
+ And you don't want multiple code paths that can't help but get out
+ of sync::
+
+ /* None of this "if (xml) {... } else {...}" logic */
+ if (xml) {
+ /* some code to make xml */
+ } else {
+ /* other code to make text */
+ /* oops! forgot to add something on both clauses! */
+ }
+
+ /* And ifdefs are right out. */
+ #ifdef MAKE_XML
+ /* icky */
+ #else
+ /* pooh */
+ #endif
+
+ But you'd really, really like all the fancy features that modern
+ encoding formats can provide. libxo can help.
diff --git a/doc/options.rst b/doc/options.rst
new file mode 100644
index 000000000000..79cd360a1f44
--- /dev/null
+++ b/doc/options.rst
@@ -0,0 +1,184 @@
+
+.. index:: --libxo
+.. index:: Options
+
+.. _options:
+
+Command-line Arguments
+======================
+
+libxo uses command line options to trigger rendering behavior. There
+are multiple conventions for passing options, all using the
+"`--libxo`" option::
+
+ --libxo <options>
+ --libxo=<options>
+ --libxo:<brief-options>
+
+The *brief-options* is a series of single letter abbrevations, where
+the *options* is a comma-separated list of words. Both provide access
+to identical functionality. The following invocations are all
+identical in outcome::
+
+ my-app --libxo warn,pretty arg1
+ my-app --libxo=warn,pretty arg1
+ my-app --libxo:WP arg1
+
+Programs using libxo are expecting to call the xo_parse_args function
+to parse these arguments. See :ref:`xo_parse_args` for details.
+
+Option Keywords
+---------------
+
+Options is a comma-separated list of tokens that correspond to output
+styles, flags, or features:
+
+ =============== =======================================================
+ Token Action
+ =============== =======================================================
+ color Enable colors/effects for display styles (TEXT, HTML)
+ colors=xxxx Adjust color output values
+ dtrt Enable "Do The Right Thing" mode
+ flush Flush after every libxo function call
+ flush-line Flush after every line (line-buffered)
+ html Emit HTML output
+ indent=xx Set the indentation level
+ info Add info attributes (HTML)
+ json Emit JSON output
+ keys Emit the key attribute for keys (XML)
+ log-gettext Log (via stderr) each gettext(3) string lookup
+ log-syslog Log (via stderr) each syslog message (via xo_syslog)
+ no-humanize Ignore the {h:} modifier (TEXT, HTML)
+ no-locale Do not initialize the locale setting
+ no-retain Prevent retaining formatting information
+ no-top Do not emit a top set of braces (JSON)
+ not-first Pretend the 1st output item was not 1st (JSON)
+ pretty Emit pretty-printed output
+ retain Force retaining formatting information
+ text Emit TEXT output
+ underscores Replace XML-friendly "-"s with JSON friendly "_"s
+ units Add the 'units' (XML) or 'data-units (HTML) attribute
+ warn Emit warnings when libxo detects bad calls
+ warn-xml Emit warnings in XML
+ xml Emit XML output
+ xpath Add XPath expressions (HTML)
+ =============== =======================================================
+
+Most of these option are simple and direct, but some require
+additional details:
+
+- "colors" is described in :ref:`color-mapping`.
+- "flush-line" performs line buffering, even when the output is not
+ directed to a TTY device.
+- "info" generates additional data for HTML, encoded in attributes
+ using names that state with "data-".
+- "keys" adds a "key" attribute for XML output to indicate that a leaf
+ is an identifier for the list member.
+- "no-humanize" avoids "humanizing" numeric output (see
+ :ref:`humanize-modifier` for details).
+- "no-locale" instructs libxo to avoid translating output to the
+ current locale.
+- "no-retain" disables the ability of libxo to internally retain
+ "compiled" information about formatting strings (see :ref:`retain`
+ for details).
+- "underscores" can be used with JSON output to change XML-friendly
+ names with dashes into JSON-friendly name with underscores.
+- "warn" allows libxo to emit warnings on stderr when application code
+ make incorrect calls.
+- "warn-xml" causes those warnings to be placed in XML inside the
+ output.
+
+Brief Options
+-------------
+
+The brief options are simple single-letter aliases to the normal
+keywords, as detailed below:
+
+ ======== =============================================
+ Option Action
+ ======== =============================================
+ c Enable color/effects for TEXT/HTML
+ F Force line-buffered flushing
+ H Enable HTML output (XO_STYLE_HTML)
+ I Enable info output (XOF_INFO)
+ i<num> Indent by <number>
+ J Enable JSON output (XO_STYLE_JSON)
+ k Add keys to XPATH expressions in HTML
+ n Disable humanization (TEXT, HTML)
+ P Enable pretty-printed output (XOF_PRETTY)
+ T Enable text output (XO_STYLE_TEXT)
+ U Add units to HTML output
+ u Change "-"s to "_"s in element names (JSON)
+ W Enable warnings (XOF_WARN)
+ X Enable XML output (XO_STYLE_XML)
+ x Enable XPath data (XOF_XPATH)
+ ======== =============================================
+
+.. index:: Colors
+
+.. _color-mapping:
+
+Color Mapping
+-------------
+
+The "colors" option takes a value that is a set of mappings from the
+pre-defined set of colors to new foreground and background colors.
+The value is a series of "fg/bg" values, separated by a "+". Each
+pair of "fg/bg" values gives the colors to which a basic color is
+mapped when used as a foreground or background color. The order is
+the mappings is:
+
+- black
+- red
+- green
+- yellow
+- blue
+- magenta
+- cyan
+- white
+
+Pairs may be skipped, leaving them mapped as normal, as are missing
+pairs or single colors.
+
+For example consider the following xo_emit call::
+
+ xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n");
+
+To turn all colored output to red-on-blue, use eight pairs of
+"red/blue" mappings separated by plus signs ("+")::
+
+ --libxo colors=red/blue+red/blue+red/blue+red/blue+\
+ red/blue+red/blue+red/blue+red/blue
+
+To turn the red-on-green text to magenta-on-cyan, give a "magenta"
+foreground value for red (the second mapping) and a "cyan" background
+to green (the third mapping)::
+
+ --libxo colors=+magenta+/cyan
+
+Consider the common situation where blue output looks unreadable on a
+terminal session with a black background. To turn both "blue"
+foreground and background output to "yellow", give only the fifth
+mapping, skipping the first four mappings with bare plus signs ("+")::
+
+ --libxo colors=++++yellow/yellow
+
+Encoders
+--------
+
+In addition to the four "built-in" formats, libxo supports an
+extensible mechanism for adding encoders. These are activated
+using the "encoder" keyword::
+
+ --libxo encoder=cbor
+
+The encoder can include encoder-specific options, separated by either
+colons (":") or plus signs ("+"):
+
+ --libxo encoder=csv+path=filesystem+leaf=name+no-header
+ --libxo encoder=csv:path=filesystem:leaf=name:no-header
+
+For brevity, the string "@" can be used in place of the string
+"encoder=".
+
+ df --libxo @csv:no-header
diff --git a/doc/xo.rst b/doc/xo.rst
new file mode 100644
index 000000000000..5a9e8819122e
--- /dev/null
+++ b/doc/xo.rst
@@ -0,0 +1,234 @@
+.. index:: --libxo, xo
+.. _xo:
+
+The "xo" Utility
+================
+
+The `xo` utility allows command line access to the functionality of
+the libxo library. Using `xo`, shell scripts can emit XML, JSON, and
+HTML using the same commands that emit text output.
+
+The style of output can be selected using a specific option: "-X" for
+XML, "-J" for JSON, "-H" for HTML, or "-T" for TEXT, which is the
+default. The "--style <style>" option can also be used. The standard
+set of "--libxo" options are available (see :ref:`options`), as well
+as the :ref:`LIBXO_OPTIONS <libxo-options>` environment variable.
+
+The `xo` utility accepts a format string suitable for `xo_emit` and
+a set of zero or more arguments used to supply data for that string::
+
+ xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6
+
+ TEXT:
+ The fish weighs 6 pounds.
+
+ XML:
+ <name>fish</name>
+ <weight>6</weight>
+
+ JSON:
+ "name": "fish",
+ "weight": 6
+
+ HTML:
+ <div class="line">
+ <div class="text">The </div>
+ <div class="data" data-tag="name">fish</div>
+ <div class="text"> weighs </div>
+ <div class="data" data-tag="weight">6</div>
+ <div class="text"> pounds.</div>
+ </div>
+
+The `--wrap $path` option can be used to wrap emitted content in a
+specific hierarchy. The path is a set of hierarchical names separated
+by the '/' character::
+
+ xo --wrap top/a/b/c '{:tag}' value
+
+ XML:
+ <top>
+ <a>
+ <b>
+ <c>
+ <tag>value</tag>
+ </c>
+ </b>
+ </a>
+ </top>
+
+ JSON:
+ "top": {
+ "a": {
+ "b": {
+ "c": {
+ "tag": "value"
+ }
+ }
+ }
+ }
+
+The `--open $path` and `--close $path` can be used to emit
+hierarchical information without the matching close and open
+tag. This allows a shell script to emit open tags, data, and
+then close tags. The `--depth` option may be used to set the
+depth for indentation. The `--leading-xpath` may be used to
+prepend data to the XPath values used for HTML output style::
+
+ EXAMPLE:
+ #!/bin/sh
+ xo --open top/data
+ xo --depth 2 '{:tag}' value
+ xo --close top/data
+
+ XML:
+ <top>
+ <data>
+ <tag>value</tag>
+ </data>
+ </top>
+
+ JSON:
+ "top": {
+ "data": {
+ "tag": "value"
+ }
+ }
+
+When making partial lines of output (where the format string does not
+include a newline), use the `--continuation` option to let secondary
+invocations know they are adding data to an existing line.
+
+When emitting a series of objects, use the `--not-first` option to
+ensure that any details from the previous object (e.g. commas in JSON)
+are handled correctly.
+
+Use the `--top-wrap` option to ensure any top-level object details are
+handled correctly, e.g. wrap the entire output in a top-level set of
+braces for JSON output.
+
+::
+
+ EXAMPLE:
+ #!/bin/sh
+ xo --top-wrap --open top/data
+ xo --depth 2 'First {:tag} ' value1
+ xo --depth 2 --continuation 'and then {:tag}\n' value2
+ xo --top-wrap --close top/data
+
+ TEXT:
+ First value1 and then value2
+
+ HTML:
+ <div class="line">
+ <div class="text">First </div>
+ <div class="data" data-tag="tag">value1</div>
+ <div class="text"> </div>
+ <div class="text">and then </div>
+ <div class="data" data-tag="tag">value2</div>
+ </div>
+
+ XML:
+ <top>
+ <data>
+ <tag>value1</tag>
+ <tag>value2</tag>
+ </data>
+ </top>
+
+ JSON:
+ {
+ "top": {
+ "data": {
+ "tag": "value1",
+ "tag": "value2"
+ }
+ }
+ }
+
+Lists and Instances
+-------------------
+
+A "*list*" is set of one or more instances that appear under the same
+parent. The instances contain details about a specific object. One
+can think of instances as objects or records. A call is needed to
+open and close the list, while a distinct call is needed to open and
+close each instance of the list.
+
+Use the `--open-list` and `--open-instances` to open lists and
+instances. Use the `--close-list` and `--close-instances` to close
+them. Each of these options take a `name` parameter, providing the
+name of the list and instance.
+
+In the following example, a list named "machine" is created with three
+instances::
+
+ opts="--json"
+ xo $opts --open-list machine
+ NF=
+ for name in red green blue; do
+ xo $opts --depth 1 $NF --open-instance machine
+ xo $opts --depth 2 "Machine {k:name} has {:memory}\n" $name 55
+ xo $opts --depth 1 --close-instance machine
+ NF=--not-first
+ done
+ xo $opts $NF --close-list machine
+
+The normal `libxo` functions use a state machine to help these
+transitions, but since each `xo` command is invoked independent of the
+previous calls, the state must be passed in explicitly via these
+command line options.
+
+The `--instance` option can be used to treat a single `xo` invocation
+as an instance with the given set of fields::
+
+ % xo --libxo:XP --instance foo 'The {:product} is {:status}\n' stereo "in route"
+ <foo>
+ <product>stereo</product>
+ <status>in route</status>
+ </foo>
+
+Command Line Options
+--------------------
+
+::
+
+ Usage: xo [options] format [fields]
+ --close <path> Close tags for the given path
+ --close-instance <name> Close an open instance name
+ --close-list <name> Close an open list name
+ --continuation OR -C Output belongs on same line as previous output
+ --depth <num> Set the depth for pretty printing
+ --help Display this help text
+ --html OR -H Generate HTML output
+ --instance OR -I <name> Wrap in an instance of the given name
+ --json OR -J Generate JSON output
+ --leading-xpath <path> Add a prefix to generated XPaths (HTML)
+ --not-first Indicate this object is not the first (JSON)
+ --open <path> Open tags for the given path
+ --open-instance <name> Open an instance given by name
+ --open-list <name> Open a list given by name
+ --option <opts> -or -O <opts> Give formatting options
+ --pretty OR -p Make 'pretty' output (add indent, newlines)
+ --style <style> Generate given style (xml, json, text, html)
+ --text OR -T Generate text output (the default style)
+ --top-wrap Generate a top-level object wrapper (JSON)
+ --version Display version information
+ --warn OR -W Display warnings in text on stderr
+ --warn-xml Display warnings in xml on stdout
+ --wrap <path> Wrap output in a set of containers
+ --xml OR -X Generate XML output
+ --xpath Add XPath data to HTML output)
+
+Example
+-------
+
+::
+
+ % xo 'The {:product} is {:status}\n' stereo "in route"
+ The stereo is in route
+ % xo -p -X 'The {:product} is {:status}\n' stereo "in route"
+ <product>stereo</product>
+ <status>in route</status>
+ % xo --libxo xml,pretty 'The {:product} is {:status}\n' stereo "in route"
+ <product>stereo</product>
+ <status>in route</status>
diff --git a/doc/xohtml.rst b/doc/xohtml.rst
new file mode 100644
index 000000000000..f92e63f4d9c1
--- /dev/null
+++ b/doc/xohtml.rst
@@ -0,0 +1,30 @@
+.. index:: xohtml
+
+.. _xohtml:
+
+xohtml
+======
+
+`xohtml` is a tool for turning the output of libxo-enabled commands into
+html files suitable for display in modern HTML web browsers. It can
+be used to test and debug HTML output, as well as to make the user
+ache to escape the world of '70s terminal devices.
+
+`xohtml` is given a command, either on the command line or via the "-c"
+option. If not command is given, standard input is used. The
+command's output is wrapped in HTML tags, with references to
+supporting CSS and Javascript files, and written to standard output or
+the file given in the "-f" option. The "-b" option can be used to
+provide an alternative base path for the support files:
+
+ ============== ===================================================
+ Option Meaning
+ ============== ===================================================
+ -b <base> Base path for finding css/javascript files
+ -c <command> Command to execute
+ -f <file> Output file name
+ ============== ===================================================
+
+The "-c" option takes a full command with arguments, including
+any libxo options needed to generate html (`--libxo=html`). This
+value must be quoted if it consists of multiple tokens.
diff --git a/doc/xolint-errors.rst b/doc/xolint-errors.rst
new file mode 100644
index 000000000000..c3e518b9cddf
--- /dev/null
+++ b/doc/xolint-errors.rst
@@ -0,0 +1,444 @@
+'A percent sign appearing in text is a literal'
++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "A percent sign appearing in text is a literal" can be caused by code like:
+
+::
+
+ xo_emit("cost: %d", cost);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{L:cost}: {:cost/%d}", cost);
+
+This can be a bit surprising and could be a field that was not
+properly converted to a libxo-style format string.
+
+
+'Unknown long name for role/modifier'
++++++++++++++++++++++++++++++++++++++
+
+The message "Unknown long name for role/modifier" can be caused by code like:
+
+::
+
+ xo_emit("{,humanization:value}", value);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{,humanize:value}", value);
+
+The hn-* modifiers (hn-decimal, hn-space, hn-1000)
+are only valid for fields with the {h:} modifier.
+
+
+'Last character before field definition is a field type'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Last character before field definition is a field type" can be caused by code like:
+A common typo:
+
+::
+
+ xo_emit("{T:Min} T{:Max}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{T:Min} {T:Max}");
+
+Twiddling the "{" and the field role is a common typo.
+
+
+'Encoding format uses different number of arguments'
+++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Encoding format uses different number of arguments" can be caused by code like:
+
+::
+
+ xo_emit("{:name/%6.6s %%04d/%s}", name, number);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:name/%6.6s %04d/%s-%d}", name, number);
+
+Both format should consume the same number of arguments off the stack
+
+
+'Only one field role can be used'
++++++++++++++++++++++++++++++++++
+
+The message "Only one field role can be used" can be caused by code like:
+
+::
+
+ xo_emit("{LT:Max}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{T:Max}");
+
+'Potential missing slash after C, D, N, L, or T with format'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like:
+
+::
+
+ xo_emit("{T:%6.6s}\n", "Max");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{T:/%6.6s}\n", "Max");
+
+The "%6.6s" will be a literal, not a field format. While
+it's possibly valid, it's likely a missing "/".
+
+
+'An encoding format cannot be given (roles: DNLT)'
+++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like:
+
+::
+
+ xo_emit("{T:Max//%s}", "Max");
+
+Fields with the C, D, N, L, and T roles are not emitted in
+the 'encoding' style (JSON, XML), so an encoding format
+would make no sense.
+
+
+'Format cannot be given when content is present (roles: CDLN)'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like:
+
+::
+
+ xo_emit("{N:Max/%6.6s}", "Max");
+
+Fields with the C, D, L, or N roles can't have both
+static literal content ("{L:Label}") and a
+format ("{L:/%s}").
+This error will also occur when the content has a backslash
+in it, like "{N:Type of I/O}"; backslashes should be escaped,
+like "{N:Type of I\\/O}". Note the double backslash, one for
+handling 'C' strings, and one for libxo.
+
+
+'Field has color without fg- or bg- (role: C)'
+++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Field has color without fg- or bg- (role: C)" can be caused by code like:
+
+::
+
+ xo_emit("{C:green}{:foo}{C:}", x);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{C:fg-green}{:foo}{C:}", x);
+
+Colors must be prefixed by either "fg-" or "bg-".
+
+
+'Field has invalid color or effect (role: C)'
++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Field has invalid color or effect (role: C)" can be caused by code like:
+
+::
+
+ xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x);
+
+The list of colors and effects are limited. The
+set of colors includes default, black, red, green,
+yellow, blue, magenta, cyan, and white, which must
+be prefixed by either "fg-" or "bg-". Effects are
+limited to bold, no-bold, underline, no-underline,
+inverse, no-inverse, normal, and reset. Values must
+be separated by commas.
+
+
+'Field has humanize modifier but no format string'
+++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Field has humanize modifier but no format string" can be caused by code like:
+
+::
+
+ xo_emit("{h:value}", value);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{h:value/%d}", value);
+
+Humanization is only value for numbers, which are not
+likely to use the default format ("%s").
+
+
+'Field has hn-* modifier but not 'h' modifier'
+++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like:
+
+::
+
+ xo_emit("{,hn-1000:value}", value);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{h,hn-1000:value}", value);
+
+The hn-* modifiers (hn-decimal, hn-space, hn-1000)
+are only valid for fields with the {h:} modifier.
+
+
+'Value field must have a name (as content)")'
++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Value field must have a name (as content)")" can be caused by code like:
+
+::
+
+ xo_emit("{:/%s}", "value");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:tag-name/%s}", "value");
+
+The field name is used for XML and JSON encodings. These
+tags names are static and must appear directly in the
+field descriptor.
+
+
+'Use hyphens, not underscores, for value field name'
+++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Use hyphens, not underscores, for value field name" can be caused by code like:
+
+::
+
+ xo_emit("{:no_under_scores}", "bad");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:no-under-scores}", "bad");
+
+Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
+flag can be used to generate underscores in JSON, if desired.
+But the raw field name should use hyphens.
+
+
+'Value field name cannot start with digit'
+++++++++++++++++++++++++++++++++++++++++++
+
+The message "Value field name cannot start with digit" can be caused by code like:
+
+::
+
+ xo_emit("{:10-gig/}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:ten-gig/}");
+
+XML element names cannot start with a digit.
+
+
+'Value field name should be lower case'
++++++++++++++++++++++++++++++++++++++++
+
+The message "Value field name should be lower case" can be caused by code like:
+
+::
+
+ xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:why-are-you-shouting}", "no reason");
+
+Lower case is more civilized. Even TLAs should be lower case
+to avoid scenarios where the differences between "XPath" and
+"Xpath" drive your users crazy. Lower case rules the seas.
+
+
+'Value field name should be longer than two characters'
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Value field name should be longer than two characters" can be caused by code like:
+
+::
+
+ xo_emit("{:x}", "mumble");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:something-meaningful}", "mumble");
+
+Field names should be descriptive, and it's hard to
+be descriptive in less than two characters. Consider
+your users and try to make something more useful.
+Note that this error often occurs when the field type
+is placed after the colon ("{:T/%20s}"), instead of before
+it ("{T:/20s}").
+
+
+'Value field name contains invalid character'
++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Value field name contains invalid character" can be caused by code like:
+
+::
+
+ xo_emit("{:cost-in-$$/%u}", 15);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:cost-in-dollars/%u}", 15);
+
+An invalid character is often a sign of a typo, like "{:]}"
+instead of "{]:}". Field names are restricted to lower-case
+characters, digits, and hyphens.
+
+
+'decoration field contains invalid character'
++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "decoration field contains invalid character" can be caused by code like:
+
+::
+
+ xo_emit("{D:not good}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{D:((}{:good}{D:))}", "yes");
+
+This is minor, but fields should use proper roles. Decoration
+fields are meant to hold punctuation and other characters used
+to decorate the content, typically to make it more readable
+to human readers.
+
+
+'Anchor content should be decimal width'
+++++++++++++++++++++++++++++++++++++++++
+
+The message "Anchor content should be decimal width" can be caused by code like:
+
+::
+
+ xo_emit("{[:mumble}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{[:32}");
+
+Anchors need an integer value to specify the width of
+the set of anchored fields. The value can be positive
+(for left padding/right justification) or negative (for
+right padding/left justification) and can appear in
+either the start or stop anchor field descriptor.
+
+
+'Anchor format should be "%d"'
+++++++++++++++++++++++++++++++
+
+The message "Anchor format should be "%d"" can be caused by code like:
+
+::
+
+ xo_emit("{[:/%s}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{[:/%d}");
+
+Anchors only grok integer values, and if the value is not static,
+if must be in an 'int' argument, represented by the "%d" format.
+Anything else is an error.
+
+
+'Anchor cannot have both format and encoding format")'
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
+The message "Anchor cannot have both format and encoding format")" can be caused by code like:
+
+::
+
+ xo_emit("{[:32/%d}");
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{[:32}");
+
+Anchors can have a static value or argument for the width,
+but cannot have both.
+
+
+'Max width only valid for strings'
+++++++++++++++++++++++++++++++++++
+
+The message "Max width only valid for strings" can be caused by code like:
+
+::
+
+ xo_emit("{:tag/%2.4.6d}", 55);
+
+This code should be replaced with code like:
+
+::
+
+ xo_emit("{:tag/%2.6d}", 55);
+
+libxo allows a true 'max width' in addition to the traditional
+printf-style 'max number of bytes to use for input'. But this
+is supported only for string values, since it makes no sense
+for non-strings. This error may occur from a typo,
+like "{:tag/%6..6d}" where only one period should be used.
diff --git a/doc/xolint.rst b/doc/xolint.rst
new file mode 100644
index 000000000000..739fa18558f7
--- /dev/null
+++ b/doc/xolint.rst
@@ -0,0 +1,40 @@
+======
+xolint
+======
+
+`xolint` is a tool for reporting common mistakes in format strings
+in source code that invokes `xo_emit`. It allows these errors
+to be diagnosed at build time, rather than waiting until runtime.
+
+`xolint` takes the one or more C files as arguments, and reports
+and errors, warning, or informational messages as needed:
+
+ ============ ===================================================
+ Option Meaning
+ ============ ===================================================
+ -c Invoke 'cpp' against the input file
+ -C <flags> Flags that are passed to 'cpp
+ -d Enable debug output
+ -D Generate documentation for all xolint messages
+ -I Generate info table code
+ -p Print the offending lines after the message
+ -V Print vocabulary of all field names
+ -X Extract samples from xolint, suitable for testing
+ ============ ===================================================
+
+The output message will contain the source filename and line number, the
+class of the message, the message, and, if -p is given, the
+line that contains the error::
+
+ % xolint.pl -t xolint.c
+ xolint.c: 16: error: anchor format should be "%d"
+ 16 xo_emit("{[:/%s}");
+
+The "-I" option will generate a table of `xo_info_t`_ structures,
+suitable for inclusion in source code.
+
+.. _xo_info_t: :ref:`field-information`
+
+The "-V" option does not report errors, but prints a complete list of
+all field names, sorted alphabetically. The output can help spot
+inconsistencies and spelling errors.
diff --git a/doc/xopo.rst b/doc/xopo.rst
new file mode 100644
index 000000000000..b10c0da36e50
--- /dev/null
+++ b/doc/xopo.rst
@@ -0,0 +1,45 @@
+
+xopo
+====
+
+The `xopo` utility filters ".pot" files generated by the
+:manpage:`xgettext(1)` utility to remove formatting information
+suitable for use with the "{G:}" modifier. This means that when the
+developer changes the formatting portion of the field definitions, or
+the fields modifiers, the string passed to :manpage:`gettext(3)` is
+unchanged, avoiding the expense of updating any existing translation
+files (".po" files).
+
+The syntax for the xopo command is one of two forms; it can be used as
+a filter for processing a .po or .pot file, rewriting the "*msgid*"
+strings with a simplified message string. In this mode, the input is
+either standard input or a file given by the "-f" option, and the
+output is either standard output or a file given by the "-o" option.
+
+In the second mode, a simple message given using the "-s" option on
+the command, and the simplified version of that message is printed on
+stdout:
+
+ =========== =================================
+ Option Meaning
+ =========== =================================
+ -o <file> Output file name
+ -f <file> Use the given .po file as input
+ -s <text> Simplify a format string
+ =========== =================================
+
+::
+
+ EXAMPLE:
+ % xopo -s "There are {:count/%u} {:event/%.6s} events\n"
+ There are {:count} {:event} events\n
+
+ % xgettext --default-domain=foo --no-wrap \
+ --add-comments --keyword=xo_emit --keyword=xo_emit_h \
+ --keyword=xo_emit_warn -C -E -n --foreign-user \
+ -o foo.pot.raw foo.c
+ % xopo -f foo.pot.raw -o foo.pot
+
+Use of the `--no-wrap` option for `xgettext` is required to
+ensure that incoming msgid strings are not wrapped across multiple
+lines.
diff --git a/encoder/test/enc_test.c b/encoder/test/enc_test.c
index ad2a6b7a43b9..7107ba733ae9 100644
--- a/encoder/test/enc_test.c
+++ b/encoder/test/enc_test.c
@@ -14,8 +14,6 @@
static int
test_handler (XO_ENCODER_HANDLER_ARGS)
{
- flags &= ~XOF_UTF8; /* Skip this flag, since it depends on terminal */
-
printf("op %s: [%s] [%s] [%#llx]\n", xo_encoder_op_name(op),
name ?: "", value ?: "", (unsigned long long) flags);
diff --git a/libxo/Makefile.am b/libxo/Makefile.am
index bc039d141cf2..9f17527e68ec 100644
--- a/libxo/Makefile.am
+++ b/libxo/Makefile.am
@@ -22,8 +22,7 @@ AM_CFLAGS = \
${GETTEXT_CFLAGS}
AM_CFLAGS += \
- -DXO_ENCODERDIR=\"${XO_ENCODERDIR}\" \
- -DXO_SHAREDIR=\"${XO_SHAREDIR}\"
+ -DXO_ENCODERDIR=\"${XO_ENCODERDIR}\"
lib_LTLIBRARIES = libxo.la
diff --git a/libxo/gen-wide.sh b/libxo/gen-wide.sh
new file mode 100644
index 000000000000..b0342874b179
--- /dev/null
+++ b/libxo/gen-wide.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+
+FILE=$1
+
+SYMBOLS="
+xo_buffer_s
+xo_buffer_t
+xo_stack_s
+xo_stack_t
+xo_handle_s
+xo_handle_t
+xo_default_handle
+xo_default_inited
+xo_realloc
+xo_free
+xo_write_to_file
+xo_close_file
+xo_buf_init
+xo_init_handle
+xo_default_init
+xo_buf_has_room
+xo_printf
+xo_escape_xml
+xo_escape_json
+xo_buf_append
+xo_buf_escape
+xo_data_append
+xo_data_escape
+xo_default
+xo_indent
+xo_warn
+xo_create
+xo_create_to_file
+xo_destroy
+xo_set_style
+xo_set_flags
+xo_set_info
+xo_set_formatter
+xo_clear_flags
+xo_buf_indent
+xo_line_ensure_open
+xo_line_close
+xo_info_compare
+xo_info_find
+xo_format_data
+xo_buf_append_div
+xo_format_text
+xo_format_label
+xo_format_title
+xo_format_prep
+xo_format_value
+xo_format_decoration
+xo_format_padding
+xo_do_emit
+xo_emit_hv
+xo_emit_h
+xo_emit
+xo_attr_hv
+xo_attr_h
+xo_attr
+xo_depth_change
+xo_open_container_h
+xo_open_container
+xo_close_container_h
+xo_close_container
+xo_open_list_h
+xo_open_list
+xo_close_list_h
+xo_close_list
+xo_open_instance_h
+xo_open_instance
+xo_close_instance_h
+xo_close_instance
+xo_set_writer
+xo_set_allocator
+"
diff --git a/libxo/libxo-csv.7 b/libxo/libxo-csv.7
index 43cbd2e68f64..6e043820a010 100644
--- a/libxo/libxo-csv.7
+++ b/libxo/libxo-csv.7
@@ -139,8 +139,7 @@ used with
.Nm xo ,
the `--instance` option will be needed:
.Bd -literal -offset indent
- % xo --libxo encoder=csv --instance foo \\
- 'The {:product} is {:status}\\n' stereo "in route"
+ % xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route"
product,status
stereo,in route
.Ed
diff --git a/libxo/libxo.c b/libxo/libxo.c
index eb34c05946ad..916a111f5af2 100644
--- a/libxo/libxo.c
+++ b/libxo/libxo.c
@@ -42,7 +42,6 @@
#include <ctype.h>
#include <wctype.h>
#include <getopt.h>
-#include <langinfo.h>
#include "xo_config.h"
#include "xo.h"
@@ -97,10 +96,6 @@
#include <libintl.h>
#endif /* HAVE_GETTEXT */
-#if HAVE_ETEXT == 1 /* Symbol */
-extern char etext;
-#endif /* HAVE_ETEXT */
-
/* Rather lame that we can't count on these... */
#ifndef FALSE
#define FALSE 0
@@ -141,17 +136,6 @@ static const char xo_default_format[] = "%s";
#define UNUSED __attribute__ ((__unused__))
#endif /* UNUSED */
-#ifndef LIBXO_TEXT_ONLY
-/* We don't want the overhead of tag maps when in text-only mode */
-#define LIBXO_NEED_MAP
-
-#define XO_MAP_INCR 128 /* Must be even */
-
-#ifndef XO_MAPDIR
-#define XO_MAPDIR XO_SHAREDIR "/map"
-#endif /* XO_MAPDIR */
-#endif /* LIBXO_TEXT_ONLY */
-
#define XO_INDENT_BY 2 /* Amount to indent when pretty printing */
#define XO_DEPTH 128 /* Default stack depth */
#define XO_MAX_ANCHOR_WIDTH (8*1024) /* Anything wider is just silly */
@@ -284,12 +268,6 @@ struct xo_handle_s {
char *xo_gt_domain; /* Gettext domain, suitable for dgettext(3) */
xo_encoder_func_t xo_encoder; /* Encoding function */
void *xo_private; /* Private data for external encoders */
-#ifdef LIBXO_NEED_MAP
- char **xo_map; /* Name mapping array */
- int xo_map_size; /* Size (count) of xo_map[] */
- int xo_map_len; /* Current length (count) of xo_map[] */
- xo_buffer_t xo_map_data; /* Data values for name mapping */
-#endif /* LIBXO_NEED_MAP */
};
/* Flag operations */
@@ -415,7 +393,6 @@ static THREAD_LOCAL(xo_handle_t) xo_default_handle;
static THREAD_LOCAL(int) xo_default_inited;
static int xo_locale_inited;
static const char *xo_program;
-static int xo_codeset_is_utf8; /* Is stdout UTF-8? */
/*
* To allow libxo to be used in diverse environment, we allow the
@@ -445,9 +422,6 @@ xo_buf_append_div (xo_handle_t *xop, const char *class, xo_xff_flags_t flags,
static void
xo_anchor_clear (xo_handle_t *xop);
-static int
-xo_map_option (xo_handle_t *xop, const char *opts);
-
/*
* xo_style is used to retrieve the current style. When we're built
* for "text only" mode, we use this function to drive the removal
@@ -551,18 +525,6 @@ xo_printable (const char *str)
return res;
}
-static inline int
-xo_str_is_const (const char *str UNUSED)
-{
-#if HAVE_ETEXT == 1
- const char *xo_etext = (const char *) &etext;
-
- return (str < xo_etext);
-#else /* HAVE_ETEXT */
- return FALSE;
-#endif /* HAVE_ETEXT */
-}
-
static int
xo_depth_check (xo_handle_t *xop, int depth)
{
@@ -602,7 +564,7 @@ xo_no_setlocale (void)
static const char *
xo_xml_leader_len (xo_handle_t *xop, const char *name, xo_ssize_t nlen)
{
- if (name == NULL || name[0] == '\0' || isalpha(name[0]) || name[0] == '_')
+ if (name == NULL || isalpha(name[0]) || name[0] == '_')
return "";
xo_failure(xop, "invalid XML tag name: '%.*s'", nlen, name);
@@ -675,13 +637,6 @@ xo_init_handle (xo_handle_t *xop)
#endif /* __FreeBSD__ */
(void) setlocale(LC_CTYPE, cp);
-
-#ifdef CODESET
- /* Now that locale is set, determine if our stdout output is UTF-8 */
- const char *codeset = nl_langinfo(CODESET);
- if (codeset && xo_streq(codeset, "UTF-8"))
- xo_codeset_is_utf8 = TRUE;
-#endif /* CODESET */
}
/*
@@ -711,9 +666,6 @@ xo_default_init (void)
xo_init_handle(xop);
- if (xo_codeset_is_utf8)
- XOF_SET(xop, XOF_UTF8);
-
#if !defined(NO_LIBXO_OPTIONS)
if (!XOF_ISSET(xop, XOF_NO_ENV)) {
char *env = getenv("LIBXO_OPTIONS");
@@ -727,20 +679,6 @@ xo_default_init (void)
xo_default_inited = 1;
}
-#if 0
-/*
- * Is the output for this handle UTF-8?
- */
-static int
-xo_is_text_utf8 (xo_handle_t *xop)
-{
- if (xo_style(xop) == XO_STYLE_TEXT)
- return XOF_ISSET(xop, XOF_UTF8);
-
- return FALSE;
-}
-#endif
-
/*
* Cheap convenience function to return either the argument, or
* the internal handle, after it has been initialized. The usage
@@ -1381,12 +1319,6 @@ xo_retain_find (const char *fmt UNUSED, xo_field_info_t **valp UNUSED,
return -1;
}
-unsigned long
-xo_retain_get_hits (void)
-{
- return 0;
-}
-
#else /* !LIBXO_NO_RETAIN */
/*
* Retain: We retain parsed field definitions to enhance performance,
@@ -1422,7 +1354,6 @@ typedef struct xo_retain_s {
static THREAD_LOCAL(xo_retain_t) xo_retain;
static THREAD_LOCAL(unsigned) xo_retain_count;
-static THREAD_LOCAL(unsigned long) xo_retain_hits;
/*
* Simple hash function based on Thomas Wang's paper. The original is
@@ -1472,7 +1403,6 @@ xo_retain_clear_all (void)
xo_retain.xr_bucket[i] = NULL;
}
xo_retain_count = 0;
- xo_retain_hits = 0;
}
/*
@@ -1512,7 +1442,6 @@ xo_retain_find (const char *fmt, xo_field_info_t **valp, unsigned *nump)
*valp = xrep->xre_fields;
*nump = xrep->xre_num_fields;
xrep->xre_hits += 1;
- xo_retain_hits += 1;
return 0;
}
}
@@ -1547,12 +1476,6 @@ xo_retain_add (const char *fmt, xo_field_info_t *fields, unsigned num_fields)
xo_retain_count += 1;
}
-unsigned long
-xo_retain_get_hits (void)
-{
- return xo_retain_hits;
-}
-
#endif /* !LIBXO_NO_RETAIN */
/*
@@ -2118,14 +2041,14 @@ xo_style_is_encoding (xo_handle_t *xop)
return 0;
}
-/* Simple name->value mapping */
-typedef struct xo_flag_mapping_s {
+/* Simple name-value mapping */
+typedef struct xo_mapping_s {
xo_xff_flags_t xm_value; /* Flag value */
const char *xm_name; /* String name */
-} xo_flag_mapping_t;
+} xo_mapping_t;
static xo_xff_flags_t
-xo_name_lookup (xo_flag_mapping_t *map, const char *value, ssize_t len)
+xo_name_lookup (xo_mapping_t *map, const char *value, ssize_t len)
{
if (len == 0)
return 0;
@@ -2153,7 +2076,7 @@ xo_name_lookup (xo_flag_mapping_t *map, const char *value, ssize_t len)
#ifdef NOT_NEEDED_YET
static const char *
-xo_value_lookup (xo_flag_mapping_t *map, xo_xff_flags_t value)
+xo_value_lookup (xo_mapping_t *map, xo_xff_flags_t value)
{
if (value == 0)
return NULL;
@@ -2166,7 +2089,7 @@ xo_value_lookup (xo_flag_mapping_t *map, xo_xff_flags_t value)
}
#endif /* NOT_NEEDED_YET */
-static xo_flag_mapping_t xo_xof_names[] = {
+static xo_mapping_t xo_xof_names[] = {
{ XOF_COLOR_ALLOWED, "color" },
{ XOF_COLOR, "color-force" },
{ XOF_COLUMNS, "columns" },
@@ -2187,7 +2110,6 @@ static xo_flag_mapping_t xo_xof_names[] = {
{ XOF_RETAIN_ALL, "retain" },
{ XOF_UNDERSCORES, "underscores" },
{ XOF_UNITS, "units" },
- { XOF_UTF8, "utf8" },
{ XOF_WARN, "warn" },
{ XOF_WARN_XML, "warn-xml" },
{ XOF_XPATH, "xpath" },
@@ -2195,7 +2117,7 @@ static xo_flag_mapping_t xo_xof_names[] = {
};
/* Options available via the environment variable ($LIBXO_OPTIONS) */
-static xo_flag_mapping_t xo_xof_simple_names[] = {
+static xo_mapping_t xo_xof_simple_names[] = {
{ XOF_COLOR_ALLOWED, "color" },
{ XOF_FLUSH, "flush" },
{ XOF_FLUSH_LINE, "flush-line" },
@@ -2339,7 +2261,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input)
int
xo_set_options (xo_handle_t *xop, const char *input)
{
- char *cp, *ep, *vp, *np, *bp, *zp;
+ char *cp, *ep, *vp, *np, *bp;
int style = -1, new_style, rc = 0;
ssize_t len;
xo_xof_flags_t new_flag;
@@ -2468,11 +2390,7 @@ xo_set_options (xo_handle_t *xop, const char *input)
continue;
}
- /* We allow either '=' or ':' to separate the keyword from the value */
vp = strchr(cp, '=');
- zp = strchr(cp, ':');
- if (zp != NULL && (vp == NULL || zp < vp))
- vp = zp;
if (vp)
*vp++ = '\0';
@@ -2511,24 +2429,6 @@ xo_set_options (xo_handle_t *xop, const char *input)
xo_warnx("error initializing encoder: %s", vp);
}
- } else if (xo_streq(cp, "map")) {
- if (vp == NULL)
- xo_failure(xop, "missing value for map option");
- else {
- rc = xo_map_option(xop, vp);
- if (rc)
- xo_warnx("error initializing map: '%s'", vp);
- }
-
- } else if (xo_streq(cp, "map-file")) {
- if (vp == NULL)
- xo_failure(xop, "missing value for map-file option");
- else {
- rc = xo_map_add_file(xop, vp);
- if (rc)
- xo_warnx("error initializing map-file: '%s'", vp);
- }
-
} else {
xo_warnx("unknown libxo option value: '%s'", cp);
rc = -1;
@@ -2807,30 +2707,6 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
if (len > 0 && !xo_buf_has_room(xbp, len))
return 0;
-#if 0
- /*
- * If we have the "right" encoding for text, then our job is
- * simpler. We can skim over the string and process it quickly.
- */
- if (cp && xo_is_text_utf8(xop) && need_enc == have_enc) {
- const char *np, *ep;
- for (np = cp, ep = cp + len; np < ep; np++)
- if (xo_is_utf8(*np) || *np == '\\' || *np == '%'
- || *np == '{' || *np == '}')
- break;
-
- /* If we found no non-ascii characters, we're golden */
- if (np == ep) {
- if (!xo_buf_has_room(xbp, len))
- return -1;
-
- memcpy(xbp->xb_curp, cp, len);
- xbp->xb_curp += len;
- return len; /* Len is the number of columns */
- }
- }
-#endif
-
for (;;) {
if (len == 0)
break;
@@ -2858,13 +2734,6 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
break;
case XF_ENC_UTF8: /* UTF-8 */
- /* Optimize the simple case: this is a traditional ASCII c */
- if (0 < *cp && *cp <= 0x7F) {
- wc = (wchar_t) *cp++;
- ilen = 1;
- break;
- }
-
ilen = xo_utf8_to_wc_len(cp);
if (ilen < 0) {
xo_failure(xop, "invalid UTF-8 character: %02hhx", *cp);
@@ -2912,7 +2781,8 @@ xo_format_string_direct (xo_handle_t *xop, xo_buffer_t *xbp,
/*
* Find the width-in-columns of this character, which must be done
- * in wide characters, since we lack a mbswidth() function.
+ * in wide characters, since we lack a mbswidth() function. If
+ * it doesn't fit
*/
width = xo_wcwidth(wc);
if (width < 0)
@@ -3020,7 +2890,7 @@ xo_needed_encoding (xo_handle_t *xop)
if (XOF_ISSET(xop, XOF_UTF8)) /* Check the override flag */
return XF_ENC_UTF8;
- if (xo_style(xop) == XO_STYLE_TEXT) /* Text defaults to locale */
+ if (xo_style(xop) == XO_STYLE_TEXT) /* Text means locale */
return XF_ENC_LOCALE;
return XF_ENC_UTF8; /* Otherwise, we love UTF-8 */
@@ -3511,7 +3381,7 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp,
* we want to ignore
*/
if (!XOF_ISSET(xop, XOF_NO_VA_ARG))
- (void) va_arg(xop->xo_vap, int);
+ va_arg(xop->xo_vap, int);
}
}
}
@@ -4408,226 +4278,6 @@ xo_arg (xo_handle_t *xop)
}
#endif /* 0 */
-/*
- * We want to allow mapping from one "name" to another replacement
- * name, like "df --libxo mapfile=df.map", so we can change the
- * vocabulary as needed. This means maintaining an array of old and
- * new names, along with the memory for the strings themselves. We
- * want this to be specific to the handle, so when the user requests a
- * map, we don't break other users of libxo. We'll need two fields in
- * the handle, one for the array, and one for the string buffer.
- */
-#ifdef LIBXO_NEED_MAP
-static int
-xo_map_find (xo_handle_t *xop, const char *name, size_t len)
-{
- for (int i = 0; i < xop->xo_map_len; i += 2) {
- if (strncmp(xop->xo_map[i], name, len) == 0)
- return i;
- }
-
- return -1;
-}
-
-/*
- * Is the path something we can find in $XO_MAPDIR? The current test
- * is simple: lack of '/'.
- */
-static int
-xo_is_shareable_filename (const char *path)
-{
- return strchr(path, '/') == NULL;
-}
-
-#endif /* LIBXO_NEED_MAP */
-
-/*
- * Find the replacement string for a tag, or return the tag itself
- */
-static inline const char *
-xo_map_name (xo_handle_t *xop UNUSED, const char *name)
-{
-#ifdef LIBXO_NEED_MAP
- if (name == NULL)
- return NULL;
-
- size_t len = strlen(name);
- for (int i = 0; i < xop->xo_map_len; i += 2) {
- if (strncmp(xop->xo_map[i], name, len) == 0)
- return xop->xo_map[i + 1];
- }
-#endif /* LIBXO_NEED_MAP */
-
- return name;
-}
-
-/*
- * Add a mapping from one tag name to another. Both "from" and "to" are
- * UTF-8 strings.
- */
-int
-xo_map_add (xo_handle_t *xop UNUSED, const char *from UNUSED,
- size_t flen UNUSED, const char *to UNUSED, size_t tlen UNUSED)
-{
-#ifdef LIBXO_NEED_MAP
- xop = xo_default(xop);
-
- int val = xo_map_find(xop, from, flen);
- if (val >= 0) {
- /* We hit a "from" value that's already there; replace the "to" */
- char *newp = xo_buf_append_val(&xop->xo_map_data, to, tlen);
- if (newp == NULL)
- return -1;
-
- /* NUL terminate the string */
- if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
- return -1;
-
- xop->xo_map[val + 1] = newp;
-
- return 0;
- }
-
- if (xop->xo_map_len >= xop->xo_map_size) {
- char **newp = xo_realloc(xop->xo_map, xop->xo_map_size + XO_MAP_INCR);
- if (newp == NULL)
- return -1;
- xop->xo_map = newp;
- xop->xo_map_size += XO_MAP_INCR;
- }
-
- char *new_from = xo_buf_append_val(&xop->xo_map_data, from, flen);
- if (new_from == NULL)
- return -1;
-
- /* NUL terminate the new string */
- if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
- return -1;
-
- char *new_to = xo_buf_append_val(&xop->xo_map_data, to, tlen);
- if (new_to == NULL)
- return -1;
-
- /* NUL terminate the new string */
- if (!xo_buf_append_val(&xop->xo_map_data, "", 1))
- return -1;
-
- val = xop->xo_map_len; /* Use next slot */
-
- xop->xo_map[val] = new_from;
- xop->xo_map[val + 1] = new_to;
-
- xop->xo_map_len += 2; /* Consume the slot */
-#endif /* LIBXO_NEED_MAP */
-
- return 0;
-}
-
-static int
-xo_map_option (xo_handle_t *xop, const char *opts)
-{
- const char *cp, *np, *vp, *ep;
- size_t nlen, vlen;
-
- for (np = opts; *np; np = ep) {
- cp = strchr(np, '=');
- if (cp == NULL)
- break;
-
- nlen = cp - np;
-
- vp = cp + 1; /* Skip '=' */
- ep = strchr(vp, ':');
- vlen = ep ? ep - vp : strlen(vp);
-
- if (xo_map_add(xop, np, nlen, vp, vlen))
- return -1;
-
- if (ep == NULL)
- break;
- ep += 1; /* Skip ':' */
- }
-
- return 0;
-}
-
-/*
- * Add a file of tag maps, with the format:
- * # example comment
- * old-tag=new-tag
- * ancient=new-hotness
- * The file should be UTF-8.
- */
-int
-xo_map_add_file (xo_handle_t *xop UNUSED, const char *fname UNUSED)
-{
-#ifdef LIBXO_NEED_MAP
- const char bom0 = 0xEF, bom1 = 0xBB, bom2 = 0xBF;
-
- char buf[BUFSIZ], *np, *cp, *ep, *vp;
- int first = TRUE;
-
- xop = xo_default(xop);
-
- FILE *fp = fopen(fname, "r");
- if (fp == NULL) {
- if (!xo_is_shareable_filename(fname))
- return -1;
-
- static const char dir[] = XO_MAPDIR;
- size_t dlen = sizeof(dir) - 1;
- size_t flen = strlen(fname);
- char *new_path = alloca(dlen + 1 + flen + 1);
- memcpy(new_path, dir, dlen);
- new_path[dlen] = '/';
- memcpy(new_path + dlen + 1, fname, flen);
- new_path[dlen + 1 + flen] = '\0';
-
- fp = fopen(new_path, "r");
- if (fp == NULL)
- return -1;
- }
-
- for (;;) {
- if (fgets(buf, sizeof(buf), fp) == NULL)
- break;
-
- /*
- * The UTF-8 file can start with a "BOM":
- * https://en.wikipedia.org/wiki/Byte_order_mark
- * So if we see this at the start of the file, we need to skip
- * over it.
- */
- cp = buf;
- if (first && buf[0] == bom0 && buf[1] == bom1 && buf[2] == bom2)
- cp += 3;
- first = FALSE;
-
- /* Skip to the start of the name (the "from") */
- np = cp + strspn(cp, " \t\r\n");
- if (*np == '#')
- continue;
-
- /* Skip to the "=" */
- cp = np + strcspn(np, " \t\r\n=");
- if (cp == np)
- continue;
-
- /* Find the start and the end of the value (the "to") */
- vp = cp + 1 + strspn(cp + 1, " \t\r\n=");
- ep = vp + strcspn(vp, " \t\r\n;");
- if (ep == vp)
- continue;
-
- (void) xo_map_add(xop, np, cp - np, vp, ep - vp);
- }
-
- fclose(fp);
-#endif /* LIBXO_NEED_MAP */
-
- return 0;
-}
-
static void
xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
const char *value, ssize_t vlen,
@@ -4709,20 +4359,6 @@ xo_format_value (xo_handle_t *xop, const char *name, ssize_t nlen,
xo_buffer_t *xbp = &xop->xo_data;
xo_humanize_save_t save; /* Save values for humanizing logic */
- if (name) {
- /*
- * We have a name, but need to see if it's been remapped
- * to a different name. To look up the tag name, we need
- * to make a local copy and NUL terminate it.
- */
- char *new_name = alloca(nlen + 1);
- memcpy(new_name, name, nlen);
- new_name[nlen] = '\0';
-
- name = xo_map_name(xop, new_name);
- nlen = strlen(name); /* Need new length for new name */
- }
-
const char *leader = xo_xml_leader_len(xop, name, nlen);
switch (xo_style(xop)) {
@@ -5715,7 +5351,7 @@ xo_role_wants_default_format (int ftype)
return 1;
}
-static xo_flag_mapping_t xo_role_names[] = {
+static xo_mapping_t xo_role_names[] = {
{ 'C', "color" },
{ 'D', "decoration" },
{ 'E', "error" },
@@ -5735,7 +5371,7 @@ static xo_flag_mapping_t xo_role_names[] = {
#define XO_ROLE_TEXT '+'
#define XO_ROLE_NEWLINE '\n'
-static xo_flag_mapping_t xo_modifier_names[] = {
+static xo_mapping_t xo_modifier_names[] = {
{ XFF_ARGUMENT, "argument" },
{ XFF_COLON, "colon" },
{ XFF_COMMA, "comma" },
@@ -5761,7 +5397,7 @@ static xo_flag_mapping_t xo_modifier_names[] = {
};
#ifdef NOT_NEEDED_YET
-static xo_flag_mapping_t xo_modifier_short_names[] = {
+static xo_mapping_t xo_modifier_short_names[] = {
{ XFF_COLON, "c" },
{ XFF_DISPLAY_ONLY, "d" },
{ XFF_ENCODE_ONLY, "e" },
@@ -5778,10 +5414,6 @@ static xo_flag_mapping_t xo_modifier_short_names[] = {
};
#endif /* NOT_NEEDED_YET */
-/*
- * This is not really a count, more like a quick-but-pessimisstic number,
- * rounded up to an even more pessimisstic number, plus one.
- */
static int
xo_count_fields (xo_handle_t *xop UNUSED, const char *fmt)
{
@@ -6888,32 +6520,15 @@ xo_do_emit (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt)
xo_field_info_t *fields = NULL;
/* Adjust XOEF_RETAIN based on global flags */
- if (flags & XOEF_NO_RETAIN) {
- /* If the "don't retain flag is on, remove the retain, just in case */
- flags &= ~XOEF_RETAIN;
-
- } else if (flags & XOEF_RETAIN) {
- /* If the user doesn't want to retain, even if the caller does */
- if (XOF_ISSET(xop, XOF_RETAIN_NONE))
- flags &= ~XOEF_RETAIN;
- } else if (!xo_str_is_const(fmt)) {
- /*
- * Unless the caller explicitly tells us otherwise, we can
- * only retain (cache) const strings, since dynamic strings
- * aren't cachable due to changing content.
- */
- /* Do nothing */
- } else if (XOF_ISSET(xop, XOF_RETAIN_ALL)) {
- /* If the user wants to retain allow it */
+ if (XOF_ISSET(xop, XOF_RETAIN_ALL))
flags |= XOEF_RETAIN;
- }
+ if (XOF_ISSET(xop, XOF_RETAIN_NONE))
+ flags &= ~XOEF_RETAIN;
/*
* Check for 'retain' flag, telling us to retain the field
* information. If we've already saved it, then we can avoid
* re-parsing the format string.
- * Dynamically build formats must tell us that the format is
- * dynamic using the XOEF_NO_RETAIN flag.
*/
if (!(flags & XOEF_RETAIN)
|| xo_retain_find(fmt, &fields, &max_fields) != 0
@@ -7012,20 +6627,6 @@ xo_emit (const char *fmt, ...)
}
xo_ssize_t
-xo_emitr (const char *fmt, ...)
-{
- xo_handle_t *xop = xo_default(NULL);
- ssize_t rc;
-
- va_start(xop->xo_vap, fmt);
- rc = xo_do_emit(xop, XOEF_RETAIN, fmt);
- va_end(xop->xo_vap);
- bzero(&xop->xo_vap, sizeof(xop->xo_vap));
-
- return rc;
-}
-
-xo_ssize_t
xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
const char *fmt, va_list vap)
{
@@ -7075,10 +6676,9 @@ xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...)
* descriptions.
*/
xo_ssize_t
-xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags UNUSED,
- const char *rolmod, const char *contents,
- const char *fmt, const char *efmt,
- va_list vap)
+xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
+ const char *fmt, const char *efmt,
+ va_list vap)
{
ssize_t rc;
@@ -7121,14 +6721,6 @@ xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags UNUSED,
}
xo_ssize_t
-xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
- const char *fmt, const char *efmt,
- va_list vap)
-{
- return xo_emit_field_hvf(xop, 0, rolmod, contents, fmt, efmt, vap);
-}
-
-xo_ssize_t
xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
const char *fmt, const char *efmt, ...)
{
@@ -7136,24 +6728,7 @@ xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
va_list vap;
va_start(vap, efmt);
- rc = xo_emit_field_hvf(xop, 0, rolmod, contents, fmt, efmt, vap);
- va_end(vap);
-
- return rc;
-}
-
-xo_ssize_t
-xo_emit_field_f (xo_emit_flags_t flags, const char *rolmod,
- const char *contents,
- const char *fmt, const char *efmt, ...)
-{
- xo_handle_t *xop = xo_default(NULL);
-
- ssize_t rc;
- va_list vap;
-
- va_start(vap, efmt);
- rc = xo_emit_field_hvf(xop, flags, rolmod, contents, fmt, efmt, vap);
+ rc = xo_emit_field_hv(xop, rolmod, contents, fmt, efmt, vap);
va_end(vap);
return rc;
@@ -7167,7 +6742,7 @@ xo_emit_field (const char *rolmod, const char *contents,
va_list vap;
va_start(vap, efmt);
- rc = xo_emit_field_hvf(NULL, 0, rolmod, contents, fmt, efmt, vap);
+ rc = xo_emit_field_hv(NULL, rolmod, contents, fmt, efmt, vap);
va_end(vap);
return rc;
@@ -7376,8 +6951,6 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
name = XO_FAILURE_NAME;
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
const char *leader = xo_xml_leader(xop, name);
flags |= xop->xo_flags; /* Pick up handle flags */
@@ -7486,22 +7059,18 @@ xo_do_close_container (xo_handle_t *xop, const char *name)
char *cp = alloca(len);
memcpy(cp, name, len);
name = cp;
- } else {
- if (!(xsp->xs_flags & XSF_DTRT))
- xo_failure(xop, "missing name without 'dtrt' mode");
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
name = XO_FAILURE_NAME;
}
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
const char *leader = xo_xml_leader(xop, name);
switch (xo_style(xop)) {
case XO_STYLE_XML:
xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0);
- rc = xo_printf(xop, "%*s</%s%s>%s", xo_indent(xop),
- "", leader, name, ppn);
+ rc = xo_printf(xop, "%*s</%s%s>%s", xo_indent(xop), "", leader, name, ppn);
break;
case XO_STYLE_JSON:
@@ -7567,8 +7136,6 @@ xo_do_open_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
const char *pre_nl = "";
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
switch (xo_style(xop)) {
case XO_STYLE_JSON:
@@ -7662,15 +7229,12 @@ xo_do_close_list (xo_handle_t *xop, const char *name)
char *cp = alloca(len);
memcpy(cp, name, len);
name = cp;
- } else {
- if (!(xsp->xs_flags & XSF_DTRT))
- xo_failure(xop, "missing name without 'dtrt' mode");
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
name = XO_FAILURE_NAME;
}
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
switch (xo_style(xop)) {
case XO_STYLE_JSON:
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
@@ -7731,8 +7295,6 @@ xo_do_open_leaf_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
const char *ppn = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
const char *pre_nl = "";
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
switch (xo_style(xop)) {
case XO_STYLE_JSON:
indent = 1;
@@ -7786,15 +7348,12 @@ xo_do_close_leaf_list (xo_handle_t *xop, const char *name)
char *cp = alloca(len);
memcpy(cp, name, len);
name = cp;
- } else {
- if (!(xsp->xs_flags & XSF_DTRT))
- xo_failure(xop, "missing name without 'dtrt' mode");
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
name = XO_FAILURE_NAME;
}
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
switch (xo_style(xop)) {
case XO_STYLE_JSON:
if (xop->xo_stack[xop->xo_depth].xs_flags & XSF_NOT_FIRST)
@@ -7833,8 +7392,6 @@ xo_do_open_instance (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
name = XO_FAILURE_NAME;
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
const char *leader = xo_xml_leader(xop, name);
flags |= xop->xo_flags;
@@ -7925,15 +7482,12 @@ xo_do_close_instance (xo_handle_t *xop, const char *name)
char *cp = alloca(len);
memcpy(cp, name, len);
name = cp;
- } else {
- if (!(xsp->xs_flags & XSF_DTRT))
- xo_failure(xop, "missing name without 'dtrt' mode");
+ } else if (!(xsp->xs_flags & XSF_DTRT)) {
+ xo_failure(xop, "missing name without 'dtrt' mode");
name = XO_FAILURE_NAME;
}
}
- name = xo_map_name(xop, name); /* Find mapped name, if any */
-
const char *leader = xo_xml_leader(xop, name);
switch (xo_style(xop)) {
@@ -8060,8 +7614,6 @@ xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state)
else
return 0; /* Unknown or useless new states are ignored */
- name = xo_map_name(xop, name);
-
for (xsp = &xop->xo_stack[xop->xo_depth]; xsp > xop->xo_stack; xsp--) {
/*
* Marker's normally stop us from going any further, unless
diff --git a/libxo/xo.h b/libxo/xo.h
index eef70eb0dc05..6a61a16c7cae 100644
--- a/libxo/xo.h
+++ b/libxo/xo.h
@@ -106,7 +106,6 @@ typedef unsigned long long xo_xof_flags_t;
typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */
#define XOEF_RETAIN (1<<0) /* Retain parsed formatting information */
-#define XOEF_NO_RETAIN (1<<1) /* Format must not be retained (dynamic) */
/*
* The xo_info_t structure provides a mapping between names and
@@ -211,9 +210,6 @@ xo_ssize_t
xo_emit (const char *fmt, ...);
xo_ssize_t
-xo_emitr (const char *fmt, ...);
-
-xo_ssize_t
xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
const char *fmt, va_list vap);
@@ -685,12 +681,6 @@ xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
xo_simplify_field_func_t field_cb);
xo_ssize_t
-xo_emit_field_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
- const char *rolmod, const char *contents,
- const char *fmt, const char *efmt,
- va_list vap);
-
-xo_ssize_t
xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
const char *fmt, const char *efmt,
va_list vap);
@@ -700,11 +690,6 @@ xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
const char *fmt, const char *efmt, ...);
xo_ssize_t
-xo_emit_field_f (xo_emit_flags_t flags, const char *rolmod,
- const char *contents,
- const char *fmt, const char *efmt, ...);
-
-xo_ssize_t
xo_emit_field (const char *rolmod, const char *contents,
const char *fmt, const char *efmt, ...);
@@ -714,14 +699,4 @@ xo_retain_clear_all (void);
void
xo_retain_clear (const char *fmt);
-unsigned long
-xo_retain_get_hits (void);
-
-int
-xo_map_add (xo_handle_t *xop, const char *from, size_t flen,
- const char *to, size_t tlen);
-
-int
-xo_map_add_file (xo_handle_t *xop, const char *fname);
-
#endif /* INCLUDE_XO_H */
diff --git a/libxo/xo_buf.h b/libxo/xo_buf.h
index 56d1a546e0bc..c97f722959c5 100644
--- a/libxo/xo_buf.h
+++ b/libxo/xo_buf.h
@@ -135,49 +135,29 @@ xo_buf_has_room (xo_buffer_t *xbp, ssize_t len)
/*
* Append the given string to the given buffer
*/
-static inline char *
-xo_buf_append_val (xo_buffer_t *xbp, const char *str, ssize_t len)
+static inline void
+xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len)
{
if (str == NULL || len == 0 || !xo_buf_has_room(xbp, len))
- return NULL;
-
- char *val = xbp->xb_curp; /* The "new" value */
+ return;
memcpy(xbp->xb_curp, str, len);
xbp->xb_curp += len;
-
- return val;
-}
-
-static inline void
-xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len)
-{
- (void) xo_buf_append_val(xbp, str, len);
}
/*
* Append the given NUL-terminated string to the given buffer
*/
-static inline char *
-xo_buf_append_str_val (xo_buffer_t *xbp, const char *str)
+static inline void
+xo_buf_append_str (xo_buffer_t *xbp, const char *str)
{
ssize_t len = strlen(str);
if (!xo_buf_has_room(xbp, len))
- return NULL;
-
- char *val = xbp->xb_curp; /* The "new" value */
+ return;
memcpy(xbp->xb_curp, str, len);
xbp->xb_curp += len;
-
- return val;
-}
-
-static inline void
-xo_buf_append_str (xo_buffer_t *xbp, const char *str)
-{
- (void) xo_buf_append_str_val(xbp, str);
}
#endif /* XO_BUF_H */
diff --git a/libxo/xo_config.h.in b/libxo/xo_config.h.in
deleted file mode 100644
index 4456f3348c45..000000000000
--- a/libxo/xo_config.h.in
+++ /dev/null
@@ -1,254 +0,0 @@
-/* libxo/xo_config.h.in. Generated from configure.ac by autoheader. */
-
-/* Define to 1 if using 'alloca.c'. */
-#undef C_ALLOCA
-
-/* Define to 1 if you have 'alloca', as a function or macro. */
-#undef HAVE_ALLOCA
-
-/* Define to 1 if <alloca.h> works. */
-#undef HAVE_ALLOCA_H
-
-/* Define to 1 if you have the `asprintf' function. */
-#undef HAVE_ASPRINTF
-
-/* Define to 1 if you have the `bzero' function. */
-#undef HAVE_BZERO
-
-/* Define to 1 if you have the `ctime' function. */
-#undef HAVE_CTIME
-
-/* Define to 1 if you have the <ctype.h> header file. */
-#undef HAVE_CTYPE_H
-
-/* Define to 1 if you have the declaration of `__isthreaded', and to 0 if you
- don't. */
-#undef HAVE_DECL___ISTHREADED
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#undef HAVE_DLFCN_H
-
-/* Define to 1 if you have the `dlfunc' function. */
-#undef HAVE_DLFUNC
-
-/* Define to 1 if you have the <errno.h> header file. */
-#undef HAVE_ERRNO_H
-
-/* Style of etext */
-#undef HAVE_ETEXT
-
-/* Define to 1 if you have the `fdopen' function. */
-#undef HAVE_FDOPEN
-
-/* Define to 1 if you have the `flock' function. */
-#undef HAVE_FLOCK
-
-/* Using real gcc */
-#undef HAVE_GCC
-
-/* Define to 1 if you have the `getpass' function. */
-#undef HAVE_GETPASS
-
-/* Define to 1 if you have the `getprogname' function. */
-#undef HAVE_GETPROGNAME
-
-/* Define to 1 if you have the `getrusage' function. */
-#undef HAVE_GETRUSAGE
-
-/* gettext(3) */
-#undef HAVE_GETTEXT
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#undef HAVE_GETTIMEOFDAY
-
-/* humanize_number(3) */
-#undef HAVE_HUMANIZE_NUMBER
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#undef HAVE_INTTYPES_H
-
-/* Define to 1 if you have the `crypto' library (-lcrypto). */
-#undef HAVE_LIBCRYPTO
-
-/* Define to 1 if you have the `m' library (-lm). */
-#undef HAVE_LIBM
-
-/* Define to 1 if you have the <libutil.h> header file. */
-#undef HAVE_LIBUTIL_H
-
-/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
- to 0 otherwise. */
-#undef HAVE_MALLOC
-
-/* Define to 1 if you have the `memmove' function. */
-#undef HAVE_MEMMOVE
-
-/* Define to 1 if you have the <monitor.h> header file. */
-#undef HAVE_MONITOR_H
-
-/* Support printflike */
-#undef HAVE_PRINTFLIKE
-
-/* Define to 1 if your system has a GNU libc compatible `realloc' function,
- and to 0 otherwise. */
-#undef HAVE_REALLOC
-
-/* Define to 1 if you have the `srand' function. */
-#undef HAVE_SRAND
-
-/* Define to 1 if you have the `sranddev' function. */
-#undef HAVE_SRANDDEV
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#undef HAVE_STDINT_H
-
-/* Define to 1 if you have the <stdio_ext.h> header file. */
-#undef HAVE_STDIO_EXT_H
-
-/* Define to 1 if you have the <stdio.h> header file. */
-#undef HAVE_STDIO_H
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#undef HAVE_STDLIB_H
-
-/* Define to 1 if you have the <stdtime/tzfile.h> header file. */
-#undef HAVE_STDTIME_TZFILE_H
-
-/* Define to 1 if you have the `strchr' function. */
-#undef HAVE_STRCHR
-
-/* Define to 1 if you have the `strcspn' function. */
-#undef HAVE_STRCSPN
-
-/* Define to 1 if you have the `strerror' function. */
-#undef HAVE_STRERROR
-
-/* Define to 1 if you have the <strings.h> header file. */
-#undef HAVE_STRINGS_H
-
-/* Define to 1 if you have the <string.h> header file. */
-#undef HAVE_STRING_H
-
-/* Define to 1 if you have the `strlcpy' function. */
-#undef HAVE_STRLCPY
-
-/* Define to 1 if you have the `strspn' function. */
-#undef HAVE_STRSPN
-
-/* Have struct sockaddr_un.sun_len */
-#undef HAVE_SUN_LEN
-
-/* Define to 1 if you have the `sysctlbyname' function. */
-#undef HAVE_SYSCTLBYNAME
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#undef HAVE_SYS_PARAM_H
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#undef HAVE_SYS_STAT_H
-
-/* Define to 1 if you have the <sys/sysctl.h> header file. */
-#undef HAVE_SYS_SYSCTL_H
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#undef HAVE_SYS_TIME_H
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#undef HAVE_SYS_TYPES_H
-
-/* Define to 1 if you have the <threads.h> header file. */
-#undef HAVE_THREADS_H
-
-/* thread-local setting */
-#undef HAVE_THREAD_LOCAL
-
-/* Define to 1 if you have the <tzfile.h> header file. */
-#undef HAVE_TZFILE_H
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#undef HAVE_UNISTD_H
-
-/* Define to 1 if you have the `__flbf' function. */
-#undef HAVE___FLBF
-
-/* Enable debugging */
-#undef LIBXO_DEBUG
-
-/* Enable text-only rendering */
-#undef LIBXO_TEXT_ONLY
-
-/* Version number as dotted value */
-#undef LIBXO_VERSION
-
-/* Version number extra information */
-#undef LIBXO_VERSION_EXTRA
-
-/* Version number as a number */
-#undef LIBXO_VERSION_NUMBER
-
-/* Version number as string */
-#undef LIBXO_VERSION_STRING
-
-/* Enable local wcwidth implementation */
-#undef LIBXO_WCWIDTH
-
-/* Define to the sub-directory where libtool stores uninstalled libraries. */
-#undef LT_OBJDIR
-
-/* Name of package */
-#undef PACKAGE
-
-/* Define to the address where bug reports for this package should be sent. */
-#undef PACKAGE_BUGREPORT
-
-/* Define to the full name of this package. */
-#undef PACKAGE_NAME
-
-/* Define to the full name and version of this package. */
-#undef PACKAGE_STRING
-
-/* Define to the one symbol short name of this package. */
-#undef PACKAGE_TARNAME
-
-/* Define to the home page for this package. */
-#undef PACKAGE_URL
-
-/* Define to the version of this package. */
-#undef PACKAGE_VERSION
-
-/* If using the C implementation of alloca, define if you know the
- direction of stack growth for your system; otherwise it will be
- automatically deduced at runtime.
- STACK_DIRECTION > 0 => grows toward higher addresses
- STACK_DIRECTION < 0 => grows toward lower addresses
- STACK_DIRECTION = 0 => direction of growth unknown */
-#undef STACK_DIRECTION
-
-/* Define to 1 if all of the C90 standard headers exist (not just the ones
- required in a freestanding environment). This macro is provided for
- backward compatibility; new code need not use it. */
-#undef STDC_HEADERS
-
-/* Use int return codes */
-#undef USE_INT_RETURN_CODES
-
-/* Version number of package */
-#undef VERSION
-
-/* Retain hash bucket size */
-#undef XO_RETAIN_SIZE
-
-/* Define to `__inline__' or `__inline' if that's what the C compiler
- calls it, or to nothing if 'inline' is not supported under any name. */
-#ifndef __cplusplus
-#undef inline
-#endif
-
-/* Define to rpl_malloc if the replacement function should be used. */
-#undef malloc
-
-/* Define to rpl_realloc if the replacement function should be used. */
-#undef realloc
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-#undef size_t
diff --git a/libxo/xo_emit.3 b/libxo/xo_emit.3
index e77ca00581d9..cbf9d2b11eb4 100644
--- a/libxo/xo_emit.3
+++ b/libxo/xo_emit.3
@@ -23,8 +23,6 @@
.Fn xo_emit_h "xo_handle_t *xop" "const char *fmt" "..."
.Ft xo_ssize_t
.Fn xo_emit_hv "xo_handle_t *xop" "const char *fmt" "va_list vap"
-.Ft xo_ssize_t
-.Fn xo_emitr "const char *fmt" "..."
.Sh DESCRIPTION
The
.Fn xo_emit
@@ -92,33 +90,6 @@ the "--libxo" option:
<div class="data" data-tag="filename">/etc/motd</div>
</div>
.Ed
-.Sh Retaining Formatting Information for Constant Strings
-.Pp
-The
-.Nm libxo
-library can cache the compiled internal version of the format for
-circumstances when the format will be used repeatedly, such as a loop.
-This cannot be used when the format string is in a dynamic buffer,
-since the cache retains a reference to the static format string,
-typically a static compile-time constant value.
-.Pp
-Typically static strings are placed in an executable's ".text" segment,
-so
-.Nm libxo
-knows that the formatting information in such static strings can be
-cached (retained), but shared libraries will have their own ".text"
-segment, so without the XOEF_RETAIN flag,
-.Nm libxo
-cannot presume to retain formatting information.
-If a caller in shared library code want their formats retained, they
-need to pass the XOEF_RETAIN flag.
-.Pp
-The
-.Fn xo_emitr
-function is a convenience function that passes the XOEF_RETAIN
-flag to
-.Fn xo_emit_hvf ,
-and can be used in shared libraries when the format string is static.
.Sh RETURN CODE
.Nm
returns a negative value on error. If the
diff --git a/libxo/xo_emit_f.3 b/libxo/xo_emit_f.3
new file mode 100644
index 000000000000..f8ac013256a8
--- /dev/null
+++ b/libxo/xo_emit_f.3
@@ -0,0 +1,121 @@
+.\" #
+.\" # Copyright (c) 2016, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, April 2016
+.\"
+.Dd April 15, 2016
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_emit_f , xo_emit_hf , xo_emit_hvf
+.Nd emit formatted output based on format string and arguments
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft xo_ssize_t
+.Fn xo_emit_f "xo_emit_flags_t flags" "const char *fmt" "..."
+.Ft xo_ssize_t
+.Fn xo_emit_hf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "..."
+.Ft xo_ssize_t
+.Fn xo_emit_hvf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "va_list vap"
+.Ft void
+.Fn xo_retain_clear_all "void"
+.Ft void
+.Fn xo_retain_clear "const char *fmt"
+.Sh DESCRIPTION
+These functions allow callers to pass a set of flags to
+.Nm
+emitting functions. These processing of arguments, except for
+.Fa flags ,
+is identical to the base functions.
+See
+.Xr xo_emit 3
+for additional information.
+.Pp
+The only currently defined flag is
+.Dv XOEF_RETAIN .
+.Nm
+can retain the parsed internal information related to the given
+format string, allowing subsequent
+.Xr xo_emit 3
+calls, the retained
+information is used, avoiding repetitive parsing of the format string.
+To retain parsed format information, use the
+.Dv XOEF_RETAIN
+flag to the
+.Fn xo_emit_f
+function.
+.Pp
+The format string must be immutable across multiple calls to
+.Xn xo_emit_f ,
+since the library retains the string.
+Typically this is done by using
+static constant strings, such as string literals. If the string is not
+immutable, the
+.Dv XOEF_RETAIN
+flag must not be used.
+.Pp
+The functions
+.Fn xo_retain_clear
+and
+.Fn xo_retain_clear_all
+release internal information on either a single format string or all
+format strings, respectively.
+Neither is required, but the library will
+retain this information until it is cleared or the process exits.
+.Pp
+The retained information is kept as thread-specific data.
+.Pp
+Use
+.Fn xo_retain_clear
+and
+.Fn xo_retain_clear_all
+to clear the retained information, clearing the retained information
+for either a specific format string or all format strings, respectively.
+These functions are only needed when the calling application wants to
+clear this information; they are not generally needed.
+.Sh EXAMPLES
+.Pp
+.Bd -literal -offset indent
+ for (i = 0; i < 1000; i++) {
+ xo_open_instance("item");
+ xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\\n",
+ name[i], count[i]);
+ }
+.Ed
+.Pp
+In this example, the caller desires to clear the retained information.
+.Bd -literal -offset indent
+ const char *fmt = "{:name} {:count/%d}\\n";
+ for (i = 0; i < 1000; i++) {
+ xo_open_instance("item");
+ xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
+ }
+ xo_retain_clear(fmt);
+.Ed
+.Sh RETURN CODE
+The return values for these functions is identical to those of their
+traditional counterparts. See
+.Xr xo_emit 3
+for details.
+.Sh SEE ALSO
+.Xr xo_emit 3 ,
+.Xr xo_open_container 3 ,
+.Xr xo_open_list 3 ,
+.Xr xo_format 5 ,
+.Xr libxo 3
+.Sh HISTORY
+The
+.Nm libxo
+library first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.Nm libxo
+was written by
+.An Phil Shafer Aq Mt phil@freebsd.org .
+
diff --git a/libxo/xo_emit_field.3 b/libxo/xo_emit_field.3
new file mode 100644
index 000000000000..4f9636cee8e7
--- /dev/null
+++ b/libxo/xo_emit_field.3
@@ -0,0 +1,113 @@
+.\" #
+.\" # Copyright (c) 2021, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd December 4, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo_emit_field
+.Nd emit formatted output based on format string and arguments
+.Sh LIBRARY
+.Lb libxo
+.Sh SYNOPSIS
+.In libxo/xo.h
+.Ft xo_ssize_t
+.Fn xo_emit_field "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "..."
+.Ft xo_ssize_t
+.Fn xo_emit_field_h "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" const char *efmt" "..."
+.Ft xo_ssize_t
+.Fn xo_emit_field_hv "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "va_list vap"
+.Sh DESCRIPTION
+The
+.Fn xo_emit_field
+function emits formatted output similar to
+.Xr xo_emit 3
+but where
+.Fn xo_emit
+uses a single string argument containing the description
+for multiple fields,
+.Fn xo_emit_field
+emits a single field using multiple arguments to contain the
+field description.
+.Fn xo_emit_field_h
+adds an explicit handle to use instead of the default
+handle, while
+.Fn xo_emit_field_hv
+accepts a
+.Fa va_list
+for additional flexibility.
+.Pp
+The arguments
+.Fa rolmod ,
+.Fa content ,
+.Fa fmt ,
+and
+.Fa efmt
+are detailed in
+.Xr xo_format 5 .
+Using distinct arguments allows callers to pass the field description
+in pieces, rather than having to use something like
+.Xr snprintf 3
+to build the format string required by
+.Fn xo_emit .
+The arguments are each NUL-terminated strings. The
+.Fa rolmod
+argument contains the "role" and "modifier" portions of
+the field description, the
+.Fa content
+argument contains the "content" portion, and the
+.Fa fmt
+and
+.Fa efmt
+contain the "field-format" and "encoding-format" portions, respectively.
+.Pp
+As with xo_emit, the
+.Fa fmt
+and
+.Fa efmt
+values are both optional, since the field-format string
+defaults to "%s", and the encoding-format's default value is
+derived from the field-format
+per
+.Xr xo_format 5 .
+However, care must be taken to avoid using a value directly as the
+format, since characters like '{', '%', and '}' will be interpreted
+as formatting directives, and may cause
+.Nm
+to dereference arbitrary values off the stack, leading to bugs,
+core files, and gnashing of teeth.
+.Sh EXAMPLES
+In this example, a set of four values is emitted using the following
+source code:
+.Bd -literal -offset indent
+ xo_emit_field("T", title, NULL, NULL, NULL);
+ xo_emit_field("Vt", "max-chaos", NULL, NULL, " very ");
+ xo_emit_field("V", "min-chaos", "%02d", "%d", 42);
+ xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
+ "gum", 1412);
+.Ed
+.Sh RETURN CODE
+.Nm
+returns a negative value on error. If the
+.Nm XOF_COLUMNS
+flag has been turned on for the specific handle using
+.Xr xo_set_flags 3 ,
+then the number of display columns consumed by the output will be returned.
+.Sh SEE ALSO
+.Xr xo_format 5 ,
+.Xr libxo 3
+.Sh HISTORY
+The
+.Nm libxo
+library first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.Nm libxo
+was written by
+.An Phil Shafer Aq Mt phil@freebsd.org .
diff --git a/libxo/xo_humanize.h b/libxo/xo_humanize.h
index ca41b8633669..edf85b8bb1ba 100644
--- a/libxo/xo_humanize.h
+++ b/libxo/xo_humanize.h
@@ -37,6 +37,8 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
+
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
diff --git a/libxo/xo_options.7 b/libxo/xo_options.7
index 485aa6b86050..297dcba92a41 100644
--- a/libxo/xo_options.7
+++ b/libxo/xo_options.7
@@ -50,8 +50,6 @@ The triggered functionality is identical.
.It "keys " "Emit the key attribute for keys (XML)"
.It "log\-gettext" "Log (via stderr) each gettext(3) string lookup"
.It "log\-syslog " "Log (via stderr) each syslog message (via xo_syslog)"
-.It "map " "Map between tag names"
-.It "map\-file " "Use a file to specify mapping between tag names"
.It "no\-humanize" "Ignore the {h:} modifier (TEXT, HTML)"
.It "no\-locale " "Do not initialize the locale setting"
.It "no\-retain " "Prevent retaining formatting information"
@@ -103,11 +101,6 @@ names that state with "data\-".
adds a "key" attribute for XML output to indicate that a leaf is
an identifier for the list member.
.Pp
-.Fa map
-and
-.Fa map\-file
-are described below.
-.Pp
.Fa no\-humanize
avoids "humanizing" numeric output (see
.Xr humanize_number 3
@@ -139,176 +132,6 @@ to emit warnings on stderr when application code make incorrect calls.
.Fa warn\-xml causes those warnings to be placed in
.Em XML
inside the output.
-.Sh Color Mapping
-The
-.Fa colors
-option takes a value that is a set of mappings from the
-pre-defined set of colors to new foreground and background colors.
-The value is a series of "fg/bg" values, separated by a "+".
-Each pair of "fg/bg" values gives the colors to which a basic color is
-mapped when used as a foreground or background color.
-The order is the mappings is:
-.Bd -literal -offset indent
-- black
-- red
-- green
-- yellow
-- blue
-- magenta
-- cyan
-- white
-.Ed
-.Pp
-Pairs may be skipped, leaving them mapped as normal, as are missing
-pairs or single colors.
-.Pp
-For example consider the following xo_emit call:
-.Bd -literal -offset indent
- xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n");
-.Ed
-.Pp
-To turn all colored output to red-on-blue, use eight pairs of
-"red/blue" mappings separated by plus signs ("+"):
-.Bd -literal -offset indent
- --libxo colors=red/blue+red/blue+red/blue+red/blue+\
- red/blue+red/blue+red/blue+red/blue
-.Ed
-.Pp
-To turn the red-on-green text to magenta-on-cyan, give a "magenta"
-foreground value for red (the second mapping) and a "cyan" background
-to green (the third mapping):
-.Bd -literal -offset indent
- --libxo colors=+magenta+/cyan
-.Ed
-.Pp
-Consider the common situation where blue output looks unreadable on a
-terminal session with a black background.
-To turn both "blue" foreground and background output to "yellow",
-give only the fifth mapping, skipping the first four mappings
-with bare plus signs ("+"):
-.Bd -literal -offset indent
- --libxo colors=++++yellow/yellow
-.Ed
-.Pp
-.Sh Tag Mapping
-.Nm libxo
-supports mapping between tag names, for scenarios where the tags
-need to make specific values.
-For example, the "user" tag might be
-needed as the "owner" tag.
-.Nm libxo
-can perform this one-to-one tag
-replacement.
-.Pp
-Note that
-.Nm libxo
-does not perform more complex transformations;
-languages such as XSLT or SLAX should be used when something more than
-simple one-to-one replacement is required.
-.Pp
-Mapping can be specified using the
-.Fa map
-and
-.Fa map-file options.
-The
-.Fa map
-option accepts one or more mapping, in the format "old=new",
-separated by colons:
-.Bd -literal -offset indent
- --libxo map:one=red,map:two=blue
-.Ed
-.Pp
-This example would turn:
-.Bd -literal -offset indent
- <one>fish</one>
- <two>fish</two>
-.Ed
-.Pp
-into:
-.Bd -literal -offset indent
- <red>fish</red>
- <blue>fish</blue>
-.Ed
-.Pp
-In another example, the command-line options:
-.Bd -literal -offset indent
- --libxo map:user=owner:name=file:size=bytes:modify-time=time
-.Ed
-.Pp
-would turn:
-.Bd -literal -offset indent
- <entry>
- <name>xx-00000009</name>
- <user>phil</user>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
-.Ed
-.Pp
-into:
-.Bd -literal -offset indent
- <entry>
- <file>xx-00000009</file>
- <owner>phil</owner>
- <bytes>12345</bytes>
- <time value="1644355825">1644355825</time>
- </entry>
-.Ed
-.Pp
-The
-.Fa map-file
-option allows the mappings to be placed into a file,
-one per line:
-.Bd -literal -offset indent
- --libxo map-file=foo.map
-.Ed
-.Pp
-where "foo.map" might contain:
-.Bd -literal -offset indent
- # comments are supported, white space is ignored
- user = owner
- name=file
- # blank lines are allowed
-
- size = bytes
- modify-time= time
-.Ed
-.Pp
-This untidy example demonstrates the flexibility in the
-.Nm libxo
-mapping files.
-.Pp
-If the filename given with the
-.Fa map-file
-option contains no slashes ("/") and such a file does not
-exist in the current working directory,
-.Nm libxo
-will look for the file in the "map" subdirectory of the system
-"share" directory, typically /usr/share/libxo/map/.
-.Sh Encoders
-In addition to the four "built-in" formats,
-.Nm libxo
-supports an extensible mechanism for adding encoders.
-These are activated using the
-.Fa encoder
-keyword::
-.Bd -literal -offset indent
- --libxo encoder=cbor
-.Ed
-.Pp
-The encoder can include encoder-specific options, separated by either
-colons (":") or plus signs ("+"):
-.Bd -literal -offset indent
- --libxo encoder=csv+path=filesystem+leaf=name+no-header
- --libxo encoder=csv:path=filesystem:leaf=name:no-header
-.Ed
-.Pp
-For brevity, the string "@" can be used in place of the string
-"encoder=".
-.Bd -literal -offset indent
- df --libxo @csv:no-header
-.Ed
-.Pp
.Sh EXAMPLES
The following are three example invocations of
.Xr ps 1 :
diff --git a/libxo/xo_syslog.c b/libxo/xo_syslog.c
index 959bc081a589..62da1811d0a5 100644
--- a/libxo/xo_syslog.c
+++ b/libxo/xo_syslog.c
@@ -38,6 +38,7 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syslog.h>
@@ -57,13 +58,9 @@
#include <stdarg.h>
#include <sys/time.h>
#include <sys/types.h>
-
-#include "xo_config.h"
-
-#ifdef HAVE_SYSCTLBYNAME
#include <sys/sysctl.h>
-#endif /* HAVE_SYSCTLBYNAME */
+#include "xo_config.h"
#include "xo.h"
#include "xo_encoder.h" /* For xo_realloc */
#include "xo_buf.h"
@@ -92,18 +89,18 @@
#if defined(__FreeBSD__)
#define XO_DEFAULT_EID 2238
-#elif defined(__APPLE__)
+#elif defined(__macosx__)
#define XO_DEFAULT_EID 63
#else
#define XO_DEFAULT_EID 32473 /* Fallback to the "example" number */
#endif
#ifndef HOST_NAME_MAX
-#ifdef _POSIX_HOST_NAME_MAX
-#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
+#ifdef _SC_HOST_NAME_MAX
+#define HOST_NAME_MAX _SC_HOST_NAME_MAX
#else
#define HOST_NAME_MAX 255
-#endif /* _POSIX_HOST_NAME_MAX */
+#endif /* _SC_HOST_NAME_MAX */
#endif /* HOST_NAME_MAX */
#ifndef UNUSED
@@ -587,13 +584,12 @@ xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)
* Add HOSTNAME; we rely on gethostname and don't fluff with
* ip addresses. Might need to revisit.....
*/
- char hostname[HOST_NAME_MAX + 1];
+ char hostname[HOST_NAME_MAX];
hostname[0] = '\0';
if (xo_unit_test)
strcpy(hostname, "worker-host");
else
- (void) gethostname(hostname, sizeof(hostname) - 1);
- hostname[HOST_NAME_MAX] = '\0'; /* Ensure NUL-terminated */
+ (void) gethostname(hostname, sizeof(hostname));
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
hostname[0] ? hostname : "-");
diff --git a/packaging/libxo.spec b/packaging/libxo.spec
deleted file mode 100644
index 2a30cbb851ce..000000000000
--- a/packaging/libxo.spec
+++ /dev/null
@@ -1,44 +0,0 @@
-Name: libxo
-Version: 1.6.0
-Release: 1%{?dist}
-Summary: The libxo library
-
-Prefix: /usr
-
-Vendor: Juniper Networks, Inc.
-Packager: Phil Shafer <phil@juniper.net>
-License: BSD
-
-Group: Development/Libraries
-URL: https://github.com/Juniper/libxo
-Source0: https://github.com/Juniper/libxo/releases/1.6.0/libxo-1.6.0.tar.gz
-
-
-%description
-Welcome to libxo, a library that generates text, XML, JSON, and HTML
-from a single source code path.
-
-%prep
-%setup -q
-
-%build
-%configure
-make %{?_smp_mflags}
-
-%install
-rm -rf $RPM_BUILD_ROOT
-%make_install
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%post -p /sbin/ldconfig
-
-%files
-%{_bindir}/*
-%{_includedir}/libxo/*
-%{_libdir}/*
-%{_datadir}/doc/libxo/*
-%docdir %{_datadir}/doc/libxo/*
-%{_mandir}/*/*
-%docdir %{_mandir}/*/*
diff --git a/tests/core/Makefile.am b/tests/core/Makefile.am
index c3b4200298fb..1e7010711757 100644
--- a/tests/core/Makefile.am
+++ b/tests/core/Makefile.am
@@ -23,8 +23,7 @@ test_08.c \
test_09.c \
test_10.c \
test_11.c \
-test_12.c \
-test_13.c
+test_12.c
test_01_test_SOURCES = test_01.c
test_02_test_SOURCES = test_02.c
@@ -38,7 +37,6 @@ test_09_test_SOURCES = test_09.c
test_10_test_SOURCES = test_10.c
test_11_test_SOURCES = test_11.c
test_12_test_SOURCES = test_12.c
-test_13_test_SOURCES = test_13.c
# TEST_CASES := $(shell cd ${srcdir} ; echo *.c )
@@ -98,7 +96,7 @@ TEST_JIG = \
TEST_JIG2 = \
echo "... $$test ... $$fmt ..."; \
-xoopts==warn,$$extra ; \
+xoopts==warn,$$csv ; \
${TEST_JIG}; true;
TEST_FORMATS = T XP JP JPu HP X J H HIPx
@@ -121,20 +119,15 @@ test tests: ${bin_PROGRAMS}
done) \
done)
-@ (${TEST_TRACE} test=test_01.c; base=test_01; \
- ( fmt=Ecsv1; extra=encoder=csv ; \
+ ( fmt=Ecsv1; csv=encoder=csv ; \
${TEST_JIG2} ); \
- ( fmt=Ecsv2; extra=encoder=csv:path=top-level/data/item:no-header ; \
+ ( fmt=Ecsv2; csv=encoder=csv:path=top-level/data/item:no-header ; \
${TEST_JIG2} ); \
- ( fmt=Ecsv3; extra=@csv:path=item:leafs=sku.sold:no-quotes ; \
- ${TEST_JIG2} ); \
- )
- -@ (${TEST_TRACE} test=test_12.c; base=test_12; \
- ( fmt=XPmap; extra=xml,pretty,map-file=${srcdir}/test_12.map ; \
- ${TEST_JIG2} ); \
- ( fmt=JPmap; extra=json,pretty,map-file=${srcdir}/test_12.map ; \
+ ( fmt=Ecsv3; csv=@csv:path=item:leafs=sku.sold:no-quotes ; \
${TEST_JIG2} ); \
)
+
one:
-@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
@@ -152,11 +145,6 @@ accept:
${CP} out/$$base.$$fmt.out ${srcdir}/saved/$$base.$$fmt.out ; \
${CP} out/$$base.$$fmt.err ${srcdir}/saved/$$base.$$fmt.err ; \
done)
- -@(test=test_01.c; base=test_12; for fmt in XPmap JPmap ; do \
- echo "... $$test ... $$fmt ..."; \
- ${CP} out/$$base.$$fmt.out ${srcdir}/saved/$$base.$$fmt.out ; \
- ${CP} out/$$base.$$fmt.err ${srcdir}/saved/$$base.$$fmt.err ; \
- done)
.c.test:
$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -o $@ $<
diff --git a/tests/core/saved/test_01.E.out b/tests/core/saved/test_01.E.out
index c3ee55c19702..506bfa83526f 100644
--- a/tests/core/saved/test_01.E.out
+++ b/tests/core/saved/test_01.E.out
@@ -24,7 +24,6 @@ op string: [some-chaos] [[42]] [0]
op attr: [test-attr] [attr-value] [0]
op open_leaf_list: [sku] [] [0]
op string: [sku] [gum-000-1412] [0x2010]
-op string: [sku] [sum-000-4121] [0x2010]
op close_leaf_list: [sku] [] [0]
op string: [host] [my-box] [0]
op string: [domain] [example.com] [0]
@@ -202,15 +201,6 @@ op content: [mode_octal] [640] [0x8]
op content: [links] [1] [0x1000]
op string: [user] [user] [0x1000]
op string: [group] [group] [0x1000]
-op content: [one] [1] [0]
-op content: [two] [2] [0]
-op content: [three] [3] [0]
-op content: [one] [1] [0]
-op content: [two] [2] [0]
-op content: [three] [3] [0]
-op content: [one] [1] [0]
-op content: [two] [2] [0]
-op content: [three] [3] [0]
op close_container: [top-level] [] [0]
op finish: [] [] [0]
op flush: [] [] [0]
diff --git a/tests/core/saved/test_01.H.out b/tests/core/saved/test_01.H.out
index 4bfec006c956..b58816d8617f 100644
--- a/tests/core/saved/test_01.H.out
+++ b/tests/core/saved/test_01.H.out
@@ -1,3 +1,3 @@
<div class="line"><div class="text">static </div><div class="data" data-tag="type">ethernet</div><div class="text"> </div><div class="data" data-tag="type">bridge</div><div class="text"> </div><div class="data" data-tag="type"> 18u</div><div class="text"> </div><div class="data" data-tag="type"> 24</div><div class="text">anchor </div><div class="padding"> </div><div class="data" data-tag="address">0x0</div><div class="text">..</div><div class="data" data-tag="port">1</div></div><div class="line"><div class="text">anchor </div><div class="padding"> </div><div class="data" data-tag="address">0x0</div><div class="text">..</div><div class="data" data-tag="port">1</div></div><div class="line"><div class="text">anchor </div><div class="padding"> </div><div class="data" data-tag="address">0x0</div><div class="text">..</div><div class="data" data-tag="port">1</div></div><div class="line"><div class="text">df </div><div class="data" data-tag="used-percent"> 12</div><div class="units">%</div></div><div class="line"><div class="text">testing argument modifier </div><div class="data" data-tag="host">my-box</div><div class="text">.</div><div class="data" data-tag="domain">example.com</div><div class="text">...</div></div><div class="line"><div class="text">testing argument modifier with encoding to </div><div class="text">.</div><div class="data" data-tag="domain">example.com</div><div class="text">...</div></div><div class="line"><div class="label">Label text</div><div class="text"> </div><div class="data" data-tag="label">value</div></div><div class="line"><div class="title">My Title
</div><div class="data" data-tag="max-chaos"> very </div><div class="data" data-tag="min-chaos">42</div><div class="data" data-tag="some-chaos">42
-</div><div class="data" data-tag="sku">gum-1412</div><div class="data" data-tag="sku">sum-4121</div><div class="text">Connecting to </div><div class="data" data-tag="host">my-box</div><div class="text">.</div><div class="data" data-tag="domain">example.com</div><div class="text">...</div></div><div class="line"><div class="title">Item </div><div class="title"> Total Sold</div><div class="title"> In Stock</div><div class="title"> On Order</div><div class="title"> SKU</div></div><div class="line"><div class="data" data-tag="name" data-key="key">gum </div><div class="data" data-tag="sold"> 1412</div><div class="data" data-tag="in-stock"> 54</div><div class="data" data-tag="on-order"> 10</div><div class="data" data-tag="sku" data-key="key"> GRO-000-415</div></div><div class="line"><div class="data" data-tag="name" data-key="key">rope </div><div class="data" data-tag="sold"> 85</div><div class="data" data-tag="in-stock"> 4</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> HRD-000-212</div></div><div class="line"><div class="data" data-tag="name" data-key="key">ladder </div><div class="data" data-tag="sold"> 0</div><div class="data" data-tag="in-stock"> 2</div><div class="data" data-tag="on-order"> 1</div><div class="data" data-tag="sku" data-key="key"> HRD-000-517</div></div><div class="line"><div class="data" data-tag="name" data-key="key">bolt </div><div class="data" data-tag="sold"> 4123</div><div class="data" data-tag="in-stock"> 144</div><div class="data" data-tag="on-order"> 42</div><div class="data" data-tag="sku" data-key="key"> HRD-000-632</div></div><div class="line"><div class="data" data-tag="name" data-key="key">water </div><div class="data" data-tag="sold"> 17</div><div class="data" data-tag="in-stock"> 14</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div></div><div class="line"></div><div class="line"></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">gum</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">1412.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">54</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">10</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-415</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">rope</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">85.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">4</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-212</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">ladder</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">2</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-517</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">bolt</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">4123.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">144</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">42</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-632</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">water</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">17.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">14</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-2331</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">fish</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">1321.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">45</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-533</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">gum</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">rope</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">ladder</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">bolt</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">water</div></div><div class="line"><div class="title">Item </div><div class="title"> Total Sold</div><div class="title"> In Stock</div><div class="title"> On Order</div><div class="title"> SKU</div></div><div class="line"><div class="data" data-tag="name" data-key="key">gum </div><div class="data" data-tag="sold"> 1412</div><div class="data" data-tag="on-order"> 10</div><div class="data" data-tag="in-stock"> 54</div><div class="data" data-tag="sku" data-key="key"> GRO-000-415</div></div><div class="line"><div class="data" data-tag="name" data-key="key">rope </div><div class="data" data-tag="sold"> 85</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="in-stock"> 4</div><div class="data" data-tag="sku" data-key="key"> HRD-000-212</div></div><div class="line"><div class="data" data-tag="name" data-key="key">ladder </div><div class="data" data-tag="sold"> 0</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 1</div><div class="data" data-tag="in-stock"> 2</div><div class="data" data-tag="sku" data-key="key"> HRD-000-517</div></div><div class="line"><div class="data" data-tag="name" data-key="key">bolt </div><div class="data" data-tag="sold"> 4123</div><div class="data" data-tag="on-order"> 42</div><div class="data" data-tag="in-stock"> 144</div><div class="data" data-tag="sku" data-key="key"> HRD-000-632</div></div><div class="line"><div class="data" data-tag="name" data-key="key">water </div><div class="data" data-tag="sold"> 17</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="in-stock"> 14</div><div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div></div><div class="line"></div><div class="line"></div><div class="line"><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">425</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">455</div></div><div class="line"><div class="text"> </div><div class="data" data-tag="links">links</div><div class="text"> </div><div class="data" data-tag="user">user</div><div class="text"> </div><div class="data" data-tag="group">group</div><div class="text"> </div></div><div class="line"><div class="data" data-tag="links">3 </div><div class="data" data-tag="post">this </div></div><div class="line"><div class="data" data-tag="mode">/some/file</div><div class="text"> </div><div class="data" data-tag="links"> 1</div><div class="text"> </div><div class="data" data-tag="user">user </div><div class="text"> </div><div class="data" data-tag="group">group </div><div class="text"> </div></div><div class="line"><div class="text">Testing...</div><div class="data" data-tag="one">1</div><div class="text">...</div><div class="data" data-tag="two">2</div><div class="text">...</div><div class="data" data-tag="three">3</div></div><div class="line"><div class="text">Testing...</div><div class="data" data-tag="one">1</div><div class="text">...</div><div class="data" data-tag="two">2</div><div class="text">...</div><div class="data" data-tag="three">3</div></div><div class="line"><div class="text">Xesting...</div><div class="data" data-tag="one">1</div><div class="text">...</div><div class="data" data-tag="two">2</div><div class="text">...</div><div class="data" data-tag="three">3</div></div> \ No newline at end of file
+</div><div class="data" data-tag="sku">gum-1412</div><div class="text">Connecting to </div><div class="data" data-tag="host">my-box</div><div class="text">.</div><div class="data" data-tag="domain">example.com</div><div class="text">...</div></div><div class="line"><div class="title">Item </div><div class="title"> Total Sold</div><div class="title"> In Stock</div><div class="title"> On Order</div><div class="title"> SKU</div></div><div class="line"><div class="data" data-tag="name" data-key="key">gum </div><div class="data" data-tag="sold"> 1412</div><div class="data" data-tag="in-stock"> 54</div><div class="data" data-tag="on-order"> 10</div><div class="data" data-tag="sku" data-key="key"> GRO-000-415</div></div><div class="line"><div class="data" data-tag="name" data-key="key">rope </div><div class="data" data-tag="sold"> 85</div><div class="data" data-tag="in-stock"> 4</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> HRD-000-212</div></div><div class="line"><div class="data" data-tag="name" data-key="key">ladder </div><div class="data" data-tag="sold"> 0</div><div class="data" data-tag="in-stock"> 2</div><div class="data" data-tag="on-order"> 1</div><div class="data" data-tag="sku" data-key="key"> HRD-000-517</div></div><div class="line"><div class="data" data-tag="name" data-key="key">bolt </div><div class="data" data-tag="sold"> 4123</div><div class="data" data-tag="in-stock"> 144</div><div class="data" data-tag="on-order"> 42</div><div class="data" data-tag="sku" data-key="key"> HRD-000-632</div></div><div class="line"><div class="data" data-tag="name" data-key="key">water </div><div class="data" data-tag="sold"> 17</div><div class="data" data-tag="in-stock"> 14</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div></div><div class="line"></div><div class="line"></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">gum</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">1412.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">54</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">10</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-415</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">rope</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">85.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">4</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-212</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">ladder</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">2</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-517</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">bolt</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">4123.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">144</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">42</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">HRD-000-632</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">water</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">17.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">14</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">2</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-2331</div></div><div class="line"><div class="label">Item</div><div class="text"> '</div><div class="data" data-tag="name" data-key="key">fish</div><div class="text">':</div></div><div class="line"><div class="padding"> </div><div class="label">Total sold</div><div class="text">: </div><div class="data" data-tag="sold">1321.0</div></div><div class="line"><div class="padding"> </div><div class="label">In stock</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="in-stock">45</div></div><div class="line"><div class="padding"> </div><div class="label">On order</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="on-order">1</div></div><div class="line"><div class="padding"> </div><div class="label">SKU</div><div class="text">: </div><div class="data" data-tag="sku" data-key="key">GRO-000-533</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">gum</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">rope</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">ladder</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">bolt</div></div><div class="line"><div class="label">Item</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="item">water</div></div><div class="line"><div class="title">Item </div><div class="title"> Total Sold</div><div class="title"> In Stock</div><div class="title"> On Order</div><div class="title"> SKU</div></div><div class="line"><div class="data" data-tag="name" data-key="key">gum </div><div class="data" data-tag="sold"> 1412</div><div class="data" data-tag="on-order"> 10</div><div class="data" data-tag="in-stock"> 54</div><div class="data" data-tag="sku" data-key="key"> GRO-000-415</div></div><div class="line"><div class="data" data-tag="name" data-key="key">rope </div><div class="data" data-tag="sold"> 85</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="in-stock"> 4</div><div class="data" data-tag="sku" data-key="key"> HRD-000-212</div></div><div class="line"><div class="data" data-tag="name" data-key="key">ladder </div><div class="data" data-tag="sold"> 0</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 1</div><div class="data" data-tag="in-stock"> 2</div><div class="data" data-tag="sku" data-key="key"> HRD-000-517</div></div><div class="line"><div class="data" data-tag="name" data-key="key">bolt </div><div class="data" data-tag="sold"> 4123</div><div class="data" data-tag="on-order"> 42</div><div class="data" data-tag="in-stock"> 144</div><div class="data" data-tag="sku" data-key="key"> HRD-000-632</div></div><div class="line"><div class="data" data-tag="name" data-key="key">water </div><div class="data" data-tag="sold"> 17</div><div class="text">Extra: </div><div class="data" data-tag="extra">special</div><div class="data" data-tag="on-order"> 2</div><div class="data" data-tag="in-stock"> 14</div><div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div></div><div class="line"></div><div class="line"></div><div class="line"><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div><div class="text">X</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">425</div></div><div class="line"><div class="text">X</div><div class="padding"> </div><div class="text">X</div><div class="label">Cost</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="cost">455</div></div><div class="line"><div class="text"> </div><div class="data" data-tag="links">links</div><div class="text"> </div><div class="data" data-tag="user">user</div><div class="text"> </div><div class="data" data-tag="group">group</div><div class="text"> </div></div><div class="line"><div class="data" data-tag="links">3 </div><div class="data" data-tag="post">this </div></div><div class="line"><div class="data" data-tag="mode">/some/file</div><div class="text"> </div><div class="data" data-tag="links"> 1</div><div class="text"> </div><div class="data" data-tag="user">user </div><div class="text"> </div><div class="data" data-tag="group">group </div><div class="text"> </div></div> \ No newline at end of file
diff --git a/tests/core/saved/test_01.HIPx.out b/tests/core/saved/test_01.HIPx.out
index 1be8bf58f674..da30b72ab7ec 100644
--- a/tests/core/saved/test_01.HIPx.out
+++ b/tests/core/saved/test_01.HIPx.out
@@ -58,7 +58,6 @@
<div class="data" data-tag="some-chaos" data-xpath="/top-level/some-chaos">42
</div>
<div class="data" data-tag="sku" data-xpath="/top-level/sku" data-type="string" data-help="Stock Keeping Unit">gum-1412</div>
- <div class="data" data-tag="sku" data-xpath="/top-level/sku" data-type="string" data-help="Stock Keeping Unit">sum-4121</div>
<div class="text">Connecting to </div>
<div class="data" data-tag="host" data-xpath="/top-level/host">my-box</div>
<div class="text">.</div>
@@ -436,27 +435,3 @@
<div class="data" data-tag="group" data-xpath="/top-level/group">group </div>
<div class="text"> </div>
</div>
-<div class="line">
- <div class="text">Testing...</div>
- <div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
-</div>
-<div class="line">
- <div class="text">Testing...</div>
- <div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
-</div>
-<div class="line">
- <div class="text">Xesting...</div>
- <div class="data" data-tag="one" data-xpath="/top-level/one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two" data-xpath="/top-level/two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three" data-xpath="/top-level/three">3</div>
-</div>
diff --git a/tests/core/saved/test_01.HP.out b/tests/core/saved/test_01.HP.out
index 91e5292d32df..5a7aed05ac0b 100644
--- a/tests/core/saved/test_01.HP.out
+++ b/tests/core/saved/test_01.HP.out
@@ -58,7 +58,6 @@
<div class="data" data-tag="some-chaos">42
</div>
<div class="data" data-tag="sku">gum-1412</div>
- <div class="data" data-tag="sku">sum-4121</div>
<div class="text">Connecting to </div>
<div class="data" data-tag="host">my-box</div>
<div class="text">.</div>
@@ -436,27 +435,3 @@
<div class="data" data-tag="group">group </div>
<div class="text"> </div>
</div>
-<div class="line">
- <div class="text">Testing...</div>
- <div class="data" data-tag="one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three">3</div>
-</div>
-<div class="line">
- <div class="text">Testing...</div>
- <div class="data" data-tag="one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three">3</div>
-</div>
-<div class="line">
- <div class="text">Xesting...</div>
- <div class="data" data-tag="one">1</div>
- <div class="text">...</div>
- <div class="data" data-tag="two">2</div>
- <div class="text">...</div>
- <div class="data" data-tag="three">3</div>
-</div>
diff --git a/tests/core/saved/test_01.J.out b/tests/core/saved/test_01.J.out
index ff6fbf5be2b2..b8c782677916 100644
--- a/tests/core/saved/test_01.J.out
+++ b/tests/core/saved/test_01.J.out
@@ -1 +1 @@
-{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412","sum-000-4121"],"host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group","one":1,"two":2,"three":3,"one":1,"two":2,"three":3,"one":1,"two":2,"three":3}}
+{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412"],"host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}}
diff --git a/tests/core/saved/test_01.JP.out b/tests/core/saved/test_01.JP.out
index 31d07a4adde7..71a77cea81df 100644
--- a/tests/core/saved/test_01.JP.out
+++ b/tests/core/saved/test_01.JP.out
@@ -22,8 +22,7 @@
"min-chaos": 42,
"some-chaos": "[42]",
"sku": [
- "gum-000-1412",
- "sum-000-4121"
+ "gum-000-1412"
],
"host": "my-box",
"domain": "example.com",
@@ -181,15 +180,6 @@
"mode_octal": 640,
"links": 1,
"user": "user",
- "group": "group",
- "one": 1,
- "two": 2,
- "three": 3,
- "one": 1,
- "two": 2,
- "three": 3,
- "one": 1,
- "two": 2,
- "three": 3
+ "group": "group"
}
}
diff --git a/tests/core/saved/test_01.JPu.out b/tests/core/saved/test_01.JPu.out
index eab1d53335a9..747db16f07a7 100644
--- a/tests/core/saved/test_01.JPu.out
+++ b/tests/core/saved/test_01.JPu.out
@@ -22,8 +22,7 @@
"min_chaos": 42,
"some_chaos": "[42]",
"sku": [
- "gum-000-1412",
- "sum-000-4121"
+ "gum-000-1412"
],
"host": "my-box",
"domain": "example.com",
@@ -181,15 +180,6 @@
"mode_octal": 640,
"links": 1,
"user": "user",
- "group": "group",
- "one": 1,
- "two": 2,
- "three": 3,
- "one": 1,
- "two": 2,
- "three": 3,
- "one": 1,
- "two": 2,
- "three": 3
+ "group": "group"
}
}
diff --git a/tests/core/saved/test_01.T.out b/tests/core/saved/test_01.T.out
index f9d473e0c653..89d3157336e2 100644
--- a/tests/core/saved/test_01.T.out
+++ b/tests/core/saved/test_01.T.out
@@ -7,7 +7,7 @@ testing argument modifier with encoding to .example.com...
Label text value
My Title
very 4242
-gum-1412sum-4121Connecting to my-box.example.com...
+gum-1412Connecting to my-box.example.com...
Item Total Sold In Stock On Order SKU
gum 1412 54 10 GRO-000-415
rope 85 4 2 HRD-000-212
@@ -65,6 +65,3 @@ X XCost: 455
links user group
3 this
/some/file 1 user group
-Testing...1...2...3
-Testing...1...2...3
-Xesting...1...2...3
diff --git a/tests/core/saved/test_01.X.out b/tests/core/saved/test_01.X.out
index a8d1629e17ad..2f1fa8261702 100644
--- a/tests/core/saved/test_01.X.out
+++ b/tests/core/saved/test_01.X.out
@@ -1 +1 @@
-<top-level><type>ethernet</type><type>bridge</type><type>18u</type><type>24</type><address>0x0</address><port>1</port><address>0x0</address><port>1</port><address>0x0</address><port>1</port><used-percent>12</used-percent><kve_start>0xdeadbeef</kve_start><kve_end>0xcabb1e</kve_end><host>my-box</host><domain>example.com</domain><host>my-box</host><domain>example.com</domain><label>value</label><max-chaos>very</max-chaos><min-chaos>42</min-chaos><some-chaos>[42]</some-chaos><sku test-attr="attr-value">gum-000-1412</sku><sku>sum-000-4121</sku><host>my-box</host><domain>example.com</domain><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data2><item><sku key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412.0</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku key="key">HRD-000-212</sku><name key="key">rope</name><sold>85.0</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123.0</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku key="key">GRO-000-2331</sku><name key="key">water</name><sold>17.0</sold><in-stock>14</in-stock><on-order>2</on-order></item></data2><data3><item><sku key="key">GRO-000-533</sku><name key="key">fish</name><sold>1321.0</sold><in-stock>45</in-stock><on-order>1</on-order></item></data3><data4><item test4="value4">gum</item><item test4="value4">rope</item><item test4="value4">ladder</item><item test4="value4">bolt</item><item test4="value4">water</item></data4><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><on-order>10</on-order><in-stock>54</in-stock></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><extra>special</extra><on-order>2</on-order><in-stock>4</in-stock></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><extra>special</extra><on-order>1</on-order><in-stock>2</in-stock></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><on-order>42</on-order><in-stock>144</in-stock></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><extra>special</extra><on-order>2</on-order><in-stock>14</in-stock></item></data><cost>425</cost><cost>455</cost><mode>mode</mode><mode_octal>octal</mode_octal><links>links</links><user>user</user><group>group</group><pre>that</pre><links>3</links><post>this</post><mode>/some/file</mode><mode_octal>640</mode_octal><links>1</links><user>user</user><group>group</group><one>1</one><two>2</two><three>3</three><one>1</one><two>2</two><three>3</three><one>1</one><two>2</two><three>3</three></top-level> \ No newline at end of file
+<top-level><type>ethernet</type><type>bridge</type><type>18u</type><type>24</type><address>0x0</address><port>1</port><address>0x0</address><port>1</port><address>0x0</address><port>1</port><used-percent>12</used-percent><kve_start>0xdeadbeef</kve_start><kve_end>0xcabb1e</kve_end><host>my-box</host><domain>example.com</domain><host>my-box</host><domain>example.com</domain><label>value</label><max-chaos>very</max-chaos><min-chaos>42</min-chaos><some-chaos>[42]</some-chaos><sku test-attr="attr-value">gum-000-1412</sku><host>my-box</host><domain>example.com</domain><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><in-stock>14</in-stock><on-order>2</on-order></item></data><data2><item><sku key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412.0</sold><in-stock>54</in-stock><on-order>10</on-order></item><item><sku key="key">HRD-000-212</sku><name key="key">rope</name><sold>85.0</sold><in-stock>4</in-stock><on-order>2</on-order></item><item><sku key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><in-stock>2</in-stock><on-order>1</on-order></item><item><sku key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123.0</sold><in-stock>144</in-stock><on-order>42</on-order></item><item><sku key="key">GRO-000-2331</sku><name key="key">water</name><sold>17.0</sold><in-stock>14</in-stock><on-order>2</on-order></item></data2><data3><item><sku key="key">GRO-000-533</sku><name key="key">fish</name><sold>1321.0</sold><in-stock>45</in-stock><on-order>1</on-order></item></data3><data4><item test4="value4">gum</item><item test4="value4">rope</item><item test4="value4">ladder</item><item test4="value4">bolt</item><item test4="value4">water</item></data4><data test="value"><item test2="value2"><sku test3="value3" key="key">GRO-000-415</sku><name key="key">gum</name><sold>1412</sold><on-order>10</on-order><in-stock>54</in-stock></item><item><sku test3="value3" key="key">HRD-000-212</sku><name key="key">rope</name><sold>85</sold><extra>special</extra><on-order>2</on-order><in-stock>4</in-stock></item><item><sku test3="value3" key="key">HRD-000-517</sku><name key="key">ladder</name><sold>0</sold><extra>special</extra><on-order>1</on-order><in-stock>2</in-stock></item><item><sku test3="value3" key="key">HRD-000-632</sku><name key="key">bolt</name><sold>4123</sold><on-order>42</on-order><in-stock>144</in-stock></item><item><sku test3="value3" key="key">GRO-000-2331</sku><name key="key">water</name><sold>17</sold><extra>special</extra><on-order>2</on-order><in-stock>14</in-stock></item></data><cost>425</cost><cost>455</cost><mode>mode</mode><mode_octal>octal</mode_octal><links>links</links><user>user</user><group>group</group><pre>that</pre><links>3</links><post>this</post><mode>/some/file</mode><mode_octal>640</mode_octal><links>1</links><user>user</user><group>group</group></top-level> \ No newline at end of file
diff --git a/tests/core/saved/test_01.XP.out b/tests/core/saved/test_01.XP.out
index 7674580d94d9..afa79ada5f81 100644
--- a/tests/core/saved/test_01.XP.out
+++ b/tests/core/saved/test_01.XP.out
@@ -21,7 +21,6 @@
<min-chaos>42</min-chaos>
<some-chaos>[42]</some-chaos>
<sku test-attr="attr-value">gum-000-1412</sku>
- <sku>sum-000-4121</sku>
<host>my-box</host>
<domain>example.com</domain>
<data test="value">
@@ -169,13 +168,4 @@
<links>1</links>
<user>user</user>
<group>group</group>
- <one>1</one>
- <two>2</two>
- <three>3</three>
- <one>1</one>
- <two>2</two>
- <three>3</three>
- <one>1</one>
- <two>2</two>
- <three>3</three>
</top-level>
diff --git a/tests/core/saved/test_13.E.err b/tests/core/saved/test_01.err
index e69de29bb2d1..e69de29bb2d1 100644
--- a/tests/core/saved/test_13.E.err
+++ b/tests/core/saved/test_01.err
diff --git a/tests/core/saved/test_01.out b/tests/core/saved/test_01.out
new file mode 100644
index 000000000000..c2ad7a005274
--- /dev/null
+++ b/tests/core/saved/test_01.out
@@ -0,0 +1,38 @@
+Item Total Sold In Stock On Order SKU
+gum 1412 54 10 GRO-000-415
+rope 85 4 2 HRD-000-212
+ladder 0 2 1 HRD-000-517
+bolt 4123 144 42 HRD-000-632
+water 17 14 2 GRO-000-2331
+
+
+Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
diff --git a/tests/core/saved/test_13.H.err b/tests/core/saved/test_02.err
index e69de29bb2d1..e69de29bb2d1 100644
--- a/tests/core/saved/test_13.H.err
+++ b/tests/core/saved/test_02.err
diff --git a/tests/core/saved/test_02.out b/tests/core/saved/test_02.out
new file mode 100644
index 000000000000..c2ad7a005274
--- /dev/null
+++ b/tests/core/saved/test_02.out
@@ -0,0 +1,38 @@
+Item Total Sold In Stock On Order SKU
+gum 1412 54 10 GRO-000-415
+rope 85 4 2 HRD-000-212
+ladder 0 2 1 HRD-000-517
+bolt 4123 144 42 HRD-000-632
+water 17 14 2 GRO-000-2331
+
+
+Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
diff --git a/tests/core/saved/test_13.HIPx.err b/tests/core/saved/test_03.err
index e69de29bb2d1..e69de29bb2d1 100644
--- a/tests/core/saved/test_13.HIPx.err
+++ b/tests/core/saved/test_03.err
diff --git a/tests/core/saved/test_03.out b/tests/core/saved/test_03.out
new file mode 100644
index 000000000000..da60fb7c9ab3
--- /dev/null
+++ b/tests/core/saved/test_03.out
@@ -0,0 +1,3 @@
+Terry Jones works in dept #660
+Leslie Patterson works in dept #341
+Ashley Smith works in dept #1440
diff --git a/tests/core/saved/test_13.HP.err b/tests/core/saved/test_10.err
index e69de29bb2d1..e69de29bb2d1 100644
--- a/tests/core/saved/test_13.HP.err
+++ b/tests/core/saved/test_10.err
diff --git a/tests/core/saved/test_10.out b/tests/core/saved/test_10.out
new file mode 100644
index 000000000000..c2ad7a005274
--- /dev/null
+++ b/tests/core/saved/test_10.out
@@ -0,0 +1,38 @@
+Item Total Sold In Stock On Order SKU
+gum 1412 54 10 GRO-000-415
+rope 85 4 2 HRD-000-212
+ladder 0 2 1 HRD-000-517
+bolt 4123 144 42 HRD-000-632
+water 17 14 2 GRO-000-2331
+
+
+Item 'gum':
+ Total sold: 1412.0
+ In stock: 54
+ On order: 10
+ SKU: GRO-000-415
+Item 'rope':
+ Total sold: 85.0
+ In stock: 4
+ On order: 2
+ SKU: HRD-000-212
+Item 'ladder':
+ Total sold: 0
+ In stock: 2
+ On order: 1
+ SKU: HRD-000-517
+Item 'bolt':
+ Total sold: 4123.0
+ In stock: 144
+ On order: 42
+ SKU: HRD-000-632
+Item 'water':
+ Total sold: 17.0
+ In stock: 14
+ On order: 2
+ SKU: GRO-000-2331
+Item 'fish':
+ Total sold: 1321.0
+ In stock: 45
+ On order: 1
+ SKU: GRO-000-533
diff --git a/tests/core/saved/test_12.E.out b/tests/core/saved/test_12.E.out
index 2c3bdde6d89a..414311499fee 100644
--- a/tests/core/saved/test_12.E.out
+++ b/tests/core/saved/test_12.E.out
@@ -83,16 +83,12 @@ op content: [time] [2:15] [0]
op string: [hand] [left] [0]
op string: [color] [blue] [0]
op content: [time] [3:45] [0]
-op close_instance: [thing] [] [0]
-op close_list: [thing] [] [0]
op open_container: [2by4] [] [0x4040010]
op string: [4x4] [truck] [0]
op string: [2morrow] [tomorrow] [0]
op close_container: [2by4] [] [0]
-op open_container: [tagÜÖÄ] [] [0x4040010]
-op string: [cölor] [blue] [0]
-op string: [säfe] [yes] [0]
-op close_container: [tagÜÖÄ] [] [0]
+op close_instance: [thing] [] [0]
+op close_list: [thing] [] [0]
op close_container: [data] [] [0]
op close_container: [top] [] [0]
op finish: [] [] [0]
diff --git a/tests/core/saved/test_12.H.out b/tests/core/saved/test_12.H.out
index 95a90164e22c..86f0b3476dfa 100644
--- a/tests/core/saved/test_12.H.out
+++ b/tests/core/saved/test_12.H.out
@@ -1 +1 @@
-<div class="line"><div class="text color-fg-red color-bg-green">Merry XMas!!</div></div><div class="line"><div class="text">One </div><div class="data color-fg-yellow color-bg-blue" data-tag="animal">fish</div><div class="text">, Two </div><div class="data color-fg-green color-bg-yellow" data-tag="animal">fish</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">There is </div><div class="data" data-tag="4x4">truck</div><div class="text"> in </div><div class="data" data-tag="2morrow">tomorrow</div></div><div class="line"><div class="text">The </div><div class="data" data-tag="cölor">blue</div><div class="text"> is </div><div class="data" data-tag="säfe">yes</div></div> \ No newline at end of file
+<div class="line"><div class="text color-fg-red color-bg-green">Merry XMas!!</div></div><div class="line"><div class="text">One </div><div class="data color-fg-yellow color-bg-blue" data-tag="animal">fish</div><div class="text">, Two </div><div class="data color-fg-green color-bg-yellow" data-tag="animal">fish</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">The </div><div class="data color-fg-red" data-tag="name">thing</div><div class="text"> is </div><div class="data color-fg-green" data-tag="color">green</div><div class="text"> til </div><div class="data" data-tag="time">02:15</div></div><div class="line"><div class="text">My </div><div class="data color-fg-red" data-tag="hand">left</div><div class="text"> hand is </div><div class="data color-fg-blue" data-tag="color">blue</div><div class="text"> til </div><div class="data" data-tag="time">03:45</div></div><div class="line"><div class="text">There is </div><div class="data" data-tag="4x4">truck</div><div class="text"> in </div><div class="data" data-tag="2morrow">tomorrow</div></div> \ No newline at end of file
diff --git a/tests/core/saved/test_12.HIPx.out b/tests/core/saved/test_12.HIPx.out
index 128a24b80634..a5588c14493b 100644
--- a/tests/core/saved/test_12.HIPx.out
+++ b/tests/core/saved/test_12.HIPx.out
@@ -169,13 +169,7 @@
</div>
<div class="line">
<div class="text">There is </div>
- <div class="data" data-tag="4x4" data-xpath="/top/data/2by4/4x4">truck</div>
+ <div class="data" data-tag="4x4" data-xpath="/top/data/thing[name = 'thing']/2by4/4x4">truck</div>
<div class="text"> in </div>
- <div class="data" data-tag="2morrow" data-xpath="/top/data/2by4/2morrow">tomorrow</div>
-</div>
-<div class="line">
- <div class="text">The </div>
- <div class="data" data-tag="cölor" data-xpath="/top/data/tagÜÖÄ/cölor">blue</div>
- <div class="text"> is </div>
- <div class="data" data-tag="säfe" data-xpath="/top/data/tagÜÖÄ/säfe">yes</div>
+ <div class="data" data-tag="2morrow" data-xpath="/top/data/thing[name = 'thing']/2by4/2morrow">tomorrow</div>
</div>
diff --git a/tests/core/saved/test_12.HP.out b/tests/core/saved/test_12.HP.out
index 7e87d45082c7..f0b04abf3397 100644
--- a/tests/core/saved/test_12.HP.out
+++ b/tests/core/saved/test_12.HP.out
@@ -173,9 +173,3 @@
<div class="text"> in </div>
<div class="data" data-tag="2morrow">tomorrow</div>
</div>
-<div class="line">
- <div class="text">The </div>
- <div class="data" data-tag="cölor">blue</div>
- <div class="text"> is </div>
- <div class="data" data-tag="säfe">yes</div>
-</div>
diff --git a/tests/core/saved/test_12.J.out b/tests/core/saved/test_12.J.out
index 80ee2b8d3bc6..25a2416195a9 100644
--- a/tests/core/saved/test_12.J.out
+++ b/tests/core/saved/test_12.J.out
@@ -1 +1 @@
-{"top": {"data": {"animal":"fish","animal":"fish", "thing": [{"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}], "2by4": {"4x4":"truck","2morrow":"tomorrow"}, "tagÜÖÄ": {"cölor":"blue","säfe":"yes"}}}}
+{"top": {"data": {"animal":"fish","animal":"fish", "thing": [{"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45"}, {"name":"thing","color":"green","time":"2:15","hand":"left","color":"blue","time":"3:45", "2by4": {"4x4":"truck","2morrow":"tomorrow"}}]}}}
diff --git a/tests/core/saved/test_12.JP.out b/tests/core/saved/test_12.JP.out
index 23cd6d1eb5a7..0095d8dcc59a 100644
--- a/tests/core/saved/test_12.JP.out
+++ b/tests/core/saved/test_12.JP.out
@@ -82,17 +82,13 @@
"time": "2:15",
"hand": "left",
"color": "blue",
- "time": "3:45"
+ "time": "3:45",
+ "2by4": {
+ "4x4": "truck",
+ "2morrow": "tomorrow"
+ }
}
- ],
- "2by4": {
- "4x4": "truck",
- "2morrow": "tomorrow"
- },
- "tagÜÖÄ": {
- "cölor": "blue",
- "säfe": "yes"
- }
+ ]
}
}
}
diff --git a/tests/core/saved/test_12.JPu.out b/tests/core/saved/test_12.JPu.out
index 23cd6d1eb5a7..0095d8dcc59a 100644
--- a/tests/core/saved/test_12.JPu.out
+++ b/tests/core/saved/test_12.JPu.out
@@ -82,17 +82,13 @@
"time": "2:15",
"hand": "left",
"color": "blue",
- "time": "3:45"
+ "time": "3:45",
+ "2by4": {
+ "4x4": "truck",
+ "2morrow": "tomorrow"
+ }
}
- ],
- "2by4": {
- "4x4": "truck",
- "2morrow": "tomorrow"
- },
- "tagÜÖÄ": {
- "cölor": "blue",
- "säfe": "yes"
- }
+ ]
}
}
}
diff --git a/tests/core/saved/test_12.T.out b/tests/core/saved/test_12.T.out
index ee17e4b53e45..42ee933808d7 100644
--- a/tests/core/saved/test_12.T.out
+++ b/tests/core/saved/test_12.T.out
@@ -21,4 +21,3 @@ My left hand is blue til 03:45
The thing is green til 02:15
My left hand is blue til 03:45
There is truck in tomorrow
-The blue is yes
diff --git a/tests/core/saved/test_12.X.out b/tests/core/saved/test_12.X.out
index 254eb5626a05..072444615c79 100644
--- a/tests/core/saved/test_12.X.out
+++ b/tests/core/saved/test_12.X.out
@@ -1 +1 @@
-<top><data><animal>fish</animal><animal>fish</animal><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><_2by4><_4x4>truck</_4x4><_2morrow>tomorrow</_2morrow></_2by4><tagÜÖÄ><cölor>blue</cölor><säfe>yes</säfe></tagÜÖÄ></data></top> \ No newline at end of file
+<top><data><animal>fish</animal><animal>fish</animal><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time></thing><thing><name>thing</name><color>green</color><time>2:15</time><hand>left</hand><color>blue</color><time>3:45</time><_2by4><_4x4>truck</_4x4><_2morrow>tomorrow</_2morrow></_2by4></thing></data></top> \ No newline at end of file
diff --git a/tests/core/saved/test_12.XP.out b/tests/core/saved/test_12.XP.out
index d56a35623090..b3dc5992fbe9 100644
--- a/tests/core/saved/test_12.XP.out
+++ b/tests/core/saved/test_12.XP.out
@@ -81,14 +81,10 @@
<hand>left</hand>
<color>blue</color>
<time>3:45</time>
+ <_2by4>
+ <_4x4>truck</_4x4>
+ <_2morrow>tomorrow</_2morrow>
+ </_2by4>
</thing>
- <_2by4>
- <_4x4>truck</_4x4>
- <_2morrow>tomorrow</_2morrow>
- </_2by4>
- <tagÜÖÄ>
- <cölor>blue</cölor>
- <säfe>yes</säfe>
- </tagÜÖÄ>
</data>
</top>
diff --git a/tests/core/saved/test_13.E.out b/tests/core/saved/test_13.E.out
deleted file mode 100644
index 8b899ff6f0c2..000000000000
--- a/tests/core/saved/test_13.E.out
+++ /dev/null
@@ -1,170 +0,0 @@
-op create: [test] [] [0]
-op open_container: [top] [] [0x4040010]
-op open_container: [data] [] [0x4040010]
-op open_list: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000000] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000001] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000002] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000003] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000004] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000005] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000006] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000007] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000008] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op open_instance: [entry] [] [0x44040010]
-op string: [name] [xx-00000009] [0x88]
-op content: [inode] [12] [0x1000]
-op content: [blocks] [1234] [0x1000]
-op string: [mode] [mode] [0x1000]
-op content: [mode_octal] [660] [0x8]
-op content: [links] [12] [0x1000]
-op string: [user] [phil] [0x1000]
-op string: [group] [phil] [0x1000]
-op string: [type] [regular] [0x8]
-op string: [flags] [123] [0]
-op string: [label] [1234] [0x1000]
-op content: [size] [12345] [0]
-op attr: [value] [1644355825] [0]
-op content: [modify-time] [1644355825] [0x28]
-op close_instance: [entry] [] [0]
-op close_list: [entry] [] [0]
-op content: [hits] [72] [0]
-op close_container: [data] [] [0]
-op close_container: [top] [] [0]
-op finish: [] [] [0]
-op flush: [] [] [0]
diff --git a/tests/core/saved/test_13.H.out b/tests/core/saved/test_13.H.out
deleted file mode 100644
index b2a7e9e9d9bc..000000000000
--- a/tests/core/saved/test_13.H.out
+++ /dev/null
@@ -1 +0,0 @@
-<div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000000</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000001</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000002</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000003</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000004</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000005</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000006</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000007</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000008</div></div><div class="line"><div class="data" data-tag="inode"> 12</div><div class="text"> </div><div class="data" data-tag="blocks">1234</div><div class="text"> </div><div class="data" data-tag="mode">mode</div><div class="text"> </div><div class="data" data-tag="links">12</div><div class="text"> </div><div class="data" data-tag="user">phil</div><div class="text"> </div><div class="data" data-tag="group">phil</div><div class="text"> </div><div class="data" data-tag="flags">123</div><div class="text"> </div><div class="data" data-tag="label">1234</div><div class="text"> </div><div class="data" data-tag="size">12345</div><div class="text"> </div><div class="data" data-tag="modify-time"> 8 Feb 16:30</div><div class="text"> </div><div class="data" data-tag="name">xx-00000009</div></div><div class="line"><div class="label">hits</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="hits">72</div></div> \ No newline at end of file
diff --git a/tests/core/saved/test_13.HIPx.out b/tests/core/saved/test_13.HIPx.out
deleted file mode 100644
index 9d72bcfba0c6..000000000000
--- a/tests/core/saved/test_13.HIPx.out
+++ /dev/null
@@ -1,236 +0,0 @@
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000000']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000000']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000000']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000000']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000000']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000000']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000000']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000000']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000000']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000000']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000000</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000001']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000001']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000001']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000001']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000001']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000001']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000001']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000001']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000001']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000001']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000001</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000002']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000002']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000002']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000002']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000002']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000002']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000002']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000002']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000002']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000002']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000002</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000003']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000003']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000003']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000003']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000003']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000003']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000003']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000003']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000003']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000003']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000003</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000004']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000004']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000004']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000004']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000004']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000004']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000004']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000004']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000004']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000004']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000004</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000005']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000005']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000005']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000005']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000005']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000005']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000005']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000005']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000005']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000005']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000005</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000006']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000006']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000006']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000006']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000006']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000006']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000006']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000006']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000006']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000006']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000006</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000007']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000007']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000007']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000007']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000007']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000007']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000007']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000007']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000007']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000007']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000007</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000008']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000008']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000008']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000008']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000008']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000008']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000008']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000008']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000008']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000008']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000008</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode" data-xpath="/top/data/entry[name = 'xx-00000009']/inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks" data-xpath="/top/data/entry[name = 'xx-00000009']/blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode" data-xpath="/top/data/entry[name = 'xx-00000009']/mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links" data-xpath="/top/data/entry[name = 'xx-00000009']/links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user" data-xpath="/top/data/entry[name = 'xx-00000009']/user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group" data-xpath="/top/data/entry[name = 'xx-00000009']/group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags" data-xpath="/top/data/entry[name = 'xx-00000009']/flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label" data-xpath="/top/data/entry[name = 'xx-00000009']/label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size" data-xpath="/top/data/entry[name = 'xx-00000009']/size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time" data-xpath="/top/data/entry[name = 'xx-00000009']/modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name" data-xpath="/top/data/entry/name">xx-00000009</div>
-</div>
-<div class="line">
- <div class="label">hits</div>
- <div class="decoration">:</div>
- <div class="padding"> </div>
- <div class="data" data-tag="hits" data-xpath="/top/data/hits">72</div>
-</div>
diff --git a/tests/core/saved/test_13.HP.out b/tests/core/saved/test_13.HP.out
deleted file mode 100644
index 0bf02bbef886..000000000000
--- a/tests/core/saved/test_13.HP.out
+++ /dev/null
@@ -1,236 +0,0 @@
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000000</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000001</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000002</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000003</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000004</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000005</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000006</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000007</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000008</div>
-</div>
-<div class="line">
- <div class="data" data-tag="inode"> 12</div>
- <div class="text"> </div>
- <div class="data" data-tag="blocks">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="mode">mode</div>
- <div class="text"> </div>
- <div class="data" data-tag="links">12</div>
- <div class="text"> </div>
- <div class="data" data-tag="user">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="group">phil</div>
- <div class="text"> </div>
- <div class="data" data-tag="flags">123</div>
- <div class="text"> </div>
- <div class="data" data-tag="label">1234</div>
- <div class="text"> </div>
- <div class="data" data-tag="size">12345</div>
- <div class="text"> </div>
- <div class="data" data-tag="modify-time"> 8 Feb 16:30</div>
- <div class="text"> </div>
- <div class="data" data-tag="name">xx-00000009</div>
-</div>
-<div class="line">
- <div class="label">hits</div>
- <div class="decoration">:</div>
- <div class="padding"> </div>
- <div class="data" data-tag="hits">72</div>
-</div>
diff --git a/tests/core/saved/test_13.J.err b/tests/core/saved/test_13.J.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.J.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.J.out b/tests/core/saved/test_13.J.out
deleted file mode 100644
index ecaa5ece2619..000000000000
--- a/tests/core/saved/test_13.J.out
+++ /dev/null
@@ -1 +0,0 @@
-{"top": {"data": {"entry": [{"name":"xx-00000000","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000001","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000002","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000003","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000004","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000005","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000006","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000007","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000008","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}, {"name":"xx-00000009","inode":12,"blocks":1234,"mode":"mode","mode_octal":660,"links":12,"user":"phil","group":"phil","type":"regular","flags":"123","label":"1234","size":12345,"modify-time":1644355825}],"hits":72}}}
diff --git a/tests/core/saved/test_13.JP.err b/tests/core/saved/test_13.JP.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.JP.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.JP.out b/tests/core/saved/test_13.JP.out
deleted file mode 100644
index aa6ab890b4d3..000000000000
--- a/tests/core/saved/test_13.JP.out
+++ /dev/null
@@ -1,159 +0,0 @@
-{
- "top": {
- "data": {
- "entry": [
- {
- "name": "xx-00000000",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000001",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000002",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000003",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000004",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000005",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000006",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000007",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000008",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- },
- {
- "name": "xx-00000009",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify-time": 1644355825
- }
- ],
- "hits": 72
- }
- }
-}
diff --git a/tests/core/saved/test_13.JPu.err b/tests/core/saved/test_13.JPu.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.JPu.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.JPu.out b/tests/core/saved/test_13.JPu.out
deleted file mode 100644
index 006b0d4f8f78..000000000000
--- a/tests/core/saved/test_13.JPu.out
+++ /dev/null
@@ -1,159 +0,0 @@
-{
- "top": {
- "data": {
- "entry": [
- {
- "name": "xx-00000000",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000001",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000002",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000003",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000004",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000005",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000006",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000007",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000008",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- },
- {
- "name": "xx-00000009",
- "inode": 12,
- "blocks": 1234,
- "mode": "mode",
- "mode_octal": 660,
- "links": 12,
- "user": "phil",
- "group": "phil",
- "type": "regular",
- "flags": "123",
- "label": "1234",
- "size": 12345,
- "modify_time": 1644355825
- }
- ],
- "hits": 72
- }
- }
-}
diff --git a/tests/core/saved/test_13.T.err b/tests/core/saved/test_13.T.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.T.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.T.out b/tests/core/saved/test_13.T.out
deleted file mode 100644
index cc7dd3a5c1b9..000000000000
--- a/tests/core/saved/test_13.T.out
+++ /dev/null
@@ -1,11 +0,0 @@
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000000
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000001
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000002
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000003
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000004
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000005
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000006
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000007
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000008
- 12 1234 mode 12 phil phil 123 1234 12345 8 Feb 16:30 xx-00000009
-hits: 72
diff --git a/tests/core/saved/test_13.X.err b/tests/core/saved/test_13.X.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.X.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.X.out b/tests/core/saved/test_13.X.out
deleted file mode 100644
index 7d9e0b29316f..000000000000
--- a/tests/core/saved/test_13.X.out
+++ /dev/null
@@ -1 +0,0 @@
-<top><data><entry><name>xx-00000000</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000001</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000002</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000003</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000004</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000005</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000006</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000007</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000008</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><entry><name>xx-00000009</name><inode>12</inode><blocks>1234</blocks><mode>mode</mode><mode_octal>660</mode_octal><links>12</links><user>phil</user><group>phil</group><type>regular</type><flags>123</flags><label>1234</label><size>12345</size><modify-time value="1644355825">1644355825</modify-time></entry><hits>72</hits></data></top> \ No newline at end of file
diff --git a/tests/core/saved/test_13.XP.err b/tests/core/saved/test_13.XP.err
deleted file mode 100644
index e69de29bb2d1..000000000000
--- a/tests/core/saved/test_13.XP.err
+++ /dev/null
diff --git a/tests/core/saved/test_13.XP.out b/tests/core/saved/test_13.XP.out
deleted file mode 100644
index 32a32db44e72..000000000000
--- a/tests/core/saved/test_13.XP.out
+++ /dev/null
@@ -1,155 +0,0 @@
-<top>
- <data>
- <entry>
- <name>xx-00000000</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000001</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000002</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000003</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000004</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000005</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000006</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000007</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000008</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <entry>
- <name>xx-00000009</name>
- <inode>12</inode>
- <blocks>1234</blocks>
- <mode>mode</mode>
- <mode_octal>660</mode_octal>
- <links>12</links>
- <user>phil</user>
- <group>phil</group>
- <type>regular</type>
- <flags>123</flags>
- <label>1234</label>
- <size>12345</size>
- <modify-time value="1644355825">1644355825</modify-time>
- </entry>
- <hits>72</hits>
- </data>
-</top>
diff --git a/tests/core/test_01.c b/tests/core/test_01.c
index 71cde5a207db..8311efbfc87c 100644
--- a/tests/core/test_01.c
+++ b/tests/core/test_01.c
@@ -114,8 +114,6 @@ main (int argc, char **argv)
xo_attr("test-attr", "attr-value");
xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
"gum", 1412);
- xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
- "sum", 4121);
xo_emit("Connecting to {:host}.{:domain}...\n", "my-box", "example.com");
@@ -257,14 +255,6 @@ main (int argc, char **argv)
"/some/file", (int) 0640, 8, 1,
10, "user", 12, "group");
- /* Test retain flag for dynamic data */
- xo_set_flags(NULL, XOF_RETAIN_ALL);
- char buf[] = "Testing...{:one/%d}...{:two/%d}...{:three/%d}\n";
- xo_emit(buf, 1, 2, 3);
- xo_emit(buf, 1, 2, 3);
- buf[0] = 'X';
- xo_emit(buf, 1, 2, 3);
-
xo_close_container_h(NULL, "top-level");
xo_finish();
diff --git a/tests/core/test_12.c b/tests/core/test_12.c
index 8fcc5419e138..32af2d211857 100644
--- a/tests/core/test_12.c
+++ b/tests/core/test_12.c
@@ -24,7 +24,6 @@ main (int argc, char **argv)
int mon = 0;
xo_emit_flags_t flags = XOEF_RETAIN;
int opt_color = 1;
- const char *map = NULL;
xo_set_program("test_12");
@@ -51,18 +50,12 @@ main (int argc, char **argv)
xo_set_flags(NULL, XOF_INFO);
else if (xo_streq(argv[argc], "no-retain"))
flags &= ~XOEF_RETAIN;
- else if (xo_streq(argv[argc], "map")) {
- if (argv[argc + 1])
- map = argv[++argc];
- } else if (xo_streq(argv[argc], "big")) {
+ else if (xo_streq(argv[argc], "big")) {
if (argv[argc + 1])
count = atoi(argv[++argc]);
}
}
- if (map)
- xo_map_add_file(NULL, map);
-
xo_set_flags(NULL, XOF_UNITS); /* Always test w/ this */
if (opt_color)
xo_set_flags(NULL, XOF_COLOR); /* Force color output */
@@ -88,17 +81,11 @@ main (int argc, char **argv)
xo_emit_f(flags, fmt2, "left", "blue", "blue", 3, 45);
}
- xo_close_list("thing");
-
xo_open_container("2by4");
xo_emit("There is {:4x4} in {:2morrow}\n", "truck", "tomorrow");
xo_close_container("2by4");
- xo_open_container("tagÜÖÄ");
- xo_emit("The {:cölor} is {:säfe}\n", "blue", "yes");
- xo_close_container("tagÜÖÄ");
-
xo_close_container("data");
xo_close_container_h(NULL, "top");
diff --git a/tests/core/test_13.c b/tests/core/test_13.c
deleted file mode 100644
index 17218e234010..000000000000
--- a/tests/core/test_13.c
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (c) 2022, Juniper Networks, Inc.
- * All rights reserved.
- * This SOFTWARE is licensed under the LICENSE provided in the
- * ../Copyright file. By downloading, installing, copying, or otherwise
- * using the SOFTWARE, you agree to be bound by the terms of that
- * LICENSE.
- * Phil Shafer, Feb 2022
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <time.h>
-#include <langinfo.h>
-#include <unistd.h>
-#include <wchar.h>
-#include <fcntl.h>
-
-#include "xo_config.h"
-#include "xo.h"
-#include "xo_encoder.h"
-
-static size_t padding_for_month[12];
-static size_t month_max_size = 0;
-
-static const char *
-get_abmon(int mon)
-{
-
- switch (mon) {
- case 0: return (nl_langinfo(ABMON_1));
- case 1: return (nl_langinfo(ABMON_2));
- case 2: return (nl_langinfo(ABMON_3));
- case 3: return (nl_langinfo(ABMON_4));
- case 4: return (nl_langinfo(ABMON_5));
- case 5: return (nl_langinfo(ABMON_6));
- case 6: return (nl_langinfo(ABMON_7));
- case 7: return (nl_langinfo(ABMON_8));
- case 8: return (nl_langinfo(ABMON_9));
- case 9: return (nl_langinfo(ABMON_10));
- case 10: return (nl_langinfo(ABMON_11));
- case 11: return (nl_langinfo(ABMON_12));
- }
-
- /* should never happen */
- abort();
-}
-
-static void
-compute_abbreviated_month_size(void)
-{
- int i;
- size_t width;
- size_t months_width[12];
-
- for (i = 0; i < 12; i++) {
- width = strlen(get_abmon(i));
- if (width == (size_t)-1) {
- month_max_size = -1;
- return;
- }
- months_width[i] = width;
- if (width > month_max_size)
- month_max_size = width;
- }
-
- for (i = 0; i < 12; i++)
- padding_for_month[i] = month_max_size - months_width[i];
-}
-
-static void
-printsize(const char *field, size_t width, off_t bytes)
-{
- char fmt[BUFSIZ];
-
- /* This format assignment needed to work round gcc bug. */
- snprintf(fmt, sizeof(fmt), "{:%s/%%%dj%sd} ",
- field, (int) width, "");
- xo_emit_f(XOEF_NO_RETAIN, fmt, (intmax_t) bytes);
-}
-
-static size_t
-ls_strftime(char *str, size_t len, const char *fmt, const struct tm *tm)
-{
- char *posb, nfmt[BUFSIZ];
- const char *format = fmt;
- size_t ret;
-
- if ((posb = strstr(fmt, "%b")) != NULL) {
- if (month_max_size > 0) {
- snprintf(nfmt, sizeof(nfmt), "%.*s%s%*s%s",
- (int)(posb - fmt), fmt,
- get_abmon(tm->tm_mon),
- (int)padding_for_month[tm->tm_mon],
- "",
- posb + 2);
- format = nfmt;
- }
- }
- ret = strftime(str, len, format, tm);
- return (ret);
-}
-
-static void
-printtime(const char *field, time_t ftime)
-{
- char longstring[80];
- char fmt[BUFSIZ];
- static time_t now = 0;
- const char *format;
- static int d_first = -1;
-
- if (d_first < 0)
- d_first = 1;
- if (now == 0)
- now = time(NULL);
-
-#define SIXMONTHS ((365 / 2) * 86400)
- if (1)
- /* mmm dd hh:mm || dd mmm hh:mm */
- format = d_first ? "%e %b %R" : "%b %e %R";
- else
- /* mmm dd yyyy || dd mmm yyyy */
- format = d_first ? "%e %b %Y" : "%b %e %Y";
- ls_strftime(longstring, sizeof(longstring), format, localtime(&ftime));
-
- snprintf(fmt, sizeof(fmt), "{d:%s/%%hs} ", field);
- xo_attr("value", "%ld", (long) ftime);
- xo_emit_f(XOEF_NO_RETAIN, fmt, longstring);
- snprintf(fmt, sizeof(fmt), "{en:%s/%%ld}", field);
- xo_emit_f(XOEF_NO_RETAIN, fmt, (long) ftime);
-}
-
-
-int
-main (int argc, char **argv)
-{
- int i, count = 10;
- int mon = 0;
- xo_emit_flags_t flags = XOF_RETAIN_ALL;
- int opt_color = 1;
-
- xo_set_program("test_13");
-
- argc = xo_parse_args(argc, argv);
- if (argc < 0)
- return 1;
-
- compute_abbreviated_month_size();
-
- for (argc = 1; argv[argc]; argc++) {
- if (xo_streq(argv[argc], "xml"))
- xo_set_style(NULL, XO_STYLE_XML);
- else if (xo_streq(argv[argc], "json"))
- xo_set_style(NULL, XO_STYLE_JSON);
- else if (xo_streq(argv[argc], "text"))
- xo_set_style(NULL, XO_STYLE_TEXT);
- else if (xo_streq(argv[argc], "html"))
- xo_set_style(NULL, XO_STYLE_HTML);
- else if (xo_streq(argv[argc], "no-color"))
- opt_color = 0;
- else if (xo_streq(argv[argc], "pretty"))
- xo_set_flags(NULL, XOF_PRETTY);
- else if (xo_streq(argv[argc], "xpath"))
- xo_set_flags(NULL, XOF_XPATH);
- else if (xo_streq(argv[argc], "info"))
- xo_set_flags(NULL, XOF_INFO);
- else if (xo_streq(argv[argc], "no-retain"))
- flags &= ~XOF_RETAIN_ALL;
- else if (xo_streq(argv[argc], "big")) {
- if (argv[argc + 1]) {
- const char *cp = argv[++argc];
- char *ep;
- count = strtoul(cp, &ep, 0);
- if (ep && *ep) {
- const char suff[] = "kmgt";
- unsigned long mult[]
- = { 1000, 1000000, 1000000000, 1000000000000 };
- char *sp = strchr(suff, *ep);
- if (sp) {
- count *= mult[sp - suff];
- }
- }
- }
- } else if (xo_streq(argv[argc], "null")) {
- int fd = open("/dev/null", O_WRONLY);
- if (fd >= 0) {
- close(1);
- dup2(fd, 1);
- }
- }
- }
-
- xo_set_flags(NULL, XOF_UNITS); /* Always test w/ this */
- if (opt_color)
- xo_set_flags(NULL, XOF_COLOR); /* Force color output */
- xo_set_file(stdout);
-
- xo_open_container("top");
- xo_open_container("data");
-
- if (flags != 0)
- xo_set_flags(NULL, flags);
-
- xo_open_list("entry");
-
- for (i = 0; i < count; i++) {
- xo_open_instance("entry");
-
- char name[80];
- snprintf(name, sizeof(name), "xx-%08u", i);
-
- xo_emitr("{ke:name/%hs}", name);
-
- xo_emitr("{t:inode/%*ju} ", 3, 12);
- xo_emitr("{t:blocks/%*jd} ", 4, 1234);
-
- xo_emitr("{t:mode/%s}{e:mode_octal/%03o} {t:links/%*ju} {t:user/%-*s} {t:group/%-*s} ",
- "mode", 0660, 2, (uintmax_t) 12,
- 4, "phil", 4, "phil");
-
-
- xo_emitr("{e:type/%s}", "regular");
-
- xo_emitr("{:flags/%-*s} ", 3, "123");
- xo_emitr("{t:label/%-*s} ", 4, "1234");
- printsize("size", 5, 12345);
- printtime("modify-time", 1644355825);
-
- xo_emitr("{dk:name/%hs}", name);
-
- xo_close_instance("entry");
- xo_emit("\n");
- }
-
- xo_close_list("entry");
-
- xo_emit("{Lwc:hits}{:hits/%ld}\n", xo_retain_get_hits());
-
- xo_close_container("data");
- xo_close_container_h(NULL, "top");
-
- xo_finish();
-
- return 0;
-}
diff --git a/xo/xo.c b/xo/xo.c
index e682cbf4aaf9..6d45c9ce5bae 100644
--- a/xo/xo.c
+++ b/xo/xo.c
@@ -95,10 +95,9 @@ static xo_ssize_t
formatter (xo_handle_t *xop, char *buf, xo_ssize_t bufsiz,
const char *fmt, va_list vap UNUSED)
{
- /* printf-style formatting flags, currently ignored */
- int lflag UNUSED = 0, hflag UNUSED = 0, jflag UNUSED = 0,
- tflag UNUSED = 0, zflag UNUSED = 0, qflag UNUSED = 0;
- int star1 = 0, star2 = 0;
+ int lflag UNUSED = 0; /* Parse long flag, though currently ignored */
+ int hflag = 0, jflag = 0, tflag = 0,
+ zflag = 0, qflag = 0, star1 = 0, star2 = 0;
int rc = 0;
int w1 = 0, w2 = 0;
const char *cp;