Import libxo-1.3.0:

- move from "oxtradoc" to RST/Sphinx documentation
- new "csv" encoder, which allows path and leaf lists
- address warnings from PVS-Stdio tool
- add "xolint" detected errors to the documentation
This commit is contained in:
Phil Shafer 2019-11-07 03:57:04 +00:00
commit 76afb20c58
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=354427
99 changed files with 2678 additions and 32097 deletions

View file

@ -32,7 +32,6 @@ errors:
docs:
@(cd doc ; ${MAKE} docs)
DIST_FILES_DIR = ~/Dropbox/dist-files/
GH_PAGES_DIR = gh-pages/
GH_PAGES_DIR_VER = gh-pages/${PACKAGE_VERSION}
@ -49,18 +48,20 @@ upload: dist upload-docs upload-xohtml-files
@echo "Remember to run:"
@echo " gt tag ${PACKAGE_VERSION}"
upload-docs: docs
@echo "Uploading libxo-manual.html ... "
@-[ -d ${GH_PAGES_DIR} ] \
&& echo "Updating manual on gh-pages ..." \
&& mkdir -p ${GH_PAGES_DIR_VER} \
&& cp doc/libxo-manual.html ${GH_PAGES_DIR} \
&& cp doc/libxo-manual.html ${GH_PAGES_DIR_VER} \
upload-docs: docs upload-html
upload-html:
@echo "Uploading html ... "
@-[ -d ${GH_PAGES_DIR} -a -d doc/html ] \
&& echo "Updating html on gh-pages ..." \
&& mkdir -p ${GH_PAGES_DIR_VER}/html \
&& cp doc/top-link.html ${GH_PAGES_DIR}/libxo.html \
&& cp -r doc/html/* ${GH_PAGES_DIR_VER}/html/ \
&& (cd ${GH_PAGES_DIR} \
&& git add ${PACKAGE_VERSION} \
&& git add libxo-manual.html \
&& git add libxo.html \
&& git add ${PACKAGE_VERSION}/html \
&& git commit -m 'new docs' \
libxo-manual.html ${PACKAGE_VERSION} \
libxo.html ${PACKAGE_VERSION}/html \
&& git push origin gh-pages ) ; true
upload-xohtml-files:

View file

@ -10,6 +10,9 @@ 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.
Imagine a simplified ``wc`` that emits its output fields in a single
xo_emit call:
```
xo_emit(" {:lines/%7ju/%ju} {:words/%7ju/%ju} "
"{:characters/%7ju/%ju}{d:filename/%s}\n",

View file

@ -12,7 +12,7 @@
#
AC_PREREQ(2.2)
AC_INIT([libxo], [1.0.4], [phil@juniper.net])
AC_INIT([libxo], [1.3.0], [phil@juniper.net])
AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
# Support silent build rules. Requires at least automake-1.11.
@ -452,6 +452,7 @@ AC_CONFIG_FILES([
libxo/add.man
encoder/Makefile
encoder/cbor/Makefile
encoder/csv/Makefile
encoder/test/Makefile
xo/Makefile
xolint/Makefile
@ -459,6 +460,7 @@ AC_CONFIG_FILES([
xopo/Makefile
packaging/libxo.pc
doc/Makefile
doc/top-link.html
tests/Makefile
tests/core/Makefile
tests/gettext/Makefile

View file

@ -8,68 +8,22 @@
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
if HAVE_OXTRADOC
OXTRADOC_DIR = ${SLAX_OXTRADOCDIR}
OXTRADOC_PREFIX = ${OXTRADOC_DIR}
OXTRADOC = ${OXTRADOC_DIR}/oxtradoc
SLAXPROC_BINDIR = ${SLAX_BINDIR}
doc docs: xolint.rst html
XML2RFC = ${OXTRADOC_DIR}/xml2rfc.tcl
XML2HTMLDIR = ${OXTRADOC_DIR}
XML2HTMLBIN = ${XML2HTMLDIR}/rfc2629-to-html.slax
SLAXPROC = ${SLAX_BINDIR}/slaxproc
#
# The contents of xolint.rst is generated based on xolint.pl, since we
# really want this to be self-documenting. But readthedocs.org needs this
# data to be _in_ repo. So we generate this file on command only, and
# the developer needs to commit any changes.
#
SLAXPROC_ARGS = \
-a oxtradoc-dir ${OXTRADOC_DIR} \
-a oxtradoc-install-dir ${OXTRADOC_DIR} \
-a anchor-prefix docs
xolint.rst: ${top_srcdir}/xolint/xolint.pl
perl ${top_srcdir}/xolint/xolint.pl -D > ${top_srcdir}/doc/xolint.rst
SLAXPROC_ARGS_INLINE = \
-a oxtradoc-inline yes
SLAXPROC_ARGS += ${SLAXPROC_ARGS_INLINE}
XML2HTML = \
${SLAXPROC} -g -e -I ${OXTRADOC_DIR} -I . \
${SLAXPROC_ARGS} \
${XML2HTMLBIN}
OX_ARGS = -P ${OXTRADOC_PREFIX} -L ${OXTRADOC_PREFIX}
OX_ARGS += -S ${SLAXPROC} -p doc
OX_CMD = ${PERL} ${PERLOPTS} ${OXTRADOC} ${OX_ARGS}
OXTRADOC_CMD = ${OX_CMD}
OUTPUT = libxo-manual
INPUT = libxo
EXTRA_DIST = \
${INPUT}.txt \
${OUTPUT}.html \
${OUTPUT}.txt
doc docs: ${OUTPUT}.txt ${OUTPUT}.html
${OUTPUT}.txt: ${INPUT}.txt ${OXTRADOC} xolint.txt
${OXTRADOC_CMD} -m text -o $@ $<
${OUTPUT}.html: ${INPUT}.txt ${OXTRADOC} ${XML2HTMLBIN} xolint.txt
${OXTRADOC_CMD} -m html -o $@ $<
xolint.txt: ${top_srcdir}/xolint/xolint.pl
perl ${top_srcdir}/xolint/xolint.pl -D > xolint.txt
CLEANFILES = \
xolint.txt \
${INPUT}.xml \
${INPUT}.fxml \
${OUTPUT}.txt \
${OUTPUT}.html
else
doc docs:
@${ECHO} "The 'oxtradoc' tool is not installed; see libslax.org"
endif
SPHINX = python3.4 -msphinx
SPHINX = python3 -msphinx
html sphinx sphinx-html:
${SPHINX} -M html ${srcdir} .
${SPHINX} -M html ${srcdir} . -N -E
singlehtml:
${SPHINX} -M singlehtml ${srcdir} . -N -E

View file

@ -1,4 +1,4 @@
.. index: API
.. index:: API
The libxo API
=============
@ -155,14 +155,14 @@ 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
=============== =========================
=============== =========================
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.
@ -256,26 +256,26 @@ 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
=================== =========================================
=================== =========================================
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.
@ -300,12 +300,12 @@ 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
=============== =========================================
=============== =========================================
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
@ -317,11 +317,11 @@ 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
=============== =========================================
=============== =========================================
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
@ -1308,52 +1308,52 @@ 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
============= =======================================================
============= =======================================================
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
=============== =======================================================
=============== =======================================================
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
============ ====================================================
============ ====================================================
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
@ -1588,26 +1588,26 @@ 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
======================= =======================================
======================= =======================================
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,

View file

@ -21,6 +21,14 @@
# 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 ------------------------------------------------
@ -47,7 +55,7 @@
# General information about the project.
project = 'libxo'
copyright = '2017, Juniper Networks'
copyright = '2017-2019, Juniper Networks Inc'
author = 'Phil Shafer'
default_role = 'code'
primary_domain = 'c'
@ -58,9 +66,9 @@
# built documents.
#
# The short X.Y version.
version = '0.8.4'
#version = 'develop'
# The full version, including alpha/beta/rc tags.
release = '0.8.4'
release = version
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.

View file

@ -0,0 +1,269 @@
.. 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 (':') and one of more options,
separated by a plus sign "+"::
df --libxo encoder=csv:path=filesystem+leaf=name+no-header
This example 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.
.. _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.

View file

@ -202,8 +202,7 @@ 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.
.. ignore for now, since we want can't have generated content
What does this message mean?
----------------------------
What does this message mean?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!include-file xolint.txt
.. include:: xolint.rst

View file

@ -53,48 +53,48 @@ 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'
===== ================= ======================
===== ================= ======================
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
===== ============= ====================
===== ============= ====================
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
@ -122,14 +122,14 @@ 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
======== ================== ===============================
======== ================== ===============================
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"
@ -266,21 +266,21 @@ incompatible with printf-like testing:
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
================== ========================
================== ========================
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
@ -305,16 +305,16 @@ 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
================== ========================
================== ========================
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

View file

@ -8,26 +8,26 @@ 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
=== =============== ===================================================
=== =============== ===================================================
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")

View file

@ -8,23 +8,25 @@ 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
=== ============== =================================================
=== ============== =================================================
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",
@ -80,36 +82,36 @@ foreground and background colors, respectively::
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
=============== =================================================
=============== =================================================
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
========= ============================================
========= ============================================
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

View file

@ -38,6 +38,7 @@ libxo ships as part of FreeBSD.
field-modifiers
field-formatting
api
encoders
xo
xolint
xohtml

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -33,36 +33,36 @@ 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)
=============== =======================================================
=============== =======================================================
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:
@ -94,25 +94,25 @@ 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)
======== =============================================
======== =============================================
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
@ -145,7 +145,7 @@ 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 "+"s::
"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
@ -159,6 +159,6 @@ to green (the third mapping)::
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 "+"s::
mapping, skipping the first four mappings with bare plus signs ("+")::
--libxo colors=++++yellow/yellow

View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Refresh" content="0; url=@LIBXO_VERSION@/html/index.html" />
</head>
<body>
<p>The current libxo version is <a href="@LIBXO_VERSION@/html/index.html">@LIBXO_VERSION@</a>.</p>
</body>
</html>

View file

@ -1,5 +1,5 @@
.. index:: --libxo, xo
.. _xo:
The "xo" Utility
================
@ -12,9 +12,7 @@ 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 `LIBXO_OPTIONS`_ environment variable.
.. _`LIBXO_OPTIONS`: :ref:`libxo-options`
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::
@ -23,12 +21,15 @@ a set of zero or more arguments used to supply data for that string::
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>
@ -54,6 +55,7 @@ by the '/' character::
</b>
</a>
</top>
JSON:
"top": {
"a": {
@ -72,17 +74,19 @@ 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;
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": {
@ -102,14 +106,18 @@ 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;
::
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>
@ -118,6 +126,7 @@ braces for JSON output.
<div class="text">and then </div>
<div class="data" data-tag="tag">value2</div>
</div>
XML:
<top>
<data>
@ -125,6 +134,7 @@ braces for JSON output.
<tag>value2</tag>
</data>
</top>
JSON:
{
"top": {
@ -150,7 +160,7 @@ 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:
instances::
opts="--json"
xo $opts --open-list machine
@ -168,6 +178,15 @@ 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
--------------------
@ -181,6 +200,7 @@ Command Line Options
--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)
@ -197,7 +217,7 @@ Command Line Options
--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);
--xpath Add XPath data to HTML output)
Example
-------
@ -206,6 +226,9 @@ Example
% xo 'The {:product} is {:status}\n' stereo "in route"
The stereo is in route
% ./xo/xo -p -X 'The {:product} is {:status}\n' stereo "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>

View file

@ -17,13 +17,13 @@ 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
============== ===================================================
============== ===================================================
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

View file

@ -1,40 +1,444 @@
'A percent sign appearing in text is a literal'
+++++++++++++++++++++++++++++++++++++++++++++++
xolint
======
The message "A percent sign appearing in text is a literal" can be caused by code like:
`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:
xo_emit("cost: %d", cost);
============ ===================================================
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
============ ===================================================
This code should be replaced with code like:
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}");
xo_emit("{L:cost}: {:cost/%d}", cost);
The "-I" option will generate a table of `xo_info_t`_ structures,
suitable for inclusion in source code.
This can be a bit surprising and could be a field that was not
properly converted to a libxo-style format string.
.. _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.
'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.

View file

@ -20,13 +20,13 @@ 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
=========== =================================
=========== =================================
Option Meaning
=========== =================================
-o <file> Output file name
-f <file> Use the given .po file as input
-s <text> Simplify a format string
=========== =================================
::

View file

@ -1,9 +1,12 @@
#
# Copyright 2015, Juniper Networks, Inc.
# Copyright 2015-2019, 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.
SUBDIRS = cbor test
SUBDIRS = \
cbor \
csv \
test

View file

@ -208,9 +208,9 @@ cbor_content (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp,
unsigned offset = xo_buf_offset(xbp);
if (value == NULL || *value == '\0' || strcmp(value, "true") == 0)
if (value == NULL || *value == '\0' || xo_streq(value, "true"))
cbor_append(xop, cbor, &cbor->c_data, CBOR_TRUE, 0, NULL);
else if (strcmp(value, "false") == 0)
else if (xo_streq(value, "false"))
cbor_append(xop, cbor, &cbor->c_data, CBOR_FALSE, 0, NULL);
else {
int negative = 0;
@ -360,6 +360,7 @@ int
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
{
arg->xei_handler = cbor_handler;
arg->xei_version = XO_ENCODER_VERSION;
return 0;
}

View file

@ -0,0 +1,51 @@
#
# $Id$
#
# Copyright 2015-2019, 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.
if LIBXO_WARNINGS_HIGH
LIBXO_WARNINGS = HIGH
endif
if HAVE_GCC
GCC_WARNINGS = yes
endif
include ${top_srcdir}/warnings.mk
enc_csvincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir}/libxo \
-I${top_builddir}/libxo \
${WARNINGS}
LIBNAME = libenc_csv
pkglib_LTLIBRARIES = libenc_csv.la
LIBS = \
-L${top_builddir}/libxo -lxo
LDADD = ${top_builddir}/libxo/libxo.la
libenc_csv_la_SOURCES = \
enc_csv.c
pkglibdir = ${XO_ENCODERDIR}
UGLY_NAME = csv.enc
install-exec-hook:
@DLNAME=`sh -c '. ./libenc_csv.la ; echo $$dlname'` ; \
if [ x"$$DLNAME" = x ]; \
then DLNAME=${LIBNAME}.${XO_LIBEXT}; fi ; \
if [ "$(build_os)" = "cygwin" ]; \
then DLNAME="../bin/$$DLNAME"; fi ; \
echo Install link $$DLNAME "->" ${UGLY_NAME} "..." ; \
mkdir -p ${DESTDIR}${XO_ENCODERDIR} ; \
cd ${DESTDIR}${XO_ENCODERDIR} \
&& chmod +w . \
&& rm -f ${UGLY_NAME} \
&& ${LN_S} $$DLNAME ${UGLY_NAME}

View file

@ -0,0 +1,826 @@
/*
* Copyright (c) 2015, 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, August 2015
*/
/*
* CSV encoder generates comma-separated value files for specific
* subsets of data. This is not (and cannot be) a generalized
* facility, but for specific subsets of data, CSV data can be
* reasonably generated. For example, the df XML content:
* <filesystem>
* <name>procfs</name>
* <total-blocks>4</total-blocks>
* <used-blocks>4</used-blocks>
* <available-blocks>0</available-blocks>
* <used-percent>100</used-percent>
* <mounted-on>/proc</mounted-on>
* </filesystem>
*
* could be represented as:
*
* #+name,total-blocks,used-blocks,available-blocks,used-percent,mounted-on
* procfs,4,4,0,100,/proc
*
* Data is then constrained to be sibling leaf values. In addition,
* singular leafs can also be matched. The costs include recording
* the specific leaf names (to ensure consistency) and some
* buffering.
*
* Some escaping is needed for CSV files, following the rules of RFC4180:
*
* - Fields containing a line-break, double-quote or commas should be
* quoted. (If they are not, the file will likely be impossible to
* process correctly).
* - A (double) quote character in a field must be represented by two
* (double) quote characters.
* - Leading and trialing whitespace require fields be quoted.
*
* Cheesy, but simple. The RFC also requires MS-DOS end-of-line, which
* we only do with the "dos" option. Strange that we still live in a
* DOS-friendly world, but then again, we make spaceships based on the
* horse butts (http://www.astrodigital.org/space/stshorse.html).
*/
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include "xo.h"
#include "xo_encoder.h"
#include "xo_buf.h"
#ifndef UNUSED
#define UNUSED __attribute__ ((__unused__))
#endif /* UNUSED */
/*
* The CSV encoder has three moving parts:
*
* - The path holds the path we are matching against
* - This is given as input via "options" and does not change
*
* - The stack holds the current names of the open elements
* - The "open" operations push, while the "close" pop
* - Turns out, at this point, the stack is unused, but I've
* left "drippings" in the code because I see this as useful
* for future features (under CSV_STACK_IS_NEEDED).
*
* - The leafs record the current set of leaf
* - A key from the parent list counts as a leaf (unless CF_NO_KEYS)
* - Once the path is matched, all other leafs at that level are leafs
* - Leafs are recorded to get the header comment accurately recorded
* - Once the first line is emited, the set of leafs _cannot_ change
*
* We use offsets into the buffers, since we know they can be
* realloc'd out from under us, as the size increases. The 'path'
* is fixed, we allocate it once, so it doesn't need offsets.
*/
typedef struct path_frame_s {
char *pf_name; /* Path member name; points into c_path_buf */
uint32_t pf_flags; /* Flags for this path element (PFF_*) */
} path_frame_t;
typedef struct stack_frame_s {
ssize_t sf_off; /* Element name; offset in c_stack_buf */
uint32_t sf_flags; /* Flags for this frame (SFF_*) */
} stack_frame_t;
/* Flags for sf_flags */
typedef struct leaf_s {
ssize_t f_name; /* Name of leaf; offset in c_name_buf */
ssize_t f_value; /* Value of leaf; offset in c_value_buf */
uint32_t f_flags; /* Flags for this value (FF_*) */
#ifdef CSV_STACK_IS_NEEDED
ssize_t f_depth; /* Depth of stack when leaf was recorded */
#endif /* CSV_STACK_IS_NEEDED */
} leaf_t;
/* Flags for f_flags */
#define LF_KEY (1<<0) /* Leaf is a key */
#define LF_HAS_VALUE (1<<1) /* Value has been set */
typedef struct csv_private_s {
uint32_t c_flags; /* Flags for this encoder */
/* The path for which we select leafs */
char *c_path_buf; /* Buffer containing path members */
path_frame_t *c_path; /* Array of path members */
ssize_t c_path_max; /* Depth of c_path[] */
ssize_t c_path_cur; /* Current depth in c_path[] */
/* A stack of open elements (xo_op_list, xo_op_container) */
#if CSV_STACK_IS_NEEDED
xo_buffer_t c_stack_buf; /* Buffer used for stack content */
stack_frame_t *c_stack; /* Stack of open tags */
ssize_t c_stack_max; /* Maximum stack depth */
#endif /* CSV_STACK_IS_NEEDED */
ssize_t c_stack_depth; /* Current stack depth */
/* List of leafs we are emitting (to ensure consistency) */
xo_buffer_t c_name_buf; /* String buffer for leaf names */
xo_buffer_t c_value_buf; /* String buffer for leaf values */
leaf_t *c_leaf; /* List of leafs */
ssize_t c_leaf_depth; /* Current depth of c_leaf[] (next free) */
ssize_t c_leaf_max; /* Max depth of c_leaf[] */
xo_buffer_t c_data; /* Buffer for creating data */
} csv_private_t;
#define C_STACK_MAX 32 /* default c_stack_max */
#define C_LEAF_MAX 32 /* default c_leaf_max */
/* Flags for this structure */
#define CF_HEADER_DONE (1<<0) /* Have already written the header */
#define CF_NO_HEADER (1<<1) /* Do not generate header */
#define CF_NO_KEYS (1<<2) /* Do not generate excess keys */
#define CF_VALUE_ONLY (1<<3) /* Only generate the value */
#define CF_DOS_NEWLINE (1<<4) /* Generate CR-NL, just like MS-DOS */
#define CF_LEAFS_DONE (1<<5) /* Leafs are already been recorded */
#define CF_NO_QUOTES (1<<6) /* Do not generate quotes */
#define CF_RECORD_DATA (1<<7) /* Record all sibling leafs */
#define CF_DEBUG (1<<8) /* Make debug output */
#define CF_HAS_PATH (1<<9) /* A "path" option was provided */
/*
* A simple debugging print function, similar to psu_dbg. Controlled by
* the undocumented "debug" option.
*/
static void
csv_dbg (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED,
const char *fmt, ...)
{
if (csv == NULL || !(csv->c_flags & CF_DEBUG))
return;
va_list vap;
va_start(vap, fmt);
vfprintf(stderr, fmt, vap);
va_end(vap);
}
/*
* Create the private data for this handle, initialize it, and record
* the pointer in the handle.
*/
static int
csv_create (xo_handle_t *xop)
{
csv_private_t *csv = xo_realloc(NULL, sizeof(*csv));
if (csv == NULL)
return -1;
bzero(csv, sizeof(*csv));
xo_buf_init(&csv->c_data);
xo_buf_init(&csv->c_name_buf);
xo_buf_init(&csv->c_value_buf);
#ifdef CSV_STACK_IS_NEEDED
xo_buf_init(&csv->c_stack_buf);
#endif /* CSV_STACK_IS_NEEDED */
xo_set_private(xop, csv);
return 0;
}
/*
* Clean up and release any data in use by this handle
*/
static void
csv_destroy (xo_handle_t *xop UNUSED, csv_private_t *csv)
{
/* Clean up */
xo_buf_cleanup(&csv->c_data);
xo_buf_cleanup(&csv->c_name_buf);
xo_buf_cleanup(&csv->c_value_buf);
#ifdef CSV_STACK_IS_NEEDED
xo_buf_cleanup(&csv->c_stack_buf);
#endif /* CSV_STACK_IS_NEEDED */
if (csv->c_leaf)
xo_free(csv->c_leaf);
if (csv->c_path_buf)
xo_free(csv->c_path_buf);
}
/*
* Return the element name at the top of the path stack. This is the
* item that we are currently trying to match on.
*/
static const char *
csv_path_top (csv_private_t *csv, ssize_t delta)
{
if (!(csv->c_flags & CF_HAS_PATH) || csv->c_path == NULL)
return NULL;
ssize_t cur = csv->c_path_cur + delta;
if (cur < 0)
return NULL;
return csv->c_path[cur].pf_name;
}
/*
* Underimplemented stack functionality
*/
static inline void
csv_stack_push (csv_private_t *csv UNUSED, const char *name UNUSED)
{
#ifdef CSV_STACK_IS_NEEDED
csv->c_stack_depth += 1;
#endif /* CSV_STACK_IS_NEEDED */
}
/*
* Underimplemented stack functionality
*/
static inline void
csv_stack_pop (csv_private_t *csv UNUSED, const char *name UNUSED)
{
#ifdef CSV_STACK_IS_NEEDED
csv->c_stack_depth -= 1;
#endif /* CSV_STACK_IS_NEEDED */
}
/* Flags for csv_quote_flags */
#define QF_NEEDS_QUOTES (1<<0) /* Needs to be quoted */
#define QF_NEEDS_ESCAPE (1<<1) /* Needs to be escaped */
/*
* Determine how much quote processing is needed. The details of the
* quoting rules are given at the top of this file. We return a set
* of flags, indicating what's needed.
*/
static uint32_t
csv_quote_flags (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED,
const char *value)
{
static const char quoted[] = "\n\r\",";
static const char escaped[] = "\"";
if (csv->c_flags & CF_NO_QUOTES) /* User doesn't want quotes */
return 0;
size_t len = strlen(value);
uint32_t rc = 0;
if (strcspn(value, quoted) != len)
rc |= QF_NEEDS_QUOTES;
else if (isspace((int) value[0])) /* Leading whitespace */
rc |= QF_NEEDS_QUOTES;
else if (isspace((int) value[len - 1])) /* Trailing whitespace */
rc |= QF_NEEDS_QUOTES;
if (strcspn(value, escaped) != len)
rc |= QF_NEEDS_ESCAPE;
csv_dbg(xop, csv, "csv: quote flags [%s] -> %x (%zu/%zu)\n",
value, rc, len, strcspn(value, quoted));
return rc;
}
/*
* Escape the string, following the rules in RFC4180
*/
static void
csv_escape (xo_buffer_t *xbp, const char *value, size_t len)
{
const char *cp, *ep, *np;
for (cp = value, ep = value + len; cp && cp < ep; cp = np) {
np = strchr(cp, '"');
if (np) {
np += 1;
xo_buf_append(xbp, cp, np - cp);
xo_buf_append(xbp, "\"", 1);
} else
xo_buf_append(xbp, cp, ep - cp);
}
}
/*
* Append a newline to the buffer, following the settings of the "dos"
* flag.
*/
static void
csv_append_newline (xo_buffer_t *xbp, csv_private_t *csv)
{
if (csv->c_flags & CF_DOS_NEWLINE)
xo_buf_append(xbp, "\r\n", 2);
else
xo_buf_append(xbp, "\n", 1);
}
/*
* Create a 'record' of 'fields' from our recorded leaf values. If
* this is the first line and "no-header" isn't given, make a record
* containing the leaf names.
*/
static void
csv_emit_record (xo_handle_t *xop, csv_private_t *csv)
{
csv_dbg(xop, csv, "csv: emit: ...\n");
ssize_t fnum;
uint32_t quote_flags;
leaf_t *lp;
/* If we have no data, then don't bother */
if (csv->c_leaf_depth == 0)
return;
if (!(csv->c_flags & (CF_HEADER_DONE | CF_NO_HEADER))) {
csv->c_flags |= CF_HEADER_DONE;
for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) {
lp = &csv->c_leaf[fnum];
const char *name = xo_buf_data(&csv->c_name_buf, lp->f_name);
if (fnum != 0)
xo_buf_append(&csv->c_data, ",", 1);
xo_buf_append(&csv->c_data, name, strlen(name));
}
csv_append_newline(&csv->c_data, csv);
}
for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) {
lp = &csv->c_leaf[fnum];
const char *value;
if (lp->f_flags & LF_HAS_VALUE) {
value = xo_buf_data(&csv->c_value_buf, lp->f_value);
} else {
value = "";
}
quote_flags = csv_quote_flags(xop, csv, value);
if (fnum != 0)
xo_buf_append(&csv->c_data, ",", 1);
if (quote_flags & QF_NEEDS_QUOTES)
xo_buf_append(&csv->c_data, "\"", 1);
if (quote_flags & QF_NEEDS_ESCAPE)
csv_escape(&csv->c_data, value, strlen(value));
else
xo_buf_append(&csv->c_data, value, strlen(value));
if (quote_flags & QF_NEEDS_QUOTES)
xo_buf_append(&csv->c_data, "\"", 1);
}
csv_append_newline(&csv->c_data, csv);
/* We flush if either flush flag is set */
if (xo_get_flags(xop) & (XOF_FLUSH | XOF_FLUSH_LINE))
xo_flush_h(xop);
/* Clean out values from leafs */
for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) {
lp = &csv->c_leaf[fnum];
lp->f_flags &= ~LF_HAS_VALUE;
lp->f_value = 0;
}
xo_buf_reset(&csv->c_value_buf);
/*
* Once we emit the first line, our set of leafs is locked and
* cannot be changed.
*/
csv->c_flags |= CF_LEAFS_DONE;
}
/*
* Open a "level" of hierarchy, either a container or an instance. Look
* for a match in the path=x/y/z hierarchy, and ignore if not a match.
* If we're at the end of the path, start recording leaf values.
*/
static int
csv_open_level (xo_handle_t *xop UNUSED, csv_private_t *csv,
const char *name, int instance)
{
/* An new "open" event means we stop recording */
if (csv->c_flags & CF_RECORD_DATA) {
csv->c_flags &= ~CF_RECORD_DATA;
csv_emit_record(xop, csv);
return 0;
}
const char *path_top = csv_path_top(csv, 0);
/* If the top of the stack does not match the name, then ignore */
if (path_top == NULL) {
if (instance && !(csv->c_flags & CF_HAS_PATH)) {
csv_dbg(xop, csv, "csv: recording (no-path) ...\n");
csv->c_flags |= CF_RECORD_DATA;
}
} else if (xo_streq(path_top, name)) {
csv->c_path_cur += 1; /* Advance to next path member */
csv_dbg(xop, csv, "csv: match: [%s] (%zd/%zd)\n", name,
csv->c_path_cur, csv->c_path_max);
/* If we're all the way thru the path members, start recording */
if (csv->c_path_cur == csv->c_path_max) {
csv_dbg(xop, csv, "csv: recording ...\n");
csv->c_flags |= CF_RECORD_DATA;
}
}
/* Push the name on the stack */
csv_stack_push(csv, name);
return 0;
}
/*
* Close a "level", either a container or an instance.
*/
static int
csv_close_level (xo_handle_t *xop UNUSED, csv_private_t *csv, const char *name)
{
/* If we're recording, a close triggers an emit */
if (csv->c_flags & CF_RECORD_DATA) {
csv->c_flags &= ~CF_RECORD_DATA;
csv_emit_record(xop, csv);
}
const char *path_top = csv_path_top(csv, -1);
csv_dbg(xop, csv, "csv: close: [%s] [%s] (%zd)\n", name,
path_top ?: "", csv->c_path_cur);
/* If the top of the stack does not match the name, then ignore */
if (path_top != NULL && xo_streq(path_top, name)) {
csv->c_path_cur -= 1;
return 0;
}
/* Pop the name off the stack */
csv_stack_pop(csv, name);
return 0;
}
/*
* Return the index of a given leaf in the c_leaf[] array, where we
* record leaf values. If the leaf is new and we haven't stopped recording
* leafs, then make a new slot for it and record the name.
*/
static int
csv_leaf_num (xo_handle_t *xop UNUSED, csv_private_t *csv,
const char *name, xo_xff_flags_t flags)
{
ssize_t fnum;
leaf_t *lp;
xo_buffer_t *xbp = &csv->c_name_buf;
for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) {
lp = &csv->c_leaf[fnum];
const char *fname = xo_buf_data(xbp, lp->f_name);
if (xo_streq(fname, name))
return fnum;
}
/* If we're done with adding new leafs, then bail */
if (csv->c_flags & CF_LEAFS_DONE)
return -1;
/* This leaf does not exist yet, so we need to create it */
/* Start by checking if there's enough room */
if (csv->c_leaf_depth + 1 >= csv->c_leaf_max) {
/* Out of room; realloc it */
ssize_t new_max = csv->c_leaf_max * 2;
if (new_max == 0)
new_max = C_LEAF_MAX;
lp = xo_realloc(csv->c_leaf, new_max * sizeof(*lp));
if (lp == NULL)
return -1; /* No luck; bail */
/* Zero out the new portion */
bzero(&lp[csv->c_leaf_max], csv->c_leaf_max * sizeof(*lp));
/* Update csv data */
csv->c_leaf = lp;
csv->c_leaf_max = new_max;
}
lp = &csv->c_leaf[csv->c_leaf_depth++];
#ifdef CSV_STACK_IS_NEEDED
lp->f_depth = csv->c_stack_depth;
#endif /* CSV_STACK_IS_NEEDED */
lp->f_name = xo_buf_offset(xbp);
char *cp = xo_buf_cur(xbp);
xo_buf_append(xbp, name, strlen(name) + 1);
if (flags & XFF_KEY)
lp->f_flags |= LF_KEY;
csv_dbg(xop, csv, "csv: leaf: name: %zd [%s] [%s] %x\n",
fnum, name, cp, lp->f_flags);
return fnum;
}
/*
* Record a new value for a leaf
*/
static void
csv_leaf_set (xo_handle_t *xop UNUSED, csv_private_t *csv, leaf_t *lp,
const char *value)
{
xo_buffer_t *xbp = &csv->c_value_buf;
lp->f_value = xo_buf_offset(xbp);
lp->f_flags |= LF_HAS_VALUE;
char *cp = xo_buf_cur(xbp);
xo_buf_append(xbp, value, strlen(value) + 1);
csv_dbg(xop, csv, "csv: leaf: value: [%s] [%s] %x\n",
value, cp, lp->f_flags);
}
/*
* Record the requested set of leaf names. The input should be a set
* of leaf names, separated by periods.
*/
static int
csv_record_leafs (xo_handle_t *xop, csv_private_t *csv, const char *leafs_raw)
{
char *cp, *ep, *np;
ssize_t len = strlen(leafs_raw);
char *leafs_buf = alloca(len + 1);
memcpy(leafs_buf, leafs_raw, len + 1); /* Make local copy */
for (cp = leafs_buf, ep = leafs_buf + len; cp && cp < ep; cp = np) {
np = strchr(cp, '.');
if (np)
*np++ = '\0';
if (*cp == '\0') /* Skip empty names */
continue;
csv_dbg(xop, csv, "adding leaf: [%s]\n", cp);
csv_leaf_num(xop, csv, cp, 0);
}
/*
* Since we've been told explicitly what leafs matter, ignore the rest
*/
csv->c_flags |= CF_LEAFS_DONE;
return 0;
}
/*
* Record the requested path elements. The input should be a set of
* container or instances names, separated by slashes.
*/
static int
csv_record_path (xo_handle_t *xop, csv_private_t *csv, const char *path_raw)
{
int count;
char *cp, *ep, *np;
ssize_t len = strlen(path_raw);
char *path_buf = xo_realloc(NULL, len + 1);
memcpy(path_buf, path_raw, len + 1);
for (cp = path_buf, ep = path_buf + len, count = 2;
cp && cp < ep; cp = np) {
np = strchr(cp, '/');
if (np) {
np += 1;
count += 1;
}
}
path_frame_t *path = xo_realloc(NULL, sizeof(path[0]) * count);
if (path == NULL) {
xo_failure(xop, "allocation failure for path '%s'", path_buf);
return -1;
}
bzero(path, sizeof(path[0]) * count);
for (count = 0, cp = path_buf; cp && cp < ep; cp = np) {
path[count++].pf_name = cp;
np = strchr(cp, '/');
if (np)
*np++ = '\0';
csv_dbg(xop, csv, "path: [%s]\n", cp);
}
path[count].pf_name = NULL;
if (csv->c_path) /* In case two paths are given */
xo_free(csv->c_path);
if (csv->c_path_buf) /* In case two paths are given */
xo_free(csv->c_path_buf);
csv->c_path_buf = path_buf;
csv->c_path = path;
csv->c_path_max = count;
csv->c_path_cur = 0;
return 0;
}
/*
* Extract the option values. The format is:
* -libxo encoder=csv:kw=val+kw=val+kw=val,pretty,etc
*/
static int
csv_options (xo_handle_t *xop, csv_private_t *csv, const char *raw_opts)
{
ssize_t len = strlen(raw_opts);
char *options = alloca(len + 1);
memcpy(options, raw_opts, len);
options[len] = '\0';
char *cp, *ep, *np, *vp;
for (cp = options, ep = options + len + 1; cp && cp < ep; cp = np) {
np = strchr(cp, '+');
if (np)
*np++ = '\0';
vp = strchr(cp, '=');
if (vp)
*vp++ = '\0';
if (xo_streq(cp, "path")) {
/* Record the path */
if (vp != NULL && csv_record_path(xop, csv, vp))
return -1;
csv->c_flags |= CF_HAS_PATH; /* Yup, we have an explicit path now */
} else if (xo_streq(cp, "leafs")
|| xo_streq(cp, "leaf")
|| xo_streq(cp, "leaves")) {
/* Record the leafs */
if (vp != NULL && csv_record_leafs(xop, csv, vp))
return -1;
} else if (xo_streq(cp, "no-keys")) {
csv->c_flags |= CF_NO_KEYS;
} else if (xo_streq(cp, "no-header")) {
csv->c_flags |= CF_NO_HEADER;
} else if (xo_streq(cp, "value-only")) {
csv->c_flags |= CF_VALUE_ONLY;
} else if (xo_streq(cp, "dos")) {
csv->c_flags |= CF_DOS_NEWLINE;
} else if (xo_streq(cp, "no-quotes")) {
csv->c_flags |= CF_NO_QUOTES;
} else if (xo_streq(cp, "debug")) {
csv->c_flags |= CF_DEBUG;
} else {
xo_warn_hc(xop, -1,
"unknown encoder option value: '%s'", cp);
return -1;
}
}
return 0;
}
/*
* Handler for incoming data values. We just record each leaf name and
* value. The values are emittd when the instance is closed.
*/
static int
csv_data (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED,
const char *name, const char *value,
xo_xof_flags_t flags)
{
csv_dbg(xop, csv, "data: [%s]=[%s] %llx\n", name, value, (unsigned long long) flags);
if (!(csv->c_flags & CF_RECORD_DATA))
return 0;
/* Find the leaf number */
int fnum = csv_leaf_num(xop, csv, name, flags);
if (fnum < 0)
return 0; /* Don't bother recording */
leaf_t *lp = &csv->c_leaf[fnum];
csv_leaf_set(xop, csv, lp, value);
return 0;
}
/*
* The callback from libxo, passing us operations/events as they
* happen.
*/
static int
csv_handler (XO_ENCODER_HANDLER_ARGS)
{
int rc = 0;
csv_private_t *csv = private;
xo_buffer_t *xbp = csv ? &csv->c_data : NULL;
csv_dbg(xop, csv, "op %s: [%s] [%s]\n", xo_encoder_op_name(op),
name ?: "", value ?: "");
fflush(stdout);
/* If we don't have private data, we're sunk */
if (csv == NULL && op != XO_OP_CREATE)
return -1;
switch (op) {
case XO_OP_CREATE: /* Called when the handle is init'd */
rc = csv_create(xop);
break;
case XO_OP_OPTIONS:
rc = csv_options(xop, csv, value);
break;
case XO_OP_OPEN_LIST:
case XO_OP_CLOSE_LIST:
break; /* Ignore these ops */
case XO_OP_OPEN_CONTAINER:
case XO_OP_OPEN_LEAF_LIST:
rc = csv_open_level(xop, csv, name, 0);
break;
case XO_OP_OPEN_INSTANCE:
rc = csv_open_level(xop, csv, name, 1);
break;
case XO_OP_CLOSE_CONTAINER:
case XO_OP_CLOSE_LEAF_LIST:
case XO_OP_CLOSE_INSTANCE:
rc = csv_close_level(xop, csv, name);
break;
case XO_OP_STRING: /* Quoted UTF-8 string */
case XO_OP_CONTENT: /* Other content */
rc = csv_data(xop, csv, name, value, flags);
break;
case XO_OP_FINISH: /* Clean up function */
break;
case XO_OP_FLUSH: /* Clean up function */
rc = write(1, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
if (rc > 0)
rc = 0;
xo_buf_reset(xbp);
break;
case XO_OP_DESTROY: /* Clean up function */
csv_destroy(xop, csv);
break;
case XO_OP_ATTRIBUTE: /* Attribute name/value */
break;
case XO_OP_VERSION: /* Version string */
break;
}
return rc;
}
/*
* Callback when our encoder is loaded.
*/
int
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
{
arg->xei_handler = csv_handler;
arg->xei_version = XO_ENCODER_VERSION;
return 0;
}

View file

@ -15,7 +15,7 @@ static int
test_handler (XO_ENCODER_HANDLER_ARGS)
{
printf("op %s: [%s] [%s] [%#llx]\n", xo_encoder_op_name(op),
name ?: "", value ?: "", flags);
name ?: "", value ?: "", (unsigned long long) flags);
return 0;
}

