mirror of https://git.FreeBSD.org/src.git
Merge commit '7087c8de43b0d5d27c52da6ba2ba4957b7e336ff' into new_merge
This commit is contained in:
commit
34b867ca30
|
@ -1,46 +1,32 @@
|
|||
# Object files
|
||||
*.o
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.app
|
||||
|
||||
*~
|
||||
*.orig
|
||||
|
||||
tag.sh
|
||||
Makefile.in
|
||||
aclocal.m4
|
||||
ar-lib
|
||||
autom4te.cache
|
||||
build
|
||||
bin
|
||||
build*
|
||||
compile
|
||||
configure
|
||||
config.guess
|
||||
config.h.in
|
||||
config.sub
|
||||
depcomp
|
||||
doc/Makefile.in
|
||||
info*
|
||||
install-sh
|
||||
ltmain.sh
|
||||
missing
|
||||
m4
|
||||
|
||||
Makefile.in
|
||||
configure
|
||||
.DS_Store
|
||||
|
||||
xoconfig.h.in
|
||||
xo_config.h.in
|
||||
|
||||
.gdbinit
|
||||
.gdbinit.local
|
||||
xtest
|
||||
xtest.dSYM
|
||||
tests/w
|
||||
missing
|
||||
patches*
|
||||
doc/Makefile.in
|
||||
encoder/Makefile.in
|
||||
encoder/cbor/Makefile.in
|
||||
encoder/test/Makefile.in
|
||||
libxo/Makefile.in
|
||||
tests/Makefile.in
|
||||
tests/core/Makefile.in
|
||||
tests/gettext/Makefile.in
|
||||
tests/xo/Makefile.in
|
||||
xo/Makefile.in
|
||||
xohtml/Makefile.in
|
||||
xolint/Makefile.in
|
||||
xopo/Makefile.in
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
Makefile.in
|
||||
aclocal.m4
|
||||
ar-lib
|
||||
autom4te.cache
|
||||
bin*
|
||||
build*
|
||||
compile
|
||||
configure
|
||||
config.guess
|
||||
config.sub
|
||||
depcomp
|
||||
doc/Makefile.in
|
||||
info*
|
||||
install-sh
|
||||
ltmain.sh
|
||||
m4
|
||||
missing
|
||||
patches*
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
SUBDIRS = libxo xo xopo xolint xohtml tests doc encoder
|
||||
SUBDIRS = bin libxo xo xopo xolint xohtml tests doc encoder
|
||||
bin_SCRIPTS=libxo-config
|
||||
dist_doc_DATA = Copyright
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
# a particular user has the dist or svn release.
|
||||
#
|
||||
|
||||
AC_PREREQ(2.2)
|
||||
AC_INIT([libxo], [1.4.0], [phil@juniper.net])
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([libxo],[1.6.0],[phil@juniper.net])
|
||||
AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
|
||||
|
||||
# Support silent build rules. Requires at least automake-1.11.
|
||||
|
@ -38,8 +38,6 @@ AC_PATH_PROG(MV, mv, /bin/mv)
|
|||
AC_PATH_PROG(RM, rm, /bin/rm)
|
||||
AC_PATH_PROG(SED, sed, /bin/sed)
|
||||
|
||||
AC_STDC_HEADERS
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_C_INLINE
|
||||
AC_TYPE_SIZE_T
|
||||
|
@ -335,9 +333,10 @@ AM_CONDITIONAL([HAVE_LIBM], [test "$HAVE_LIBM" != "no"])
|
|||
AC_MSG_CHECKING([compiler for gcc])
|
||||
HAVE_GCC=no
|
||||
if test "${CC}" != ""; then
|
||||
HAVE_GCC=`${CC} --version 2>&1 | grep GCC`
|
||||
HAVE_GCC=`${CC} --version 2>&1 | grep -i GCC`
|
||||
if test "${HAVE_GCC}" != ""; then
|
||||
HAVE_GCC=yes
|
||||
AC_DEFINE([HAVE_GCC], [1], [Using real gcc])
|
||||
else
|
||||
HAVE_GCC=no
|
||||
fi
|
||||
|
@ -450,6 +449,7 @@ AC_CONFIG_FILES([
|
|||
xohtml/xohtml.sh
|
||||
libxo/Makefile
|
||||
libxo/add.man
|
||||
bin/Makefile
|
||||
encoder/Makefile
|
||||
encoder/cbor/Makefile
|
||||
encoder/csv/Makefile
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
# using the SOFTWARE, you agree to be bound by the terms of that
|
||||
# LICENSE.
|
||||
|
||||
doc docs: xolint.rst html
|
||||
doc docs: xolint-errors.rst html
|
||||
|
||||
#
|
||||
# The contents of xolint.rst is generated based on xolint.pl, since we
|
||||
|
@ -17,8 +17,8 @@ doc docs: xolint.rst html
|
|||
# the developer needs to commit any changes.
|
||||
#
|
||||
|
||||
xolint.rst: ${top_srcdir}/xolint/xolint.pl
|
||||
perl ${top_srcdir}/xolint/xolint.pl -D > ${top_srcdir}/doc/xolint.rst
|
||||
xolint-errors.rst: ${top_srcdir}/xolint/xolint.pl
|
||||
perl ${top_srcdir}/xolint/xolint.pl -D > ${top_srcdir}/doc/xolint-errors.rst
|
||||
|
||||
SPHINX = python3 -msphinx
|
||||
|
||||
|
|
|
@ -386,19 +386,18 @@ xo_destroy
|
|||
Emitting Content (xo_emit)
|
||||
--------------------------
|
||||
|
||||
The functions in this section are used to emit output.
|
||||
|
||||
The "fmt" argument is a string containing field descriptors as
|
||||
specified in :ref:`format-strings`. The use of a handle is optional and
|
||||
`NULL` can be passed to access the internal "default" handle. See
|
||||
The functions in this section are used to emit output. They use a
|
||||
`format` string containing field descriptors as specified in
|
||||
:ref:`format-strings`. The use of a handle is optional and `NULL` can
|
||||
be passed to access the internal "default" handle. See
|
||||
:ref:`handles`.
|
||||
|
||||
The remaining arguments to `xo_emit` and `xo_emit_h` are a set of
|
||||
arguments corresponding to the fields in the format string. Care must
|
||||
be taken to ensure the argument types match the fields in the format
|
||||
string, since an inappropriate cast can ruin your day. The vap
|
||||
argument to `xo_emit_hv` points to a variable argument list that can
|
||||
be used to retrieve arguments via `va_arg`.
|
||||
string, since an inappropriate or missing argument can ruin your day.
|
||||
The `vap` argument to `xo_emit_hv` points to a variable argument list
|
||||
that can be used to retrieve arguments via `va_arg`.
|
||||
|
||||
.. c:function:: xo_ssize_t xo_emit (const char *fmt, ...)
|
||||
|
||||
|
@ -428,19 +427,40 @@ be used to retrieve arguments via `va_arg`.
|
|||
Single Field Emitting Functions (xo_emit_field)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The functions in this section can also make output, but only make a
|
||||
single field at a time. These functions are intended to avoid the
|
||||
scenario where one would otherwise need to compose a format
|
||||
descriptors using `snprintf`. The individual parts of the format
|
||||
descriptor are passed in distinctly.
|
||||
The functions in this section emit formatted output similar to
|
||||
`xo_emit` but where `xo_emit` uses a single string argument containing
|
||||
the description for multiple fields, `xo_emit_field` emits a single
|
||||
field using multiple ar- guments to contain the field description.
|
||||
`xo_emit_field_h` adds an ex- plicit handle to use instead of the
|
||||
default handle, while `xo_emit_field_hv` accepts a va_list for
|
||||
additional flexibility.
|
||||
|
||||
.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...)
|
||||
The arguments `rolmod`, `content`, `fmt`, and `efmt` are detailed in
|
||||
:ref:`field-formatting`. Using distinct arguments allows callers to
|
||||
pass the field description in pieces, rather than having to use
|
||||
something like `snprintf` to build the format string required by
|
||||
`xo_emit`. The arguments are each NUL-terminated strings. The `rolmod`
|
||||
argument contains the `role` and `modifier` portions of the field
|
||||
description, the `content` argument contains the `content` portion, and
|
||||
the `fmt` and `efmt` contain the `field-format` and `encoding-format` por-
|
||||
tions, respectively.
|
||||
|
||||
As with `xo_emit`, the `fmt` and `efmt` values are both optional,
|
||||
since the `field-format` string defaults to "%s", and the
|
||||
`encoding-format`'s default value is derived from the `field-format`
|
||||
per :ref:`field-formatting`. However, care must be taken to avoid
|
||||
using a value directly as the format, since characters like '{', '%',
|
||||
and '}' will be interpreted as formatting directives, and may cause
|
||||
xo_emit_field to dereference arbitrary values off the stack, leading
|
||||
to bugs, core files, and gnashing of teeth.
|
||||
|
||||
.. c:function:: xo_ssize_t xo_emit_field (const char *rolmod, const char *content, const char *fmt, const char *efmt, ...)
|
||||
|
||||
:param rolmod: A comma-separated list of field roles and field modifiers
|
||||
:type rolmod: const char *
|
||||
:param contents: The "contents" portion of the field description string
|
||||
:type contents: const char *
|
||||
:param fmt: Content format string
|
||||
:param content: The "content" portion of the field description string
|
||||
:type content: const char *
|
||||
:param fmt: Contents format string
|
||||
:type fmt: const char *
|
||||
:param efmt: Encoding format string, followed by additional arguments
|
||||
:type efmt: const char *
|
||||
|
@ -450,8 +470,11 @@ descriptor are passed in distinctly.
|
|||
::
|
||||
|
||||
EXAMPLE::
|
||||
xo_emit_field("T", title, NULL, NULL, NULL);
|
||||
xo_emit_field("T", "Host name is ", NULL, NULL);
|
||||
xo_emit_field("V", "host-name", NULL, NULL, host-name);
|
||||
xo_emit_field(",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u",
|
||||
"gum", 1412);
|
||||
|
||||
.. c:function:: xo_ssize_t xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents, const char *fmt, const char *efmt, ...)
|
||||
|
||||
|
|
|
@ -205,4 +205,7 @@ a difference, change the names to make that difference more obvious.
|
|||
What does this message mean?
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. include:: xolint.rst
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
xolint-errors.rst
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
.. index:: Field Formatting
|
||||
.. _field-formatting:
|
||||
|
||||
Field Formatting
|
||||
----------------
|
||||
|
|
|
@ -180,6 +180,11 @@ Labels are text that appears before a value::
|
|||
|
||||
xo_emit("{Lwc:Cost}{:cost/%u}\n", cost);
|
||||
|
||||
If a label needs to include a slash, it must be escaped using two
|
||||
backslashes, one for the C compiler and one for libxo::
|
||||
|
||||
xo_emit("{Lc:Low\\/warn level}{:level/%s}\n", level);
|
||||
|
||||
.. index:: Field Roles; Note
|
||||
.. _note-role:
|
||||
|
||||
|
|
|
@ -0,0 +1,444 @@
|
|||
'A percent sign appearing in text is a literal'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "A percent sign appearing in text is a literal" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("cost: %d", cost);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{L:cost}: {:cost/%d}", cost);
|
||||
|
||||
This can be a bit surprising and could be a field that was not
|
||||
properly converted to a libxo-style format string.
|
||||
|
||||
|
||||
'Unknown long name for role/modifier'
|
||||
+++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Unknown long name for role/modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanization:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanize:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Last character before field definition is a field type'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Last character before field definition is a field type" can be caused by code like:
|
||||
A common typo:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} T{:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} {T:Max}");
|
||||
|
||||
Twiddling the "{" and the field role is a common typo.
|
||||
|
||||
|
||||
'Encoding format uses different number of arguments'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Encoding format uses different number of arguments" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %%04d/%s}", name, number);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %04d/%s-%d}", name, number);
|
||||
|
||||
Both format should consume the same number of arguments off the stack
|
||||
|
||||
|
||||
'Only one field role can be used'
|
||||
+++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Only one field role can be used" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{LT:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max}");
|
||||
|
||||
'Potential missing slash after C, D, N, L, or T with format'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:%6.6s}\n", "Max");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:/%6.6s}\n", "Max");
|
||||
|
||||
The "%6.6s" will be a literal, not a field format. While
|
||||
it's possibly valid, it's likely a missing "/".
|
||||
|
||||
|
||||
'An encoding format cannot be given (roles: DNLT)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max//%s}", "Max");
|
||||
|
||||
Fields with the C, D, N, L, and T roles are not emitted in
|
||||
the 'encoding' style (JSON, XML), so an encoding format
|
||||
would make no sense.
|
||||
|
||||
|
||||
'Format cannot be given when content is present (roles: CDLN)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{N:Max/%6.6s}", "Max");
|
||||
|
||||
Fields with the C, D, L, or N roles can't have both
|
||||
static literal content ("{L:Label}") and a
|
||||
format ("{L:/%s}").
|
||||
This error will also occur when the content has a backslash
|
||||
in it, like "{N:Type of I/O}"; backslashes should be escaped,
|
||||
like "{N:Type of I\\/O}". Note the double backslash, one for
|
||||
handling 'C' strings, and one for libxo.
|
||||
|
||||
|
||||
'Field has color without fg- or bg- (role: C)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has color without fg- or bg- (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:green}{:foo}{C:}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-green}{:foo}{C:}", x);
|
||||
|
||||
Colors must be prefixed by either "fg-" or "bg-".
|
||||
|
||||
|
||||
'Field has invalid color or effect (role: C)'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has invalid color or effect (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x);
|
||||
|
||||
The list of colors and effects are limited. The
|
||||
set of colors includes default, black, red, green,
|
||||
yellow, blue, magenta, cyan, and white, which must
|
||||
be prefixed by either "fg-" or "bg-". Effects are
|
||||
limited to bold, no-bold, underline, no-underline,
|
||||
inverse, no-inverse, normal, and reset. Values must
|
||||
be separated by commas.
|
||||
|
||||
|
||||
'Field has humanize modifier but no format string'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has humanize modifier but no format string" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value/%d}", value);
|
||||
|
||||
Humanization is only value for numbers, which are not
|
||||
likely to use the default format ("%s").
|
||||
|
||||
|
||||
'Field has hn-* modifier but not 'h' modifier'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,hn-1000:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h,hn-1000:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Value field must have a name (as content)")'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field must have a name (as content)")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:/%s}", "value");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag-name/%s}", "value");
|
||||
|
||||
The field name is used for XML and JSON encodings. These
|
||||
tags names are static and must appear directly in the
|
||||
field descriptor.
|
||||
|
||||
|
||||
'Use hyphens, not underscores, for value field name'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Use hyphens, not underscores, for value field name" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no_under_scores}", "bad");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no-under-scores}", "bad");
|
||||
|
||||
Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
|
||||
flag can be used to generate underscores in JSON, if desired.
|
||||
But the raw field name should use hyphens.
|
||||
|
||||
|
||||
'Value field name cannot start with digit'
|
||||
++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name cannot start with digit" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:10-gig/}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:ten-gig/}");
|
||||
|
||||
XML element names cannot start with a digit.
|
||||
|
||||
|
||||
'Value field name should be lower case'
|
||||
+++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be lower case" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:why-are-you-shouting}", "no reason");
|
||||
|
||||
Lower case is more civilized. Even TLAs should be lower case
|
||||
to avoid scenarios where the differences between "XPath" and
|
||||
"Xpath" drive your users crazy. Lower case rules the seas.
|
||||
|
||||
|
||||
'Value field name should be longer than two characters'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be longer than two characters" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:x}", "mumble");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:something-meaningful}", "mumble");
|
||||
|
||||
Field names should be descriptive, and it's hard to
|
||||
be descriptive in less than two characters. Consider
|
||||
your users and try to make something more useful.
|
||||
Note that this error often occurs when the field type
|
||||
is placed after the colon ("{:T/%20s}"), instead of before
|
||||
it ("{T:/20s}").
|
||||
|
||||
|
||||
'Value field name contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-$$/%u}", 15);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-dollars/%u}", 15);
|
||||
|
||||
An invalid character is often a sign of a typo, like "{:]}"
|
||||
instead of "{]:}". Field names are restricted to lower-case
|
||||
characters, digits, and hyphens.
|
||||
|
||||
|
||||
'decoration field contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "decoration field contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:not good}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:((}{:good}{D:))}", "yes");
|
||||
|
||||
This is minor, but fields should use proper roles. Decoration
|
||||
fields are meant to hold punctuation and other characters used
|
||||
to decorate the content, typically to make it more readable
|
||||
to human readers.
|
||||
|
||||
|
||||
'Anchor content should be decimal width'
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor content should be decimal width" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:mumble}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors need an integer value to specify the width of
|
||||
the set of anchored fields. The value can be positive
|
||||
(for left padding/right justification) or negative (for
|
||||
right padding/left justification) and can appear in
|
||||
either the start or stop anchor field descriptor.
|
||||
|
||||
|
||||
'Anchor format should be "%d"'
|
||||
++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor format should be "%d"" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%s}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%d}");
|
||||
|
||||
Anchors only grok integer values, and if the value is not static,
|
||||
if must be in an 'int' argument, represented by the "%d" format.
|
||||
Anything else is an error.
|
||||
|
||||
|
||||
'Anchor cannot have both format and encoding format")'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor cannot have both format and encoding format")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32/%d}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors can have a static value or argument for the width,
|
||||
but cannot have both.
|
||||
|
||||
|
||||
'Max width only valid for strings'
|
||||
++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Max width only valid for strings" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.4.6d}", 55);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.6d}", 55);
|
||||
|
||||
libxo allows a true 'max width' in addition to the traditional
|
||||
printf-style 'max number of bytes to use for input'. But this
|
||||
is supported only for string values, since it makes no sense
|
||||
for non-strings. This error may occur from a typo,
|
||||
like "{:tag/%6..6d}" where only one period should be used.
|
|
@ -1,444 +1,40 @@
|
|||
'A percent sign appearing in text is a literal'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "A percent sign appearing in text is a literal" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("cost: %d", cost);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{L:cost}: {:cost/%d}", cost);
|
||||
|
||||
This can be a bit surprising and could be a field that was not
|
||||
properly converted to a libxo-style format string.
|
||||
|
||||
|
||||
'Unknown long name for role/modifier'
|
||||
+++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Unknown long name for role/modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanization:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,humanize:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Last character before field definition is a field type'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Last character before field definition is a field type" can be caused by code like:
|
||||
A common typo:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} T{:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Min} {T:Max}");
|
||||
|
||||
Twiddling the "{" and the field role is a common typo.
|
||||
|
||||
|
||||
'Encoding format uses different number of arguments'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Encoding format uses different number of arguments" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %%04d/%s}", name, number);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:name/%6.6s %04d/%s-%d}", name, number);
|
||||
|
||||
Both format should consume the same number of arguments off the stack
|
||||
|
||||
|
||||
'Only one field role can be used'
|
||||
+++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Only one field role can be used" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{LT:Max}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max}");
|
||||
|
||||
'Potential missing slash after C, D, N, L, or T with format'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Potential missing slash after C, D, N, L, or T with format" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:%6.6s}\n", "Max");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:/%6.6s}\n", "Max");
|
||||
|
||||
The "%6.6s" will be a literal, not a field format. While
|
||||
it's possibly valid, it's likely a missing "/".
|
||||
|
||||
|
||||
'An encoding format cannot be given (roles: DNLT)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "An encoding format cannot be given (roles: DNLT)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{T:Max//%s}", "Max");
|
||||
|
||||
Fields with the C, D, N, L, and T roles are not emitted in
|
||||
the 'encoding' style (JSON, XML), so an encoding format
|
||||
would make no sense.
|
||||
|
||||
|
||||
'Format cannot be given when content is present (roles: CDLN)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Format cannot be given when content is present (roles: CDLN)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{N:Max/%6.6s}", "Max");
|
||||
|
||||
Fields with the C, D, L, or N roles can't have both
|
||||
static literal content ("{L:Label}") and a
|
||||
format ("{L:/%s}").
|
||||
This error will also occur when the content has a backslash
|
||||
in it, like "{N:Type of I/O}"; backslashes should be escaped,
|
||||
like "{N:Type of I\\/O}". Note the double backslash, one for
|
||||
handling 'C' strings, and one for libxo.
|
||||
|
||||
|
||||
'Field has color without fg- or bg- (role: C)'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has color without fg- or bg- (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:green}{:foo}{C:}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-green}{:foo}{C:}", x);
|
||||
|
||||
Colors must be prefixed by either "fg-" or "bg-".
|
||||
|
||||
|
||||
'Field has invalid color or effect (role: C)'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has invalid color or effect (role: C)" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-purple,bold}{:foo}{C:gween}", x);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{C:fg-red,bold}{:foo}{C:fg-green}", x);
|
||||
|
||||
The list of colors and effects are limited. The
|
||||
set of colors includes default, black, red, green,
|
||||
yellow, blue, magenta, cyan, and white, which must
|
||||
be prefixed by either "fg-" or "bg-". Effects are
|
||||
limited to bold, no-bold, underline, no-underline,
|
||||
inverse, no-inverse, normal, and reset. Values must
|
||||
be separated by commas.
|
||||
|
||||
|
||||
'Field has humanize modifier but no format string'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has humanize modifier but no format string" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h:value/%d}", value);
|
||||
|
||||
Humanization is only value for numbers, which are not
|
||||
likely to use the default format ("%s").
|
||||
|
||||
|
||||
'Field has hn-* modifier but not 'h' modifier'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Field has hn-* modifier but not 'h' modifier" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{,hn-1000:value}", value);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{h,hn-1000:value}", value);
|
||||
|
||||
The hn-* modifiers (hn-decimal, hn-space, hn-1000)
|
||||
are only valid for fields with the {h:} modifier.
|
||||
|
||||
|
||||
'Value field must have a name (as content)")'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field must have a name (as content)")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:/%s}", "value");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag-name/%s}", "value");
|
||||
|
||||
The field name is used for XML and JSON encodings. These
|
||||
tags names are static and must appear directly in the
|
||||
field descriptor.
|
||||
|
||||
|
||||
'Use hyphens, not underscores, for value field name'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Use hyphens, not underscores, for value field name" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no_under_scores}", "bad");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:no-under-scores}", "bad");
|
||||
|
||||
Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
|
||||
flag can be used to generate underscores in JSON, if desired.
|
||||
But the raw field name should use hyphens.
|
||||
|
||||
|
||||
'Value field name cannot start with digit'
|
||||
++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name cannot start with digit" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:10-gig/}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:ten-gig/}");
|
||||
|
||||
XML element names cannot start with a digit.
|
||||
|
||||
|
||||
'Value field name should be lower case'
|
||||
+++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be lower case" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:WHY-ARE-YOU-SHOUTING}", "NO REASON");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:why-are-you-shouting}", "no reason");
|
||||
|
||||
Lower case is more civilized. Even TLAs should be lower case
|
||||
to avoid scenarios where the differences between "XPath" and
|
||||
"Xpath" drive your users crazy. Lower case rules the seas.
|
||||
|
||||
|
||||
'Value field name should be longer than two characters'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name should be longer than two characters" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:x}", "mumble");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:something-meaningful}", "mumble");
|
||||
|
||||
Field names should be descriptive, and it's hard to
|
||||
be descriptive in less than two characters. Consider
|
||||
your users and try to make something more useful.
|
||||
Note that this error often occurs when the field type
|
||||
is placed after the colon ("{:T/%20s}"), instead of before
|
||||
it ("{T:/20s}").
|
||||
|
||||
|
||||
'Value field name contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Value field name contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-$$/%u}", 15);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:cost-in-dollars/%u}", 15);
|
||||
|
||||
An invalid character is often a sign of a typo, like "{:]}"
|
||||
instead of "{]:}". Field names are restricted to lower-case
|
||||
characters, digits, and hyphens.
|
||||
|
||||
|
||||
'decoration field contains invalid character'
|
||||
+++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "decoration field contains invalid character" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:not good}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{D:((}{:good}{D:))}", "yes");
|
||||
|
||||
This is minor, but fields should use proper roles. Decoration
|
||||
fields are meant to hold punctuation and other characters used
|
||||
to decorate the content, typically to make it more readable
|
||||
to human readers.
|
||||
|
||||
|
||||
'Anchor content should be decimal width'
|
||||
++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor content should be decimal width" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:mumble}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors need an integer value to specify the width of
|
||||
the set of anchored fields. The value can be positive
|
||||
(for left padding/right justification) or negative (for
|
||||
right padding/left justification) and can appear in
|
||||
either the start or stop anchor field descriptor.
|
||||
|
||||
|
||||
'Anchor format should be "%d"'
|
||||
++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor format should be "%d"" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%s}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:/%d}");
|
||||
|
||||
Anchors only grok integer values, and if the value is not static,
|
||||
if must be in an 'int' argument, represented by the "%d" format.
|
||||
Anything else is an error.
|
||||
|
||||
|
||||
'Anchor cannot have both format and encoding format")'
|
||||
++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Anchor cannot have both format and encoding format")" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32/%d}");
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{[:32}");
|
||||
|
||||
Anchors can have a static value or argument for the width,
|
||||
but cannot have both.
|
||||
|
||||
|
||||
'Max width only valid for strings'
|
||||
++++++++++++++++++++++++++++++++++
|
||||
|
||||
The message "Max width only valid for strings" can be caused by code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.4.6d}", 55);
|
||||
|
||||
This code should be replaced with code like:
|
||||
|
||||
::
|
||||
|
||||
xo_emit("{:tag/%2.6d}", 55);
|
||||
|
||||
libxo allows a true 'max width' in addition to the traditional
|
||||
printf-style 'max number of bytes to use for input'. But this
|
||||
is supported only for string values, since it makes no sense
|
||||
for non-strings. This error may occur from a typo,
|
||||
like "{:tag/%6..6d}" where only one period should be used.
|
||||
======
|
||||
xolint
|
||||
======
|
||||
|
||||
`xolint` is a tool for reporting common mistakes in format strings
|
||||
in source code that invokes `xo_emit`. It allows these errors
|
||||
to be diagnosed at build time, rather than waiting until runtime.
|
||||
|
||||
`xolint` takes the one or more C files as arguments, and reports
|
||||
and errors, warning, or informational messages as needed:
|
||||
|
||||
============ ===================================================
|
||||
Option Meaning
|
||||
============ ===================================================
|
||||
-c Invoke 'cpp' against the input file
|
||||
-C <flags> Flags that are passed to 'cpp
|
||||
-d Enable debug output
|
||||
-D Generate documentation for all xolint messages
|
||||
-I Generate info table code
|
||||
-p Print the offending lines after the message
|
||||
-V Print vocabulary of all field names
|
||||
-X Extract samples from xolint, suitable for testing
|
||||
============ ===================================================
|
||||
|
||||
The output message will contain the source filename and line number, the
|
||||
class of the message, the message, and, if -p is given, the
|
||||
line that contains the error::
|
||||
|
||||
% xolint.pl -t xolint.c
|
||||
xolint.c: 16: error: anchor format should be "%d"
|
||||
16 xo_emit("{[:/%s}");
|
||||
|
||||
The "-I" option will generate a table of `xo_info_t`_ structures,
|
||||
suitable for inclusion in source code.
|
||||
|
||||
.. _xo_info_t: :ref:`field-information`
|
||||
|
||||
The "-V" option does not report errors, but prints a complete list of
|
||||
all field names, sorted alphabetically. The output can help spot
|
||||
inconsistencies and spelling errors.
|
||||
|
|
|
@ -74,6 +74,7 @@ man5_files = \
|
|||
xo_format.5
|
||||
|
||||
man7_files = \
|
||||
libxo-csv.7 \
|
||||
xo_options.7
|
||||
|
||||
man_MANS = ${man3_files} ${man5_files} ${man7_files}
|
||||
|
|
|
@ -0,0 +1,274 @@
|
|||
.\" #
|
||||
.\" # Copyright (c) 2021, Juniper Networks, Inc.
|
||||
.\" # All rights reserved.
|
||||
.\" # This SOFTWARE is licensed under the LICENSE provided in the
|
||||
.\" # ../Copyright file. By downloading, installing, copying, or
|
||||
.\" # using the SOFTWARE, you agree to be bound by the terms of that
|
||||
.\" # LICENSE.
|
||||
.\" # Phil Shafer, May 2021
|
||||
.\"
|
||||
.Dd May 13, 2021
|
||||
.Dt LIBXO-CSV 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm --libxo encoder=csv[+options]
|
||||
.Nd a CVS encoder for libxo\-based commands
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm libxo
|
||||
library supports a "pluggable" encoder mechanism, and ships with an
|
||||
encoder for CSV (comma separated values) files. The encoder allows
|
||||
paths and fields to be selected out of the output contents:
|
||||
.Bd -literal -offset indent
|
||||
% df --libxo @csv
|
||||
name,total-blocks,used-blocks,available-blocks,used-percent,mounted-on
|
||||
zroot/ROOT/default,3825984331,29376725,3796607605,1,/
|
||||
devfs,1,1,0,100,/dev
|
||||
zroot/usr/home,3808301289,11693684,3796607605,0,/usr/home
|
||||
zroot/var/audit,3796607806,201,3796607605,0,/var/audit
|
||||
...
|
||||
% df --libxo @csv+leafs=name.used-percent
|
||||
name,used-percent
|
||||
zroot/ROOT/default,1
|
||||
devfs,100
|
||||
zroot/usr/home,0
|
||||
zroot/var/audit,0
|
||||
...
|
||||
% df --libxo @csv+leafs=available-blocks+no-header /
|
||||
3796607605
|
||||
.Ed
|
||||
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.
|
||||
.Pp
|
||||
To allow support for additional encodings, libxo includes a
|
||||
"pluggable" extension mechanism for dynamically loading new encoders.
|
||||
.Nm libxo -based
|
||||
applications can automatically use any installed encoder.
|
||||
.Pp
|
||||
Use the "encoder=XXX" option to access encoders. The following
|
||||
example uses the "cbor" encoder, saving the output into a file:
|
||||
.Bd -literal -offset indent
|
||||
df --libxo encoder=cbor > df-output.cbor
|
||||
.Ed
|
||||
.Pp
|
||||
Encoders can support specific options that can be accessed by
|
||||
following the encoder name with a colon (':') or a plus sign ('+') and
|
||||
one of more options, separated by the same character:
|
||||
.Bd -literal -offset indent
|
||||
df --libxo encoder=csv+path=filesystem+leaf=name+no-header
|
||||
df --libxo encoder=csv:path=filesystem:leaf=name:no-header
|
||||
.Ed
|
||||
.Pp
|
||||
These examples instructs libxo to load the "csv" encoder and pass the
|
||||
following options:
|
||||
.Bd -literal -offset indent
|
||||
path=filesystem
|
||||
leaf=name
|
||||
no-header
|
||||
.Ed
|
||||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
The string "@" can be used in place of the string "encoder=".
|
||||
.Bd -literal -offset indent
|
||||
df --libxo @csv:no-header
|
||||
.Ed
|
||||
.Sh The CSV (Comma Separated Values) Encoder
|
||||
.Nm 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.
|
||||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
Consider the following XML:
|
||||
.Bd -literal -offset indent
|
||||
% 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>
|
||||
.Ed
|
||||
.Pp
|
||||
This output is a list of `instances` (named "item"), each containing a
|
||||
set of `leafs` ("sku", "name", etc).
|
||||
.Pp
|
||||
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:
|
||||
.Bd -literal -offset indent
|
||||
% 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
|
||||
.Ed
|
||||
.Pp
|
||||
Be aware that since the CSV encoder looks for data instances, when
|
||||
used with
|
||||
.Nm xo ,
|
||||
the `--instance` option will be needed:
|
||||
.Bd -literal -offset indent
|
||||
% xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route"
|
||||
product,status
|
||||
stereo,in route
|
||||
.Ed
|
||||
.Sh 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.
|
||||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
For example, if the "list-items" application generates other lists,
|
||||
the user can give "path=top/data/item" as a path:
|
||||
.Bd -literal -offset indent
|
||||
% 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
|
||||
.Ed
|
||||
.Pp
|
||||
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.
|
||||
.Sh 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).
|
||||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
The "leafs" option can also be used to exclude leafs, limiting the
|
||||
output to only those leafs provided.
|
||||
.Pp
|
||||
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.
|
||||
.Pp
|
||||
So the "leafs" option can be used to expand, limit, and order the set
|
||||
of leafs.
|
||||
.Pp
|
||||
The value of the leafs option should be one or more leaf names,
|
||||
separated by a period ("."):
|
||||
.Bd -literal -offset indent
|
||||
% 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
|
||||
.Ed
|
||||
.Pp
|
||||
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.
|
||||
.Sh 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:
|
||||
.Bd -literal -offset indent
|
||||
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
|
||||
.Ed
|
||||
.Pp
|
||||
There is no reliable mechanism for determining whether this header
|
||||
line is included, so the consumer must make an assumption.
|
||||
.Pp
|
||||
The csv encoder defaults to producing the header line, but the
|
||||
"no-header" option can be included to avoid the header line.
|
||||
.Sh 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.
|
||||
.Sh 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.
|
||||
.Pp
|
||||
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.
|
||||
.Sh Option Handling
|
||||
The handling of command-line options is complex, since there are three
|
||||
hierarchies in use, but the rules are:
|
||||
.Bl -bullet
|
||||
.It
|
||||
commas separate
|
||||
.Nm libxo
|
||||
options
|
||||
.Bd -literal -ofset indent
|
||||
\-\-libxo json,pretty,warn
|
||||
.Ed
|
||||
.It
|
||||
pluses separate encoder options
|
||||
.Bd -literal -ofset indent
|
||||
\-\-libxo @csv+dos+no-header,warn
|
||||
.Ed
|
||||
.It
|
||||
periods separate tag names
|
||||
.Bd -literal -ofset indent
|
||||
\-\-libxo @csv+leafs=name.used.free+dos,warn
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr libxo 3 ,
|
||||
.Xr xo_options 7
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm libxo
|
||||
library first appeared in
|
||||
.Fx 11.0 .
|
||||
The CSV encoder first appeared in
|
||||
.Fx 13.0 .
|
||||
.Sh AUTHORS
|
||||
.Nm libxo
|
||||
was written by
|
||||
.An Phil Shafer Aq Mt phil@freebsd.org .
|
||||
|
|
@ -86,6 +86,95 @@ suited for terminal output and HTML is suited for display in a web
|
|||
browser (see
|
||||
.Xr xohtml 1 ).
|
||||
.Pp
|
||||
.Nm libxo
|
||||
uses command line options to trigger rendering behavior.
|
||||
The following options are recognised:
|
||||
.Pp
|
||||
.Bl -tag -width "--libxo"
|
||||
.It
|
||||
\-\^\-libxo <options>
|
||||
.It
|
||||
\-\^\-libxo=<options>
|
||||
.It
|
||||
\-\^\-libxo:<brief-options>
|
||||
.El
|
||||
.Pp
|
||||
Options is a comma-separated list of tokens that correspond to output
|
||||
styles, flags, or features:
|
||||
.Pp
|
||||
.Bl -tag -width "12345678"
|
||||
.It Sy "Token Action"
|
||||
.It Dv dtrt
|
||||
Enable "Do The Right Thing" mode
|
||||
.It Dv html
|
||||
Emit HTML output
|
||||
.It Dv indent=xx
|
||||
Set the indentation level
|
||||
.It Dv info
|
||||
Add info attributes (HTML)
|
||||
.It Dv json
|
||||
Emit JSON output
|
||||
.It Dv keys
|
||||
Emit the key attribute for keys (XML)
|
||||
.It Dv log-gettext
|
||||
Log (via stderr) each
|
||||
.Xr gettext 3
|
||||
string lookup
|
||||
.It Dv log-syslog
|
||||
Log (via stderr) each syslog message (via
|
||||
.Xr xo_syslog 3 )
|
||||
.It Dv no-humanize
|
||||
Ignore the {h:} modifier (TEXT, HTML)
|
||||
.It Dv no-locale
|
||||
Do not initialize the locale setting
|
||||
.It Dv no-retain
|
||||
Prevent retaining formatting information
|
||||
.It Dv no-top
|
||||
Do not emit a top set of braces (JSON)
|
||||
.It Dv not-first
|
||||
Pretend the 1st output item was not 1st (JSON)
|
||||
.It Dv pretty
|
||||
Emit pretty-printed output
|
||||
.It Dv retain
|
||||
Force retaining formatting information
|
||||
.It Dv text
|
||||
Emit TEXT output
|
||||
.It Dv underscores
|
||||
Replace XML-friendly "-"s with JSON friendly "_"s e
|
||||
.It Dv units
|
||||
Add the 'units' (XML) or 'data-units (HTML) attribute
|
||||
.It Dv warn
|
||||
Emit warnings when libxo detects bad calls
|
||||
.It Dv warn-xml
|
||||
Emit warnings in XML
|
||||
.It Dv xml
|
||||
Emit XML output
|
||||
.It Dv xpath
|
||||
Add XPath expressions (HTML)
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Dq brief-options
|
||||
are single letter commands, designed for those with
|
||||
too little patience to use real tokens.
|
||||
No comma separator is used.
|
||||
.Bl -column "i<num>"
|
||||
.It Sy "Token Action"
|
||||
.It "H " "Enable HTML output (XO_STYLE_HTML)"
|
||||
.It "I " "Enable info output (XOF_INFO)"
|
||||
.It "i<num> " "Indent by <number>"
|
||||
.It "J " "Enable JSON output (XO_STYLE_JSON)"
|
||||
.It "P " "Enable pretty-printed output (XOF_PRETTY)"
|
||||
.It "T " "Enable text output (XO_STYLE_TEXT)"
|
||||
.It "W " "Enable warnings (XOF_WARN)"
|
||||
.It "X " "Enable XML output (XO_STYLE_XML)"
|
||||
.It "x " "Enable XPath data (XOF_XPATH)"
|
||||
.El
|
||||
.Pp
|
||||
Refer to
|
||||
.Xr xo_options 7
|
||||
for additional option information.
|
||||
.Pp
|
||||
The
|
||||
.Nm
|
||||
library allows an application to generate text, XML, JSON,
|
||||
|
@ -291,6 +380,7 @@ Instructs
|
|||
to use an alternative set of low-level output functions.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr libxo-csv 7,
|
||||
.Xr xo 1 ,
|
||||
.Xr xolint 1 ,
|
||||
.Xr xo_attr 3 ,
|
||||
|
@ -303,6 +393,7 @@ to use an alternative set of low-level output functions.
|
|||
.Xr xo_no_setlocale 3 ,
|
||||
.Xr xo_open_container 3 ,
|
||||
.Xr xo_open_list 3 ,
|
||||
.Xr xo_options 7,
|
||||
.Xr xo_parse_args 3 ,
|
||||
.Xr xo_set_allocator 3 ,
|
||||
.Xr xo_set_flags 3 ,
|
||||
|
|
|
@ -6979,8 +6979,21 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
|||
pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
|
||||
xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
|
||||
|
||||
/* If we need underscores, make a local copy and doctor it */
|
||||
const char *new_name = name;
|
||||
if (XOF_ISSET(xop, XOF_UNDERSCORES)) {
|
||||
size_t len = strlen(name);
|
||||
const char *old_name = name;
|
||||
char *buf, *cp, *ep;
|
||||
|
||||
buf = alloca(len + 1);
|
||||
for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++)
|
||||
*cp = (*old_name == '-') ? '_' : *old_name;
|
||||
new_name = buf;
|
||||
}
|
||||
|
||||
rc = xo_printf(xop, "%s%*s\"%s\": {%s",
|
||||
pre_nl, xo_indent(xop), "", name, ppn);
|
||||
pre_nl, xo_indent(xop), "", new_name, ppn);
|
||||
break;
|
||||
|
||||
case XO_STYLE_SDPARAMS:
|
||||
|
@ -7142,8 +7155,21 @@ xo_do_open_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name)
|
|||
pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", ";
|
||||
xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST;
|
||||
|
||||
/* If we need underscores, make a local copy and doctor it */
|
||||
const char *new_name = name;
|
||||
if (XOF_ISSET(xop, XOF_UNDERSCORES)) {
|
||||
size_t len = strlen(name);
|
||||
const char *old_name = name;
|
||||
char *buf, *cp, *ep;
|
||||
|
||||
buf = alloca(len + 1);
|
||||
for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++)
|
||||
*cp = (*old_name == '-') ? '_' : *old_name;
|
||||
new_name = buf;
|
||||
}
|
||||
|
||||
rc = xo_printf(xop, "%s%*s\"%s\": [%s",
|
||||
pre_nl, xo_indent(xop), "", name, ppn);
|
||||
pre_nl, xo_indent(xop), "", new_name, ppn);
|
||||
break;
|
||||
|
||||
case XO_STYLE_ENCODER:
|
||||
|
|
|
@ -33,7 +33,7 @@ function.
|
|||
Example:
|
||||
xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN);
|
||||
....
|
||||
xo_emit_h(xop, "testing\n");
|
||||
xo_emit_h(xop, "testing\\n");
|
||||
.Ed
|
||||
.Pp
|
||||
By default,
|
||||
|
|
|
@ -48,7 +48,7 @@ In this example, a set of four values is emitted using the following
|
|||
source code:
|
||||