View file

@ -5,7 +5,7 @@ uses
version @LIBXO_VERSION@.
Complete documentation can be found on github:
.Bd -literal -offset indent
http://juniper.github.io/libxo/@LIBXO_VERSION@/libxo\-manual.html
https://juniper.github.io/libxo/@LIBXO_VERSION@/html/index.html
.Ed
.Pp
.Nm libxo

View file

@ -293,39 +293,6 @@ struct xo_handle_s {
#define XOIF_INIT_IN_PROGRESS XOF_BIT(5) /* Init of handle is in progress */
#define XOIF_MADE_OUTPUT XOF_BIT(6) /* Have already made output */
/* Flags for formatting functions */
typedef unsigned long xo_xff_flags_t;
#define XFF_COLON (1<<0) /* Append a ":" */
#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */
#define XFF_WS (1<<2) /* Append a blank */
#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding styles (XML, JSON) */
#define XFF_QUOTE (1<<4) /* Force quotes */
#define XFF_NOQUOTE (1<<5) /* Force no quotes */
#define XFF_DISPLAY_ONLY (1<<6) /* Only emit for display styles (text, html) */
#define XFF_KEY (1<<7) /* Field is a key (for XPath) */
#define XFF_XML (1<<8) /* Force XML encoding style (for XPath) */
#define XFF_ATTR (1<<9) /* Escape value using attribute rules (XML) */
#define XFF_BLANK_LINE (1<<10) /* Emit a blank line */
#define XFF_NO_OUTPUT (1<<11) /* Do not make any output */
#define XFF_TRIM_WS (1<<12) /* Trim whitespace off encoded values */
#define XFF_LEAF_LIST (1<<13) /* A leaf-list (list of values) */
#define XFF_UNESCAPE (1<<14) /* Need to printf-style unescape the value */
#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */
#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */
#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */
#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */
#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */
#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */
#define XFF_ARGUMENT (1<<21) /* Content provided via argument */
/* Flags to turn off when we don't want i18n processing */
#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL)
/*
* Normal printf has width and precision, which for strings operate as
* min and max number of columns. But this depends on the idea that
@ -435,9 +402,6 @@ xo_realloc_func_t xo_realloc = realloc;
xo_free_func_t xo_free = free;
/* Forward declarations */
static void
xo_failure (xo_handle_t *xop, const char *fmt, ...);
static ssize_t
xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name,
xo_state_t new_state);
@ -660,13 +624,18 @@ xo_init_handle (xo_handle_t *xop)
if (!xo_locale_inited) {
xo_locale_inited = 1; /* Only do this once */
const char *cp = getenv("LC_CTYPE");
#ifdef __FreeBSD__ /* Who does The Right Thing */
const char *cp = "";
#else /* __FreeBSD__ */
const char *cp = getenv("LC_ALL");
if (cp == NULL)
cp = getenv("LC_CTYPE");
if (cp == NULL)
cp = getenv("LANG");
if (cp == NULL)
cp = getenv("LC_ALL");
if (cp == NULL)
cp = "C"; /* Default for C programs */
#endif /* __FreeBSD__ */
(void) setlocale(LC_CTYPE, cp);
}
@ -1871,7 +1840,7 @@ xo_message (const char *fmt, ...)
va_end(vap);
}
static void
void
xo_failure (xo_handle_t *xop, const char *fmt, ...)
{
if (!XOF_ISSET(xop, XOF_WARN))
@ -2042,17 +2011,17 @@ xo_get_style (xo_handle_t *xop)
static int
xo_name_to_style (const char *name)
{
if (strcmp(name, "xml") == 0)
if (xo_streq(name, "xml"))
return XO_STYLE_XML;
else if (strcmp(name, "json") == 0)
else if (xo_streq(name, "json"))
return XO_STYLE_JSON;
else if (strcmp(name, "encoder") == 0)
else if (xo_streq(name, "encoder"))
return XO_STYLE_ENCODER;
else if (strcmp(name, "text") == 0)
else if (xo_streq(name, "text"))
return XO_STYLE_TEXT;
else if (strcmp(name, "html") == 0)
else if (xo_streq(name, "html"))
return XO_STYLE_HTML;
else if (strcmp(name, "sdparams") == 0)
else if (xo_streq(name, "sdparams"))
return XO_STYLE_SDPARAMS;
return -1;
@ -2230,7 +2199,7 @@ xo_set_color_map (xo_handle_t *xop, char *value)
}
/* If no color initialization happened, then we don't need the map */
if (num > 0)
if (num > 1)
XOF_SET(xop, XOF_COLOR_MAP);
else
XOF_CLEAR(xop, XOF_COLOR_MAP);
@ -2261,7 +2230,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input)
if (vp)
*vp++ = '\0';
if (strcmp("colors", cp) == 0) {
if (xo_streq("colors", cp)) {
xo_set_color_map(xop, vp);
continue;
}
@ -2269,7 +2238,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input)
new_flag = xo_name_lookup(xo_xof_simple_names, cp, -1);
if (new_flag != 0) {
XOF_SET(xop, new_flag);
} else if (strcmp(cp, "no-color") == 0) {
} else if (xo_streq(cp, "no-color")) {
XOF_CLEAR(xop, XOF_COLOR_ALLOWED);
} else {
xo_failure(xop, "unknown simple option: %s", cp);
@ -2406,7 +2375,7 @@ xo_set_options (xo_handle_t *xop, const char *input)
if (vp)
*vp++ = '\0';
if (strcmp("colors", cp) == 0) {
if (xo_streq("colors", cp)) {
xo_set_color_map(xop, vp);
continue;
}
@ -2425,21 +2394,20 @@ xo_set_options (xo_handle_t *xop, const char *input)
new_flag = xo_name_to_flag(cp);
if (new_flag != 0)
XOF_SET(xop, new_flag);
else if (strcmp(cp, "no-color") == 0)
else if (xo_streq(cp, "no-color"))
XOF_CLEAR(xop, XOF_COLOR_ALLOWED);
else if (strcmp(cp, "indent") == 0) {
else if (xo_streq(cp, "indent")) {
if (vp)
xop->xo_indent_by = atoi(vp);
else
xo_failure(xop, "missing value for indent option");
} else if (strcmp(cp, "encoder") == 0) {
} else if (xo_streq(cp, "encoder")) {
if (vp == NULL)
xo_failure(xop, "missing value for encoder option");
else {
if (xo_encoder_init(xop, vp)) {
xo_failure(xop, "encoder not found: %s", vp);
rc = -1;
}
rc = xo_encoder_init(xop, vp);
if (rc)
xo_warnx("error initializing encoder: %s", vp);
}
} else {
@ -3356,7 +3324,7 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp,
cp += 1;
continue;
} if (cp + 1 < ep && cp[1] == '%') {
} else if (cp + 1 < ep && cp[1] == '%') {
cp += 1;
goto add_one;
}
@ -4733,7 +4701,7 @@ xo_color_find (const char *str)
int i;
for (i = 0; xo_color_names[i]; i++) {
if (strcmp(xo_color_names[i], str) == 0)
if (xo_streq(xo_color_names[i], str))
return i;
}
@ -4784,7 +4752,7 @@ xo_effect_find (const char *str)
int i;
for (i = 0; xo_effect_names[i]; i++) {
if (strcmp(xo_effect_names[i], str) == 0)
if (xo_streq(xo_effect_names[i], str))
return i;
}
@ -5653,6 +5621,7 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED,
xo_field_info_t *xfip;
unsigned fnum, max_fields;
uint64_t bits = 0;
const uint64_t one = 1; /* Avoid "1ULL" */
/* First make a list of add the explicitly used bits */
for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) {
@ -5669,7 +5638,7 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED,
break;
if (xfip->xfi_fnum)
bits |= 1 << xfip->xfi_fnum;
bits |= one << xfip->xfi_fnum;
}
max_fields = fnum;
@ -5687,14 +5656,14 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED,
continue;
/* Find the next unassigned field */
for (fnum++; bits & (1 << fnum); fnum++)
for (fnum++; bits & (one << fnum); fnum++)
continue;
if (fnum > max_fields)
break;
xfip->xfi_fnum = fnum; /* Mark the field number */
bits |= 1 << fnum; /* Mark it used */
bits |= one << fnum; /* Mark it used */
}
}
@ -5709,6 +5678,7 @@ xo_parse_field_numbers (xo_handle_t *xop, const char *fmt,
xo_field_info_t *xfip;
unsigned field, fnum;
uint64_t bits = 0;
const uint64_t one = 1; /* Avoid 1ULL */
for (xfip = fields, field = 0; field < num_fields; xfip++, field++) {
/* Fields default to 1:1 with natural position */
@ -5721,12 +5691,12 @@ xo_parse_field_numbers (xo_handle_t *xop, const char *fmt,
fnum = xfip->xfi_fnum - 1; /* Move to zero origin */
if (fnum < 64) { /* Only test what fits */
if (bits & (1 << fnum)) {
if (bits & (one << fnum)) {
xo_failure(xop, "field number %u reused: '%s'",
xfip->xfi_fnum, fmt);
return -1;
}
bits |= 1 << fnum;
bits |= one << fnum;
}
}
@ -5786,9 +5756,10 @@ xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields,
xfip->xfi_len = sp - xfip->xfi_start + 1;
/* Move along the string, but don't run off the end */
if (*sp == '}' && sp[1] == '}')
if (*sp == '}' && sp[1] == '}') /* Paranoid; must be true */
sp += 2;
cp = *sp ? sp : sp;
cp = sp;
xfip->xfi_next = cp;
continue;
}
@ -6186,7 +6157,7 @@ xo_gettext_build_format (xo_handle_t *xop,
goto bail2;
const char *gtfmt = xo_dgettext(xop, xb.xb_bufp);
if (gtfmt == NULL || gtfmt == fmt || strcmp(gtfmt, fmt) == 0)
if (gtfmt == NULL || gtfmt == fmt || xo_streq(gtfmt, fmt))
goto bail2;
char *new_fmt = xo_strndup(gtfmt, -1);
@ -6875,7 +6846,7 @@ xo_depth_change (xo_handle_t *xop, const char *name,
xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth];
if (XOF_ISSET(xop, XOF_WARN)) {
const char *top = xsp->xs_name;
if (top != NULL && name != NULL && strcmp(name, top) != 0) {
if (top != NULL && name != NULL && !xo_streq(name, top)) {
xo_failure(xop, "incorrect close: '%s' .vs. '%s'",
name, top);
return;
@ -7074,7 +7045,6 @@ xo_do_close_container (xo_handle_t *xop, const char *name)
xo_stack_set_flags(xop);
pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : "";
ppn = (xop->xo_depth <= 1) ? pre_nl : "";
ppn = "";
xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0);
@ -7622,7 +7592,7 @@ xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state)
if (xsp->xs_state != need_state)
continue;
if (name && xsp->xs_name && strcmp(name, xsp->xs_name) != 0)
if (name && xsp->xs_name && !xo_streq(name, xsp->xs_name))
continue;
limit = xsp;
@ -7680,13 +7650,6 @@ xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name,
break;
case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_CONTAINER):
if (on_marker)
goto marker_prevents_close;
rc = xo_do_close_list(xop, NULL);
if (rc >= 0)
goto open_container;
break;
case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_CONTAINER):
if (on_marker)
goto marker_prevents_close;
@ -7695,18 +7658,13 @@ xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name,
goto open_container;
break;
/*close_container:*/
case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER):
if (on_marker)
goto marker_prevents_close;
rc = xo_do_close(xop, name, new_state);
break;
case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_CONTAINER):
/* This is an exception for "xo --close" */
rc = xo_do_close_container(xop, name);
break;
/*close_container:*/
case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER):
case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_CONTAINER):
case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_CONTAINER):
if (on_marker)
@ -8062,7 +8020,7 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap)
char *newfmt = alloca(len + 2);
memcpy(newfmt, fmt, len);
newfmt[len] = '\n';
newfmt[len] = '\0';
newfmt[len + 1] = '\0';
fmt = newfmt;
}
@ -8145,7 +8103,16 @@ xo_parse_args (int argc, char **argv)
xo_program = argv[0];
cp = strrchr(xo_program, '/');
if (cp)
xo_program = cp + 1;
xo_program = ++cp;
/* GNU tools add an annoying ".test" as the program extension; remove it */
size_t len = strlen(xo_program);
static const char gnu_ext[] = ".test";
if (len >= sizeof(gnu_ext)) {
cp = &cp[len + 1 - sizeof(gnu_ext)];
if (xo_streq(cp, gnu_ext))
*cp = '\0';
}
xo_handle_t *xop = xo_default(NULL);
@ -8178,7 +8145,7 @@ xo_parse_args (int argc, char **argv)
} else if (*cp == '-') {
cp += 1;
if (strcmp(cp, "check") == 0) {
if (xo_streq(cp, "check")) {
exit(XO_HAS_LIBXO);
} else {
@ -8386,9 +8353,8 @@ xo_emit_err (int eval, const char *fmt, ...)
int code = errno;
va_list vap;
va_start(vap, fmt);
xo_emit_err_v(0, code, fmt, vap);
va_end(vap);
exit(eval);
xo_emit_err_v(eval, code, fmt, vap);
/*NOTREACHED*/
}
void
@ -8397,10 +8363,8 @@ xo_emit_errx (int eval, const char *fmt, ...)
va_list vap;
va_start(vap, fmt);
xo_emit_err_v(0, -1, fmt, vap);
va_end(vap);
xo_finish();
exit(eval);
xo_emit_err_v(eval, -1, fmt, vap); /* This will exit */
/*NOTREACHED*/
}
void
@ -8409,10 +8373,8 @@ xo_emit_errc (int eval, int code, const char *fmt, ...)
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
va_end(vap);
xo_finish();
exit(eval);
xo_emit_err_v(eval, code, fmt, vap); /* This will exit */
/*NOTREACHED*/
}
/*

View file

@ -72,14 +72,14 @@ xo_buf_is_empty (xo_buffer_t *xbp)
/*
* Return the current offset
*/
static inline unsigned
static inline ssize_t
xo_buf_offset (xo_buffer_t *xbp)
{
return xbp ? (xbp->xb_curp - xbp->xb_bufp) : 0;
}
static inline char *
xo_buf_data (xo_buffer_t *xbp, unsigned offset)
xo_buf_data (xo_buffer_t *xbp, ssize_t offset)
{
if (xbp == NULL)
return NULL;

View file

@ -199,7 +199,7 @@ xo_encoder_find (const char *name)
xo_encoder_list_init(&xo_encoders);
XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) {
if (strcmp(xep->xe_name, name) == 0)
if (xo_streq(xep->xe_name, name))
return xep;
}
@ -290,9 +290,26 @@ xo_encoder_init (xo_handle_t *xop, const char *name)
{
xo_encoder_setup();
const char *opts = strchr(name, ':');
if (opts) {
/* Make a writable copy of the name */
size_t len = strlen(name);
char *copy = alloca(len + 1);
memcpy(copy, name, len);
copy[len] = '\0';
char *opts_copy = copy + (opts - name); /* Move to ':' */
*opts_copy++ = '\0'; /* Trim it off */
opts = opts_copy; /* Use copy as options */
name = copy; /* Use trimmed copy as name */
}
/* Can't have names containing '/' or ':' */
if (strchr(name, '/') != NULL || strchr(name, ':') != NULL)
if (strchr(name, '/') != NULL || strchr(name, ':') != NULL) {
xo_failure(xop, "invalid encoder name: %s", name);
return -1;
}
/*
* First we look on the list of known (registered) encoders.
@ -302,13 +319,20 @@ xo_encoder_init (xo_handle_t *xop, const char *name)
xo_encoder_node_t *xep = xo_encoder_find(name);
if (xep == NULL) {
xep = xo_encoder_discover(name);
if (xep == NULL)
if (xep == NULL) {
xo_failure(xop, "encoder not founde: %s", name);
return -1;
}
}
xo_set_encoder(xop, xep->xe_handler);
return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL, 0);
int rc = xo_encoder_handle(xop, XO_OP_CREATE, name, NULL, 0);
if (rc == 0 && opts != NULL) {
rc = xo_encoder_handle(xop, XO_OP_OPTIONS, name, opts, 0);
}
return rc;
}
/*
@ -334,7 +358,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags)
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
const char *name, const char *value, xo_xof_flags_t flags)
const char *name, const char *value, xo_xff_flags_t flags)
{
void *private = xo_get_private(xop);
xo_encoder_func_t func = xo_get_encoder(xop);
@ -366,6 +390,7 @@ xo_encoder_op_name (xo_encoder_op_t op)
/* 14 */ "destroy",
/* 15 */ "attr",
/* 16 */ "version",
/* 17 */ "options",
};
if (op > sizeof(names) / sizeof(names[0]))

View file

@ -18,12 +18,57 @@
#ifndef XO_ENCODER_H
#define XO_ENCODER_H
#include <string.h>
/*
* Expose libxo's memory allocation functions
*/
extern xo_realloc_func_t xo_realloc;
extern xo_free_func_t xo_free;
/*
* Simple string comparison function (without the temptation
* to forget the "== 0").
*/
static inline int
xo_streq (const char *one, const char *two)
{
return strcmp(one, two) == 0;
}
/* Flags for formatting functions */
typedef unsigned long xo_xff_flags_t;
#define XFF_COLON (1<<0) /* Append a ":" */
#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */
#define XFF_WS (1<<2) /* Append a blank */
#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding styles (XML, JSON) */
#define XFF_QUOTE (1<<4) /* Force quotes */
#define XFF_NOQUOTE (1<<5) /* Force no quotes */
#define XFF_DISPLAY_ONLY (1<<6) /* Only emit for display styles (text, html) */
#define XFF_KEY (1<<7) /* Field is a key (for XPath) */
#define XFF_XML (1<<8) /* Force XML encoding style (for XPath) */
#define XFF_ATTR (1<<9) /* Escape value using attribute rules (XML) */
#define XFF_BLANK_LINE (1<<10) /* Emit a blank line */
#define XFF_NO_OUTPUT (1<<11) /* Do not make any output */
#define XFF_TRIM_WS (1<<12) /* Trim whitespace off encoded values */
#define XFF_LEAF_LIST (1<<13) /* A leaf-list (list of values) */
#define XFF_UNESCAPE (1<<14) /* Need to printf-style unescape the value */
#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */
#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */
#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */
#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */
#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */
#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */
#define XFF_ARGUMENT (1<<21) /* Content provided via argument */
/* Flags to turn off when we don't want i18n processing */
#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL)
typedef unsigned xo_encoder_op_t;
/* Encoder operations; names are in xo_encoder.c:xo_encoder_op_name() */
@ -44,6 +89,7 @@ typedef unsigned xo_encoder_op_t;
#define XO_OP_DESTROY 14 /* Clean up function */
#define XO_OP_ATTRIBUTE 15 /* Attribute name/value */
#define XO_OP_VERSION 16 /* Version string */
#define XO_OP_OPTIONS 17 /* Additional command line options */
#define XO_ENCODER_HANDLER_ARGS \
xo_handle_t *xop __attribute__ ((__unused__)), \
@ -51,7 +97,7 @@ typedef unsigned xo_encoder_op_t;
const char *name __attribute__ ((__unused__)), \
const char *value __attribute__ ((__unused__)), \
void *private __attribute__ ((__unused__)), \
xo_xof_flags_t flags __attribute__ ((__unused__))
xo_xff_flags_t flags __attribute__ ((__unused__))
typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS);
@ -106,7 +152,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags);
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
const char *name, const char *value, xo_xof_flags_t flags);
const char *name, const char *value, xo_xff_flags_t flags);
void
xo_encoders_clean (void);
@ -114,4 +160,10 @@ xo_encoders_clean (void);
const char *
xo_encoder_op_name (xo_encoder_op_t op);
/*
* xo_failure is used to announce internal failures, when "warn" is on
*/
void
xo_failure (xo_handle_t *xop, const char *fmt, ...);
#endif /* XO_ENCODER_H */

View file

@ -86,6 +86,11 @@ TEST_JIG = \
${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.out out/$$base.$$fmt.out ${S2O} ; \
${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.err out/$$base.$$fmt.err ${S2O}
TEST_JIG2 = \
echo "... $$test ... $$fmt ..."; \
xoopts==warn,encoder=csv$$csv ; \
${TEST_JIG}; true;
TEST_FORMATS = T XP JP HP X J H HIPx
test tests: ${bin_PROGRAMS}
@ -105,6 +110,12 @@ test tests: ${bin_PROGRAMS}
true; \
done) \
done)
-@ (${TEST_TRACE} test=test_01.c; base=test_01; \
( fmt=Ecsv1; csv= ; ${TEST_JIG2} ); \
( fmt=Ecsv2; csv=:path=top/data/item+no-header ; ${TEST_JIG2} ); \
( fmt=Ecsv3; csv=:path=item+leafs=sku.sold+no-quotes ; ${TEST_JIG2} ); \
)
one:
-@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
@ -112,12 +123,17 @@ one:
accept:
-@(for test in ${TEST_CASES} ; do \
base=`${BASENAME} $$test .c` ; \
(for fmt in ${TEST_FORMATS} E; do \
(for fmt in ${TEST_FORMATS} E ; 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) \
done)
-@(test=test_01.c; base=test_01; for fmt in Ecsv1 Ecsv2 Ecsv3 ; 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 $@ $<

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [top] [] [0x810]
op string: [type] [ethernet] [0]
op content: [type] [bridge] [0]
@ -133,6 +133,55 @@ op attr: [test4] [value4] [0]
op string: [item] [water] [0x2000]
op close_list: [item] [] [0]
op close_container: [data4] [] [0]
op attr: [test] [value] [0]
op open_container: [data] [] [0x810]
op open_list: [item] [] [0]
op attr: [test2] [value2] [0]
op open_instance: [item] [] [0x810]
op attr: [test3] [value3] [0]
op string: [sku] [GRO-000-415] [0x98]
op string: [name] [gum] [0x80]
op content: [sold] [1412] [0x20]
op content: [on-order] [10] [0]
op content: [in-stock] [54] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op attr: [test3] [value3] [0]
op string: [sku] [HRD-000-212] [0x98]
op string: [name] [rope] [0x80]
op content: [sold] [85] [0x20]
op string: [extra] [special] [0]
op content: [on-order] [2] [0]
op content: [in-stock] [4] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op attr: [test3] [value3] [0]
op string: [sku] [HRD-000-517] [0x98]
op string: [name] [ladder] [0x80]
op content: [sold] [0] [0x20]
op string: [extra] [special] [0]
op content: [on-order] [1] [0]
op content: [in-stock] [2] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op attr: [test3] [value3] [0]
op string: [sku] [HRD-000-632] [0x98]
op string: [name] [bolt] [0x80]
op content: [sold] [4123] [0x20]
op content: [on-order] [42] [0]
op content: [in-stock] [144] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op attr: [test3] [value3] [0]
op string: [sku] [GRO-000-2331] [0x98]
op string: [name] [water] [0x80]
op content: [sold] [17] [0x20]
op string: [extra] [special] [0]
op content: [on-order] [2] [0]
op content: [in-stock] [14] [0]
op close_instance: [item] [] [0]
op close_list: [item] [] [0]
op close_container: [data] [] [0]
op content: [cost] [425] [0]
op content: [cost] [455] [0]
op string: [mode] [mode] [0x8]

View file

@ -0,0 +1,17 @@
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
HRD-000-632,bolt,4123,144,42
GRO-000-2331,water,17,14,2
GRO-000-415,gum,1412.0,54,10
HRD-000-212,rope,85.0,4,2
HRD-000-517,ladder,0,2,1
HRD-000-632,bolt,4123.0,144,42
GRO-000-2331,water,17.0,14,2
GRO-000-533,fish,1321.0,45,1
GRO-000-415,gum,1412,54,10
HRD-000-212,rope,85,4,2
HRD-000-517,ladder,0,2,1
HRD-000-632,bolt,4123,144,42
GRO-000-2331,water,17,14,2

View file

@ -0,0 +1,10 @@
GRO-000-415,gum,1412,54,10
HRD-000-212,rope,85,4,2
HRD-000-517,ladder,0,2,1
HRD-000-632,bolt,4123,144,42
GRO-000-2331,water,17,14,2
GRO-000-415,gum,1412,54,10
HRD-000-212,rope,85,4,2
HRD-000-517,ladder,0,2,1
HRD-000-632,bolt,4123,144,42
GRO-000-2331,water,17,14,2

View file

@ -0,0 +1,17 @@
sku,sold
GRO-000-415,1412
HRD-000-212,85
HRD-000-517,0
HRD-000-632,4123
GRO-000-2331,17
GRO-000-415,1412.0
HRD-000-212,85.0
HRD-000-517,0
HRD-000-632,4123.0
GRO-000-2331,17.0
GRO-000-533,1321.0
GRO-000-415,1412
HRD-000-212,85
HRD-000-517,0
HRD-000-632,4123
GRO-000-2331,17

File diff suppressed because one or more lines are too long

View file

@ -329,6 +329,58 @@
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/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-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">gum </div>
<div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/sold" data-type="number" data-help="Number of items sold"> 1412</div>
<div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/on-order" data-type="number" data-help="Number of items on order"> 10</div>
<div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-415'][name = 'gum']/in-stock" data-type="number" data-help="Number of items in stock"> 54</div>
<div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> GRO-000-415</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">rope </div>
<div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/sold" data-type="number" data-help="Number of items sold"> 85</div>
<div class="text">Extra: </div>
<div class="data" data-tag="extra" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/extra">special</div>
<div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/on-order" data-type="number" data-help="Number of items on order"> 2</div>
<div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-212'][name = 'rope']/in-stock" data-type="number" data-help="Number of items in stock"> 4</div>
<div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-212</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">ladder </div>
<div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/sold" data-type="number" data-help="Number of items sold"> 0</div>
<div class="text">Extra: </div>
<div class="data" data-tag="extra" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/extra">special</div>
<div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/on-order" data-type="number" data-help="Number of items on order"> 1</div>
<div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-517'][name = 'ladder']/in-stock" data-type="number" data-help="Number of items in stock"> 2</div>
<div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-517</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">bolt </div>
<div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/sold" data-type="number" data-help="Number of items sold"> 4123</div>
<div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/on-order" data-type="number" data-help="Number of items on order"> 42</div>
<div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'HRD-000-632'][name = 'bolt']/in-stock" data-type="number" data-help="Number of items in stock"> 144</div>
<div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key"> HRD-000-632</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-xpath="/top/data/item/name" data-type="string" data-help="Name of the item" data-key="key">water </div>
<div class="data" data-tag="sold" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/sold" data-type="number" data-help="Number of items sold"> 17</div>
<div class="text">Extra: </div>
<div class="data" data-tag="extra" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/extra">special</div>
<div class="data" data-tag="on-order" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/on-order" data-type="number" data-help="Number of items on order"> 2</div>
<div class="data" data-tag="in-stock" data-xpath="/top/data/item[sku = 'GRO-000-2331'][name = 'water']/in-stock" data-type="number" data-help="Number of items in stock"> 14</div>
<div class="data" data-tag="sku" data-xpath="/top/data/item/sku" data-type="string" data-help="Stock Keeping Unit" 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>

View file

@ -329,6 +329,58 @@
<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>

View file

@ -1 +1 @@
{"top": {"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]","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"]},"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"}}
{"top": {"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]","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"}}

View file

@ -121,6 +121,48 @@
"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",

View file

@ -50,6 +50,14 @@ Item: rope
Item: ladder
Item: bolt
Item: water
Item Total Sold In Stock On Order SKU
gum 1412 10 54 GRO-000-415
rope 85Extra: special 2 4 HRD-000-212
ladder 0Extra: special 1 2 HRD-000-517
bolt 4123 42 144 HRD-000-632
water 17Extra: special 2 14 GRO-000-2331
XXXXXXXX
X XCost: 425
X XCost: 455

View file

@ -1 +1 @@
<top><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><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><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>
<top><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><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>

View file

@ -112,6 +112,46 @@
<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>

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [top] [] [0x40010]
op open_container: [data] [] [0x40010]
op string: [name] [em0] [0x1080]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [employees] [] [0x10]
op open_list: [employee] [] [0]
op close_list: [employee] [] [0]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [employees] [] [0x10]
op open_list: [employee] [] [0]
op open_instance: [employee] [] [0x10]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [indian-languages] [] [0x200010]
op string: [gurmukhi] [ਲਹੌਰ ਪਾਕਿਸਤਾਨੀ ਪੰਜਾਬ ਦੀ ਰਾਜਧਾਨੀ ਹੈ । ਲੋਕ ਗਿਣਤੀ ਦੇ ਨਾਲ ਕਰਾਚੀ ਤੋਂ ਬਾਅਦ ਲਹੌਰ ਦੂਜਾ ਸਭ ਤੋਂ ਵੱਡਾ ਸ਼ਹਿਰ ਹੈ । ਲਹੌਰ ਪਾਕਿਸਤਾਨ ਦਾ ਸਿਆਸੀ, ਰਹਤਲੀ ਤੇ ਪੜ੍ਹਾਈ ਦਾ ਗੜ੍ਹ ਹੈ ਅਤੇ ਇਸ ਲਈ ਇਹਨੂੰ ਪਾਕਿਸਤਾਨ ਦਾ ਦਿਲ ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ । ਲਹੌਰ ਦਰਿਆ-ਏ-ਰਾਵੀ ਦੇ ਕੰਢੇ ਤੇ ਵਸਦਾ ਹੈ ਤੇ ਇਸਦੀ ਲੋਕ ਗਿਣਤੀ ਇੱਕ ਕਰੋੜ ਦੇ ਨੇੜੇ ਹੈ ।] [0]
op string: [shahmukhi] [لہور پاکستانی پنجاب دا دارالحکومت اے۔ لوک گنتی دے نال کراچی توں بعد لہور دوجا سبھ توں وڈا شہر اے۔ لہور پاکستان دا سیاسی، رہتلی تے پڑھائی دا گڑھ اے تے اس لئی ایھنوں پاکستان دا دل وی کیھا جاندا اے۔ لہور دریاۓ راوی دے کنڈھے تے وسدا اے اسدی لوک گنتی اک کروڑ دے نیڑے اے ۔] [0]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [employees] [] [0x410]
op open_list: [employee] [] [0]
op open_instance: [employee] [] [0x410]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [employees] [] [0x200010]
op open_list: [test] [] [0]
op open_instance: [test] [] [0x200010]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [top] [] [0x810]
op open_container: [data] [] [0x810]
op open_container: [contents] [] [0x810]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [top] [] [0x810]
op open_container: [data] [] [0x810]
op open_container: [contents] [] [0x810]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op version: [] [3.1.4] [0]
op open_container: [top] [] [0x4000810]
op attr: [test] [value] [0]

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op version: [] [3.1.4] [0]
op open_container: [top] [] [0x10]
{{<14>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-status [animal-status@42 animal="snake" state="loose"] The snake is loose}}

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
op create: [] [] [0]
op create: [test] [] [0]
op open_container: [top] [] [0x4040010]
op open_container: [data] [] [0x4040010]
op string: [animal] [fish] [0]

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -1,4 +1,4 @@
test_12.test: invalid XML tag name: '2by4'
test_12.test: invalid XML tag name: '4x4'
test_12.test: invalid XML tag name: '2morrow'
test_12.test: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '2by4'
test_12: invalid XML tag name: '4x4'
test_12: invalid XML tag name: '2morrow'
test_12: invalid XML tag name: '2by4'

View file

@ -14,6 +14,7 @@
#include <unistd.h>
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -55,21 +56,21 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
else if (strcmp(argv[argc], "error") == 0) {
else if (xo_streq(argv[argc], "error")) {
close(-1);
xo_err(1, "error detected");
}
@ -186,6 +187,44 @@ main (int argc, char **argv)
xo_close_list("item");
xo_close_container("data4");
xo_attr("test", "value");
xo_open_container("data");
xo_open_list("item");
xo_attr("test2", "value2");
xo_emit("{T:Item/%-10s}{T:Total Sold/%12s}{T:In Stock/%12s}"
"{T:On Order/%12s}{T:SKU/%5s}\n");
for (ip = list; ip->i_title; ip++) {
xo_open_instance("item");
xo_attr("test3", "value3");
xo_emit("{keq:sku/%s-%u/%s-000-%u}"
"{k:name/%-10s/%s}{n:sold/%12u/%u}",
ip->i_sku_base, ip->i_sku_num,
ip->i_title, ip->i_sold);
if (ip->i_onorder < 5)
xo_emit("Extra: {:extra}", "special");
if (ip->i_instock & 1)
xo_emit("{:in-stock/%12u/%u}", ip->i_instock);
xo_emit("{:on-order/%12u/%u}", ip->i_onorder);
if (!(ip->i_instock & 1))
xo_emit("{:in-stock/%12u/%u}", ip->i_instock);
xo_emit("{qkd:sku/%5s-000-%u/%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_emit("\n\n");
xo_emit("X{P:}X", "epic fail");
xo_emit("X{T:}X", "epic fail");
xo_emit("X{N:}X", "epic fail");

View file

@ -14,6 +14,7 @@
#include <string.h>
#include "xo.h"
#include "xo_encoder.h"
#include "xo_humanize.h"
@ -25,19 +26,19 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
}

View file

@ -13,6 +13,7 @@
#include <string.h>
#include "xo.h"
#include "xo_encoder.h"
xo_info_t info[] = {
{ "employee", "object", "Employee data" },
@ -44,10 +45,10 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "count") == 0) {
if (xo_streq(argv[argc], "count")) {
if (argv[argc + 1])
opt_count = atoi(argv[++argc]);
} else if (strcmp(argv[argc], "extra") == 0) {
} else if (xo_streq(argv[argc], "extra")) {
if (argv[argc + 1])
opt_extra = atoi(argv[++argc]);
}

View file

@ -15,6 +15,7 @@
#include <errno.h>
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -39,21 +40,21 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
else if (strcmp(argv[argc], "error") == 0) {
else if (xo_streq(argv[argc], "error")) {
close(-1);
xo_err(1, "error detected");
}

View file

@ -15,6 +15,7 @@
#include <errno.h>
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -39,21 +40,21 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
else if (strcmp(argv[argc], "error") == 0) {
else if (xo_streq(argv[argc], "error")) {
close(-1);
xo_err(1, "error detected");
}

View file

@ -16,6 +16,7 @@
#include <ctype.h>
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -58,21 +59,21 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
else if (strcmp(argv[argc], "error") == 0) {
else if (xo_streq(argv[argc], "error")) {
close(-1);
xo_err(1, "error detected");
}

View file

@ -18,6 +18,7 @@
#include <syslog.h>
#include "xo.h"
#include "xo_encoder.h"
void
test_syslog_open (void)
@ -50,11 +51,11 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "full") == 0)
if (xo_streq(argv[argc], "full"))
unit_test = 0;
else if (strcmp(argv[argc], "fire") == 0)
else if (xo_streq(argv[argc], "fire"))
fire = 1;
else if (strcmp(argv[argc], "tz") == 0)
else if (xo_streq(argv[argc], "tz"))
tzone = argv[++argc];
}

View file

@ -15,6 +15,7 @@
#include "xo_config.h"
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -29,25 +30,25 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "xml") == 0)
if (xo_streq(argv[argc], "xml"))
xo_set_style(NULL, XO_STYLE_XML);
else if (strcmp(argv[argc], "json") == 0)
else if (xo_streq(argv[argc], "json"))
xo_set_style(NULL, XO_STYLE_JSON);
else if (strcmp(argv[argc], "text") == 0)
else if (xo_streq(argv[argc], "text"))
xo_set_style(NULL, XO_STYLE_TEXT);
else if (strcmp(argv[argc], "html") == 0)
else if (xo_streq(argv[argc], "html"))
xo_set_style(NULL, XO_STYLE_HTML);
else if (strcmp(argv[argc], "no-color") == 0)
else if (xo_streq(argv[argc], "no-color"))
opt_color = 0;
else if (strcmp(argv[argc], "pretty") == 0)
else if (xo_streq(argv[argc], "pretty"))
xo_set_flags(NULL, XOF_PRETTY);
else if (strcmp(argv[argc], "xpath") == 0)
else if (xo_streq(argv[argc], "xpath"))
xo_set_flags(NULL, XOF_XPATH);
else if (strcmp(argv[argc], "info") == 0)
else if (xo_streq(argv[argc], "info"))
xo_set_flags(NULL, XOF_INFO);
else if (strcmp(argv[argc], "no-retain") == 0)
else if (xo_streq(argv[argc], "no-retain"))
flags &= ~XOEF_RETAIN;
else if (strcmp(argv[argc], "big") == 0) {
else if (xo_streq(argv[argc], "big")) {
if (argv[argc + 1])
count = atoi(argv[++argc]);
}

View file

@ -21,6 +21,7 @@
#include <libintl.h>
#include "xo.h"
#include "xo_encoder.h"
int
main (int argc, char **argv)
@ -35,11 +36,11 @@ main (int argc, char **argv)
return 1;
for (argc = 1; argv[argc]; argc++) {
if (strcmp(argv[argc], "tz") == 0)
if (xo_streq(argv[argc], "tz"))
tzone = argv[++argc];
else if (strcmp(argv[argc], "lang") == 0)
else if (xo_streq(argv[argc], "lang"))
lang = argv[++argc];
else if (strcmp(argv[argc], "po") == 0)
else if (xo_streq(argv[argc], "po"))
strlcpy(path, argv[++argc], sizeof(path));
}

View file

@ -1 +1 @@
<div class="line"><div class="text">Ouryay </div><div class="data" data-tag="noun">ordsway</div><div class="text"> </div><div class="data" data-tag="adjective">amingflay</div><div class="text"> isyay </div><div class="data" data-tag="owner">ymay</div><div class="data" data-tag="target">ouchcay</div><div class="text"> bubbly-bubbly </div><div class="data" data-tag="verb">urningbay</div></div><div class="line"><div class="text">Ethay </div><div class="data" data-tag="noun">ordsway</div><div class="text"> asway '</div><div class="data" data-tag="owner">ymay</div><div class="data" data-tag="adjective">amingflay</div><div class="data" data-tag="target">ouchcay</div><div class="text">' </div><div class="data" data-tag="verb">urningbay</div></div><div class="line"><div class="data" data-tag="bytes">0</div><div class="padding"> </div><div class="note">yebay</div></div><div class="line"><div class="data" data-tag="bytes">1</div><div class="padding"> </div><div class="note">yesbay</div></div><div class="line"><div class="data" data-tag="bytes">2</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="data" data-tag="bytes">3</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="data" data-tag="bytes">4</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="label">otaltay</div><div class="text"> </div><div class="data" data-tag="total">1234</div></div><div class="line"><div class="text">Eceivedray </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">ldb2</div><div class="text"> omfray </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> inyay </div><div class="data" data-tag="time">32</div><div class="text"> msyay</div></div><div class="line"><div class="text">Received </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">yezbay</div><div class="text"> from </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> in </div><div class="data" data-tag="time">32</div><div class="text"> ms</div></div><div class="line"><div class="text">Eceivedray </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">ldb2</div><div class="text"> omfray </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> inyay </div><div class="data" data-tag="time">32</div><div class="text"> msyay</div></div><div class="line"><div class="text">Onlyay </div><div class="data" data-tag="marzlevanes">3</div><div class="text"> </div><div class="note">arzlevanezmay</div><div class="text"> areyay unctioningfay orrectlycay</div></div><div class="line"><div class="text">Ersionvay </div><div class="data" data-tag="date">Tue Jun 23 18:47:09 UTC 2015</div><div class="text"> </div><div class="data" data-tag="version">1.2.3</div></div><div class="line"><div class="data" data-tag="program">gt_01.test</div><div class="decoration">:</div><div class="padding"> </div><div class="text">Nableuay otay </div><div class="data" data-tag="verb">ectulatobjay</div><div class="text"> orwardfay elocipingvay</div><div class="text">: </div><div class="data" data-tag="error">Ermissionpay eniedday</div></div><div class="line"><div class="data" data-tag="program">gt_01.test</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="style">automaticyay</div><div class="text"> ynchronizationsay ofyay </div><div class="data" data-tag="type">ardinalyay</div><div class="text"> </div><div class="data" data-tag="target">ammetersgray</div><div class="text"> ailedfay</div><div class="text">: </div><div class="data" data-tag="error">Ermissionpay eniedday</div></div><div class="line"><div class="label">ydrocoptichay arzlevanesmay</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="marzlevanes">6</div></div><div class="line"><div class="text">Dude, </div><div class="label">Indingsway</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="windings">otuslay-oyay-eltayay</div></div>
<div class="line"><div class="text">Ouryay </div><div class="data" data-tag="noun">ordsway</div><div class="text"> </div><div class="data" data-tag="adjective">amingflay</div><div class="text"> isyay </div><div class="data" data-tag="owner">ymay</div><div class="data" data-tag="target">ouchcay</div><div class="text"> bubbly-bubbly </div><div class="data" data-tag="verb">urningbay</div></div><div class="line"><div class="text">Ethay </div><div class="data" data-tag="noun">ordsway</div><div class="text"> asway '</div><div class="data" data-tag="owner">ymay</div><div class="data" data-tag="adjective">amingflay</div><div class="data" data-tag="target">ouchcay</div><div class="text">' </div><div class="data" data-tag="verb">urningbay</div></div><div class="line"><div class="data" data-tag="bytes">0</div><div class="padding"> </div><div class="note">yebay</div></div><div class="line"><div class="data" data-tag="bytes">1</div><div class="padding"> </div><div class="note">yesbay</div></div><div class="line"><div class="data" data-tag="bytes">2</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="data" data-tag="bytes">3</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="data" data-tag="bytes">4</div><div class="padding"> </div><div class="note">yezbay</div></div><div class="line"><div class="label">otaltay</div><div class="text"> </div><div class="data" data-tag="total">1234</div></div><div class="line"><div class="text">Eceivedray </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">ldb2</div><div class="text"> omfray </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> inyay </div><div class="data" data-tag="time">32</div><div class="text"> msyay</div></div><div class="line"><div class="text">Received </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">yezbay</div><div class="text"> from </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> in </div><div class="data" data-tag="time">32</div><div class="text"> ms</div></div><div class="line"><div class="text">Eceivedray </div><div class="data" data-tag="received">1234</div><div class="text"> </div><div class="note">ldb2</div><div class="text"> omfray </div><div class="data" data-tag="from">foop</div><div class="text">#</div><div class="data" data-tag="port">4321</div><div class="text"> inyay </div><div class="data" data-tag="time">32</div><div class="text"> msyay</div></div><div class="line"><div class="text">Onlyay </div><div class="data" data-tag="marzlevanes">3</div><div class="text"> </div><div class="note">arzlevanezmay</div><div class="text"> areyay unctioningfay orrectlycay</div></div><div class="line"><div class="text">Ersionvay </div><div class="data" data-tag="date">Tue Jun 23 18:47:09 UTC 2015</div><div class="text"> </div><div class="data" data-tag="version">1.2.3</div></div><div class="line"><div class="data" data-tag="program">gt_01</div><div class="decoration">:</div><div class="padding"> </div><div class="text">Nableuay otay </div><div class="data" data-tag="verb">ectulatobjay</div><div class="text"> orwardfay elocipingvay</div><div class="text">: </div><div class="data" data-tag="error">Ermissionpay eniedday</div></div><div class="line"><div class="data" data-tag="program">gt_01</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="style">automaticyay</div><div class="text"> ynchronizationsay ofyay </div><div class="data" data-tag="type">ardinalyay</div><div class="text"> </div><div class="data" data-tag="target">ammetersgray</div><div class="text"> ailedfay</div><div class="text">: </div><div class="data" data-tag="error">Ermissionpay eniedday</div></div><div class="line"><div class="label">ydrocoptichay arzlevanesmay</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="marzlevanes">6</div></div><div class="line"><div class="text">Dude, </div><div class="label">Indingsway</div><div class="decoration">:</div><div class="padding"> </div><div class="data" data-tag="windings">otuslay-oyay-eltayay</div></div>

View file

@ -102,7 +102,7 @@
<div class="data" data-tag="version" data-xpath="/top/version">1.2.3</div>
</div>
<div class="line">
<div class="data" data-tag="program" data-xpath="/top/xo_emit_warn_hcv/__warning/program">gt_01.test</div>
<div class="data" data-tag="program" data-xpath="/top/xo_emit_warn_hcv/__warning/program">gt_01</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="text">Nableuay otay </div>
@ -112,7 +112,7 @@
<div class="data" data-tag="error" data-xpath="/top/xo_emit_warn_hcv/__warning/error">Ermissionpay eniedday</div>
</div>
<div class="line">
<div class="data" data-tag="program" data-xpath="/top/xo_emit_warn_hcv/__warning/program">gt_01.test</div>
<div class="data" data-tag="program" data-xpath="/top/xo_emit_warn_hcv/__warning/program">gt_01</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="style" data-xpath="/top/xo_emit_warn_hcv/__warning/style">automaticyay</div>

View file

@ -102,7 +102,7 @@
<div class="data" data-tag="version">1.2.3</div>
</div>
<div class="line">
<div class="data" data-tag="program">gt_01.test</div>
<div class="data" data-tag="program">gt_01</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="text">Nableuay otay </div>
@ -112,7 +112,7 @@
<div class="data" data-tag="error">Ermissionpay eniedday</div>
</div>
<div class="line">
<div class="data" data-tag="program">gt_01.test</div>
<div class="data" data-tag="program">gt_01</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="style">automaticyay</div>

View file

@ -1 +1 @@
{"top": {"adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay","adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay", "bytes": [0,1,2,3,4],"total":1234,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"marzlevanes":3,"version":"1.2.3","date":"Tue Jun 23 18:47:09 UTC 2015", "__warning": {"program":"gt_01.test","message":"Nableuay otay ectulatobjay orwardfay elocipingvay","verb":"ectulatobjay","error":"Ermissionpay eniedday"}, "__warning": {"program":"gt_01.test","message":"automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay","style":"automaticyay","type":"ardinalyay","target":"ammetersgray","error":"Ermissionpay eniedday"},"marzlevanes":6,"windings":"otuslay-oyay-eltayay"}}
{"top": {"adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay","adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay", "bytes": [0,1,2,3,4],"total":1234,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"marzlevanes":3,"version":"1.2.3","date":"Tue Jun 23 18:47:09 UTC 2015", "__warning": {"program":"gt_01","message":"Nableuay otay ectulatobjay orwardfay elocipingvay","verb":"ectulatobjay","error":"Ermissionpay eniedday"}, "__warning": {"program":"gt_01","message":"automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay","style":"automaticyay","type":"ardinalyay","target":"ammetersgray","error":"Ermissionpay eniedday"},"marzlevanes":6,"windings":"otuslay-oyay-eltayay"}}

View file

@ -34,13 +34,13 @@
"version": "1.2.3",
"date": "Tue Jun 23 18:47:09 UTC 2015",
"__warning": {
"program": "gt_01.test",
"program": "gt_01",
"message": "Nableuay otay ectulatobjay orwardfay elocipingvay",
"verb": "ectulatobjay",
"error": "Ermissionpay eniedday"
},
"__warning": {
"program": "gt_01.test",
"program": "gt_01",
"message": "automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay",
"style": "automaticyay",
"type": "ardinalyay",

View file

@ -11,7 +11,7 @@ Received 1234 yezbay from foop#4321 in 32 ms
Eceivedray 1234 ldb2 omfray foop#4321 inyay 32 msyay
Onlyay 3 arzlevanezmay areyay unctioningfay orrectlycay
Ersionvay Tue Jun 23 18:47:09 UTC 2015 1.2.3
gt_01.test: Nableuay otay ectulatobjay orwardfay elocipingvay: Ermissionpay eniedday
gt_01.test: automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay: Ermissionpay eniedday
gt_01: Nableuay otay ectulatobjay orwardfay elocipingvay: Ermissionpay eniedday
gt_01: automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay: Ermissionpay eniedday
ydrocoptichay arzlevanesmay: 6
Dude, Indingsway: otuslay-oyay-eltayay

View file

@ -1 +1 @@
<top><adjective>amingflay</adjective><noun>ordsway</noun><verb>urningbay</verb><owner>ymay</owner><target>ouchcay</target><adjective>amingflay</adjective><noun>ordsway</noun><verb>urningbay</verb><owner>ymay</owner><target>ouchcay</target><bytes>0</bytes><bytes>1</bytes><bytes>2</bytes><bytes>3</bytes><bytes>4</bytes><total>1234</total><received>1234</received><from>foop</from><port>4321</port><time>32</time><received>1234</received><from>foop</from><port>4321</port><time>32</time><received>1234</received><from>foop</from><port>4321</port><time>32</time><marzlevanes>3</marzlevanes><version>1.2.3</version><date>Tue Jun 23 18:47:09 UTC 2015</date><__warning><program>gt_01.test</program><message>Nableuay otay ectulatobjay orwardfay elocipingvay</message><verb>ectulatobjay</verb><error>Ermissionpay eniedday</error></__warning><__warning><program>gt_01.test</program><message>automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay</message><style>automaticyay</style><type>ardinalyay</type><target>ammetersgray</target><error>Ermissionpay eniedday</error></__warning><marzlevanes>6</marzlevanes><windings>otuslay-oyay-eltayay</windings></top>
<top><adjective>amingflay</adjective><noun>ordsway</noun><verb>urningbay</verb><owner>ymay</owner><target>ouchcay</target><adjective>amingflay</adjective><noun>ordsway</noun><verb>urningbay</verb><owner>ymay</owner><target>ouchcay</target><bytes>0</bytes><bytes>1</bytes><bytes>2</bytes><bytes>3</bytes><bytes>4</bytes><total>1234</total><received>1234</received><from>foop</from><port>4321</port><time>32</time><received>1234</received><from>foop</from><port>4321</port><time>32</time><received>1234</received><from>foop</from><port>4321</port><time>32</time><marzlevanes>3</marzlevanes><version>1.2.3</version><date>Tue Jun 23 18:47:09 UTC 2015</date><__warning><program>gt_01</program><message>Nableuay otay ectulatobjay orwardfay elocipingvay</message><verb>ectulatobjay</verb><error>Ermissionpay eniedday</error></__warning><__warning><program>gt_01</program><message>automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay</message><style>automaticyay</style><type>ardinalyay</type><target>ammetersgray</target><error>Ermissionpay eniedday</error></__warning><marzlevanes>6</marzlevanes><windings>otuslay-oyay-eltayay</windings></top>

View file

@ -31,13 +31,13 @@
<version>1.2.3</version>
<date>Tue Jun 23 18:47:09 UTC 2015</date>
<__warning>
<program>gt_01.test</program>
<program>gt_01</program>
<message>Nableuay otay ectulatobjay orwardfay elocipingvay</message>
<verb>ectulatobjay</verb>
<error>Ermissionpay eniedday</error>
</__warning>
<__warning>
<program>gt_01.test</program>
<program>gt_01</program>
<message>automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay</message>
<style>automaticyay</style>
<type>ardinalyay</type>

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -6,6 +6,7 @@ Usage: xo [options] format [fields]
--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> OR -l <path> Add a prefix to generated XPaths (HTML)
--not-first Indicate this object is not the first (JSON)

View file

@ -201,6 +201,7 @@ print_help (void)
" --depth <num> Set the depth for pretty printing\n"
" --help Display this help text\n"
" --html OR -H Generate HTML output\n"
" --instance OR -I <name> Wrap in an instance of the given name\n"
" --json OR -J Generate JSON output\n"
" --leading-xpath <path> OR -l <path> "
"Add a prefix to generated XPaths (HTML)\n"
@ -245,6 +246,7 @@ static struct option long_opts[] = {
{ "depth", required_argument, &opts.o_depth, 1 },
{ "help", no_argument, &opts.o_help, 1 },
{ "html", no_argument, NULL, 'H' },
{ "instance", required_argument, NULL, 'I' },
{ "json", no_argument, NULL, 'J' },
{ "leading-xpath", required_argument, NULL, 'l' },
{ "not-first", no_argument, &opts.o_not_first, 1 },
@ -271,6 +273,7 @@ main (int argc UNUSED, char **argv)
char *fmt = NULL, *cp, *np;
char *opt_opener = NULL, *opt_closer = NULL, *opt_wrapper = NULL;
char *opt_options = NULL;
char *opt_instance = NULL;
char *opt_name = NULL;
xo_state_t new_state = 0;
int opt_depth = 0;
@ -298,6 +301,10 @@ main (int argc UNUSED, char **argv)
xo_set_style(NULL, XO_STYLE_HTML);
break;
case 'I':
opt_instance = optarg;
break;
case 'J':
xo_set_style(NULL, XO_STYLE_JSON);
break;
@ -496,12 +503,18 @@ main (int argc UNUSED, char **argv)
}
}
if (opt_instance)
xo_open_instance(opt_instance);
/* If there's a format string, call xo_emit to emit the contents */
if (fmt && *fmt) {
save_argv = argv;
prep_arg(fmt);
xo_emit(fmt); /* This call does the real formatting */
}
if (opt_instance)
xo_close_instance(opt_instance);
/* If there's an wrapper hierarchy, close each element's container */
while (opt_wrapper) {

View file

@ -98,16 +98,18 @@ sub extract_docs {
$need_nl = 0;
}
print "*** '$_'\n\n";
print "The message \"$_\" can be caused by code like:\n\n";
$under = "+" x (length($_) + 2);
print "'$_'\n$under\n\n";
print "The message \"$_\" can be caused by code like:\n";
$new = 0;
} elsif (/xo_emit\s*\(/) {
s/^\s+//;
print " $_\n\n";
print "\n::\n\n $_\n\n";
} elsif (/^Should be/i) {
print "This code should be replaced with code like:\n\n";
print "This code should be replaced with code like:\n";
} else {
print "$_\n";

View file

@ -114,4 +114,6 @@ MLINKS= xo_attr.3 xo_attr_h.3 \
HAS_TESTS=
SUBDIR.${MK_TESTS}+= tests
SUBDIR = encoder
.include <bsd.lib.mk>

View file

@ -3,10 +3,10 @@
.Fx
uses
.Nm libxo
version 1.0.4.
version 1.3.0.
Complete documentation can be found on github:
.Bd -literal -offset indent
http://juniper.github.io/libxo/1.0.4/libxo\-manual.html
https://juniper.github.io/libxo/1.3.0/html/index.html
.Ed
.Pp
.Nm libxo

View file

@ -0,0 +1,13 @@
# $FreeBSD$
SHLIBDIR?= /lib
.include <src.opts.mk>
PACKAGE= runtime
LIBXOSRC= ${SRCTOP}/contrib/libxo
SUBDIR = csv
.include <bsd.subdir.mk>

View file

@ -0,0 +1,29 @@
# $FreeBSD$
LIBXODIR= ${STAGEDIR}${PREFIX}/usr/lib/libxo/encoder
SHLIBDIR?= ${LIBXODIR}
LIBDIR?= ${LIBXODIR}
.include <src.opts.mk>
PACKAGE= runtime
LIBXOSRC= ${SRCTOP}/contrib/libxo
.PATH: ${LIBXOSRC}/encoder/csv
LIB= enc_csv
SHLIB_MAJOR=0
SRCS= enc_csv.c
CFLAGS+=-I${LIBXOSRC}/libxo -I${.CURDIR}
CFLAGS+=-DXO_ENCODERDIR=\"/usr/lib/libxo/encoder\"
LIBADD= util xo
WARNS?= 5
SYMLINKS+= ${SHLIB_NAME} ${LIBXODIR}/csv.enc
.include <bsd.lib.mk>

View file

@ -183,16 +183,16 @@
/* #undef LIBXO_TEXT_ONLY */
/* Version number as dotted value */
#define LIBXO_VERSION "1.0.4"
#define LIBXO_VERSION "1.3.0"
/* Version number extra information */
#define LIBXO_VERSION_EXTRA ""
/* Version number as a number */
#define LIBXO_VERSION_NUMBER 1000004
#define LIBXO_VERSION_NUMBER 1003000
/* Version number as string */
#define LIBXO_VERSION_STRING "1000004"
#define LIBXO_VERSION_STRING "1003000"
/* Enable local wcwidth implementation */
#define LIBXO_WCWIDTH 1
@ -210,7 +210,7 @@
#define PACKAGE_NAME "libxo"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libxo 1.0.4"
#define PACKAGE_STRING "libxo 1.3.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libxo"
@ -219,7 +219,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.0.4"
#define PACKAGE_VERSION "1.3.0"
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
@ -236,7 +236,7 @@
/* #undef USE_INT_RETURN_CODES */
/* Version number of package */
#define VERSION "1.0.4"
#define VERSION "1.3.0"
/* Retain hash bucket size */
/* #undef XO_RETAIN_SIZE */

View file

@ -12,7 +12,7 @@
#
BASE=/usr/share/libxo
VERSION=1.0.4
VERSION=1.3.0
CMD=cat
DONE=
WEB=http://juniper.github.io/libxo/${VERSION}/xohtml