Tag libxo 0.9.0

This commit is contained in:
phil 2018-05-23 01:12:39 +00:00
parent d58b3d7d3d
commit f701945270
377 changed files with 80487 additions and 0 deletions

46
0.9.0/.gitignore vendored Normal file
View File

@ -0,0 +1,46 @@
# Object files
*.o
# Libraries
*.lib
*.a
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.app
*~
*.orig
aclocal.m4
ar-lib
autom4te.cache
build
compile
config.guess
config.h.in
config.sub
depcomp
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

18
0.9.0/.svnignore Normal file
View File

@ -0,0 +1,18 @@
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*

12
0.9.0/.travis.yml Normal file
View File

@ -0,0 +1,12 @@
language: c
script: printenv && uname -a && ls -l && /bin/sh -x ./bin/setup.sh && cd build && ../configure --enable-warnings && make && sudo make install && make test
notifications:
recipients:
- libslax-noise@googlegroups.com
branches:
only:
- master
- develop

23
0.9.0/Copyright Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2014 Juniper Networks, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

15
0.9.0/INSTALL.md Normal file
View File

@ -0,0 +1,15 @@
<!---
# $Id$
#
# Copyright 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.
#-->
## Instructions for building libxo
Instructions for building libxo are now available in the
[wiki](http://juniper.github.io/libxo/libxo-manual.html#getting-libxo).

23
0.9.0/LICENSE Normal file
View File

@ -0,0 +1,23 @@
Copyright (c) 2014, Juniper Networks
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

143
0.9.0/Makefile.am Normal file
View File

@ -0,0 +1,143 @@
#
# $Id$
#
# Copyright 2014, 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.
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = libxo xo xopo xolint xohtml tests doc encoder
bin_SCRIPTS=libxo-config
dist_doc_DATA = Copyright
EXTRA_DIST = \
libxo-config.in \
warnings.mk \
README.md \
INSTALL.md \
packaging/libxo.spec
.PHONY: test tests
test tests:
@(cd tests ; ${MAKE} test)
errors:
@(cd tests/errors ; ${MAKE} test)
docs:
@(cd doc ; ${MAKE} docs)
DIST_FILES_DIR = ~/Dropbox/dist-files/
GH_PAGES_DIR = gh-pages/
GH_PAGES_DIR_VER = gh-pages/${PACKAGE_VERSION}
PACKAGE_FILE = ${PACKAGE_TARNAME}-${PACKAGE_VERSION}.tar.gz
XOHTML_FILES = \
${top_srcdir}/xohtml/xohtml.css \
${top_srcdir}/xohtml/xohtml.js \
${top_srcdir}/xohtml/external/jquery.js \
${top_srcdir}/xohtml/external/jquery.qtip.css \
${top_srcdir}/xohtml/external/jquery.qtip.js
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} \
&& (cd ${GH_PAGES_DIR} \
&& git add ${PACKAGE_VERSION} \
&& git add libxo-manual.html \
&& git commit -m 'new docs' \
libxo-manual.html ${PACKAGE_VERSION} \
&& git push origin gh-pages ) ; true
upload-xohtml-files:
@echo "Uploading xohtml files ... "
@-[ -d ${GH_PAGES_DIR} ] \
&& echo "Updating xohtml files on gh-pages ..." \
&& mkdir -p ${GH_PAGES_DIR_VER}/xohtml \
&& cp ${XOHTML_FILES} ${GH_PAGES_DIR_VER}/xohtml \
&& (cd ${GH_PAGES_DIR} \
&& git add ${PACKAGE_VERSION}/xohtml \
&& git commit -m 'new xohtml files' \
${PACKAGE_VERSION}/xohtml \
&& git push origin gh-pages ) ; true
pkgconfigdir=$(libdir)/pkgconfig
pkgconfig_DATA = packaging/${PACKAGE_NAME}.pc
get-wiki:
git clone https://github.com/Juniper/${PACKAGE_NAME}.wiki.git wiki
get-gh-pages:
git clone https://github.com/Juniper/${PACKAGE_NAME}.git \
gh-pages -b gh-pages
UPDATE_PACKAGE_FILE = \
-e "s;__SHA1__;$$SHA1;" \
-e "s;__SHA256__;SHA256 (textproc/${PACKAGE_FILE}) = $$SHA256;" \
-e "s;__SIZE__;SIZE (textproc/${PACKAGE_FILE}) = $$SIZE;"
GH_PACKAGING_DIR = ${PACKAGE_VERSION}/packaging
GH_PAGES_PACKAGE_DIR = ${GH_PAGES_DIR}/${GH_PACKAGING_DIR}
packages:
@-[ -d ${GH_PAGES_DIR} ] && set -x \
&& echo "Updating packages on gh-pages ..." \
&& mkdir -p ${GH_PAGES_DIR}/${GH_PACKAGING_DIR} \
&& SHA1="`openssl sha1 ${PACKAGE_FILE} | awk '{print $$2}'`" \
&& SHA256="`openssl sha256 ${PACKAGE_FILE} | awk '{print $$2}'`" \
&& SIZE="`ls -l ${PACKAGE_FILE} | awk '{print $$5}'`" \
&& echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.rb ..." \
&& sed ${UPDATE_PACKAGE_FILE} \
packaging/${PACKAGE_NAME}.rb.base \
> ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.rb \
&& echo "... ${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec ..." \
&& cp packaging/${PACKAGE_NAME}.spec \
${GH_PAGES_PACKAGE_DIR}/${PACKAGE_NAME}.spec \
&& (cd ${GH_PAGES_DIR} \
&& git add ${GH_PACKAGING_DIR} \
&& git add ${GH_PACKAGING_DIR}/libxo.rb \
${GH_PACKAGING_DIR}/libxo.spec \
&& git commit -m 'new packaging data' \
${GH_PACKAGING_DIR} \
&& git push origin gh-pages ) ; true
ANALYZE_DIR = ~/trash/libxo
ANALYZE_CMD = scan-build-mp-3.6
analyze:
${MAKE} clean
${ANALYZE_CMD} -o ${ANALYZE_DIR} ${MAKE}
SANIFLAGS=-fno-omit-frame-pointer -g -O2
sanitize-address:
${MAKE} clean
${MAKE} CFLAGS="-fsanitize=address ${SANIFLAGS}"
${MAKE} install
${MAKE} test
sanitize-undefined:
${MAKE} clean
${MAKE} CFLAGS="-fsanitize=undefined ${SANIFLAGS}"
${MAKE} install
${MAKE} test
sanitize-memory:
${MAKE} clean
${MAKE} CFLAGS="-fsanitize=memory ${SANIFLAGS}"
${MAKE} install
${MAKE} test

64
0.9.0/README.md Normal file
View File

@ -0,0 +1,64 @@
libxo
=====
libxo - A Library for Generating Text, XML, JSON, and HTML Output
The libxo library allows an application to generate text, XML, JSON,
and HTML output using a common set of function calls. The application
decides at run time which output style should be produced. The
application calls a function "xo_emit" to product output that is
described in a format string. A "field descriptor" tells libxo what
the field is and what it means.
```
xo_emit(" {:lines/%7ju/%ju} {:words/%7ju/%ju} "
"{:characters/%7ju/%ju}{d:filename/%s}\n",
linect, wordct, charct, file);
```
Output can then be generated in various style, using the "--libxo"
option:
```
% wc /etc/motd
25 165 1140 /etc/motd
% wc --libxo xml,pretty,warn /etc/motd
<wc>
<file>
<filename>/etc/motd</filename>
<lines>25</lines>
<words>165</words>
<characters>1140</characters>
</file>
</wc>
% wc --libxo json,pretty,warn /etc/motd
{
"wc": {
"file": [
{
"filename": "/etc/motd",
"lines": 25,
"words": 165,
"characters": 1140
}
]
}
}
% wc --libxo html,pretty,warn /etc/motd
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines"> 25</div>
<div class="text"> </div>
<div class="data" data-tag="words"> 165</div>
<div class="text"> </div>
<div class="data" data-tag="characters"> 1140</div>
<div class="text"> </div>
<div class="data" data-tag="filename">/etc/motd</div>
</div>
```
View the beautiful documentation at:
http://juniper.github.io/libxo/libxo-manual.html
[![Analytics](https://ga-beacon.appspot.com/UA-56056421-1/Juniper/libxo/Readme)](https://github.com/Juniper/libxo)

498
0.9.0/configure.ac Normal file
View File

@ -0,0 +1,498 @@
#
# $Id$
#
# See ./INSTALL for more info
#
#
# Release numbering: even numbered dot releases are official ones, and
# odd numbers are development ones. The svn version of this file will
# only (ONLY!) ever (EVER!) contain odd numbers, so I'll always know if
# a particular user has the dist or svn release.
#
AC_PREREQ(2.2)
AC_INIT([libxo], [0.9.0], [phil@juniper.net])
AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability])
# Support silent build rules. Requires at least automake-1.11.
# Disable with "configure --disable-silent-rules" or "make V=1"
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC
AC_PROG_INSTALL
AC_CONFIG_MACRO_DIR([m4])
AC_PROG_LN_S
# Must be after AC_PROG_AR
LT_INIT([dlopen shared])
AC_PATH_PROG(BASENAME, basename, /usr/bin/basename)
AC_PATH_PROG(BISON, bison, /usr/bin/bison)
AC_PATH_PROG(CAT, cat, /bin/cat)
AC_PATH_PROG(CHMOD, chmod, /bin/chmod)
AC_PATH_PROG(CP, cp, /bin/cp)
AC_PATH_PROG(DIFF, diff, /usr/bin/diff)
AC_PATH_PROG(MKDIR, mkdir, /bin/mkdir)
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
# Checks for library functions.
AC_FUNC_ALLOCA
AC_FUNC_MALLOC
AC_FUNC_REALLOC
AC_CHECK_FUNCS([bzero memmove strchr strcspn strerror strspn])
AC_CHECK_FUNCS([sranddev srand strlcpy])
AC_CHECK_FUNCS([fdopen getrusage])
AC_CHECK_FUNCS([gettimeofday ctime])
AC_CHECK_FUNCS([getpass])
AC_CHECK_FUNCS([getprogname])
AC_CHECK_FUNCS([sysctlbyname])
AC_CHECK_FUNCS([flock])
AC_CHECK_FUNCS([asprintf])
AC_CHECK_FUNCS([__flbf])
AC_CHECK_FUNCS([sysctlbyname])
AC_CHECK_HEADERS([dlfcn.h])
AC_CHECK_HEADERS([dlfcn.h])
AC_CHECK_HEADERS([stdio_ext.h])
AC_CHECK_HEADERS([tzfile.h])
AC_CHECK_HEADERS([stdtime/tzfile.h])
AC_CHECK_FUNCS([dlfunc])
AC_CHECK_HEADERS([sys/time.h])
AC_CHECK_HEADERS([ctype.h errno.h stdio.h stdlib.h])
AC_CHECK_HEADERS([string.h sys/param.h unistd.h ])
AC_CHECK_HEADERS([sys/sysctl.h])
AC_CHECK_HEADERS([threads.h])
AC_CHECK_HEADERS([monitor.h])
dnl humanize_number(3) is a great function, but it's not standard.
dnl Note Macosx has the function in libutil.a but doesn't ship the
dnl header file, so I'll need to carry my own implementation. See:
dnl https://devforums.apple.com/thread/271121
AC_CHECK_HEADERS([libutil.h])
AC_CHECK_LIB([util], [humanize_number],
[HAVE_HUMANIZE_NUMBER=$ac_cv_header_libutil_h],
[HAVE_HUMANIZE_NUMBER=no])
AC_MSG_RESULT(humanize_number results: :${HAVE_HUMANIZE_NUMBER}:${ac_cv_header_libutil_h}:)
if test "$HAVE_HUMANIZE_NUMBER" = "yes"; then
AC_DEFINE([HAVE_HUMANIZE_NUMBER], [1], [humanize_number(3)])
fi
AM_CONDITIONAL([HAVE_HUMANIZE_NUMBER], [test "$HAVE_HUMANIZE_NUMBER" = "yes"])
AC_ARG_ENABLE([gettext],
[ --disable-gettext Turn off support for gettext],
[GETTEXT_ENABLE=$enableval],
[GETTEXT_ENABLE=yes])
dnl Looking for gettext(), assumably in libintl
AC_ARG_WITH(gettext,
[ --with-gettext=[PFX] Specify location of gettext installation],
[GETTEXT_PREFIX=$withval],
[GETTEXT_PREFIX=/usr],
)
HAVE_GETTEXT=no
if test "$GETTEXT_ENABLE" != "no"; then
AC_MSG_CHECKING([gettext in ${GETTEXT_PREFIX}])
_save_cflags="$CFLAGS"
CFLAGS="$CFLAGS -I${GETTEXT_PREFIX}/include -L${GETTEXT_PREFIX}/lib -Werror -lintl"
AC_LINK_IFELSE([AC_LANG_SOURCE([[#include <libintl.h>]
[int main() {char *cp = dgettext(NULL, "xx"); return 0; }]])],
[HAVE_GETTEXT=yes],
[HAVE_GETTEXT=no])
CFLAGS="$_save_cflags"
AC_MSG_RESULT([$HAVE_GETTEXT])
if test "$HAVE_GETTEXT" != "yes"; then
GETTEXT_PREFIX=/opt/local
AC_MSG_CHECKING([gettext in ${GETTEXT_PREFIX}])
_save_cflags="$CFLAGS"
CFLAGS="$CFLAGS -I${GETTEXT_PREFIX}/include -L${GETTEXT_PREFIX}/lib -Werror -lintl"
AC_LINK_IFELSE([AC_LANG_SOURCE([[#include <libintl.h>]
[int main() {char *cp = dgettext(NULL, "xx"); return 0; }]])],
[HAVE_GETTEXT=yes],
[HAVE_GETTEXT=no])
CFLAGS="$_save_cflags"
AC_MSG_RESULT([$HAVE_GETTEXT])
fi
if test "$HAVE_GETTEXT" != "yes"; then
GETTEXT_PREFIX=/usr/local
AC_MSG_CHECKING([gettext in ${GETTEXT_PREFIX}])
_save_cflags="$CFLAGS"
CFLAGS="$CFLAGS -I${GETTEXT_PREFIX}/include -L${GETTEXT_PREFIX}/lib -Werror -lintl"
AC_LINK_IFELSE([AC_LANG_SOURCE([[#include <libintl.h>]
[int main() {char *cp = dgettext(NULL, "xx"); return 0; }]])],
[HAVE_GETTEXT=yes],
[HAVE_GETTEXT=no])
CFLAGS="$_save_cflags"
AC_MSG_RESULT([$HAVE_GETTEXT])
fi
fi
if test "$HAVE_GETTEXT" = "yes"; then
AC_DEFINE([HAVE_GETTEXT], [1], [gettext(3)])
GETTEXT_CFLAGS="-I${GETTEXT_PREFIX}/include"
GETTEXT_LIBS="-L${GETTEXT_PREFIX}/lib -lintl"
else
GETTEXT_PREFIX=none
GETTEXT_CFLAGS=
GETTEXT_LIBS=
fi
AC_SUBST(GETTEXT_CFLAGS)
AC_SUBST(GETTEXT_LIBS)
GETTEXT_LIBDIR=${GETTEXT_PREFIX}/lib
AC_SUBST(GETTEXT_LIBDIR)
if test -x ${GETTEXT_PREFIX}/bin/msgfmt ; then
GETTEXT_BINDIR=${GETTEXT_PREFIX}/bin
elif test -x ${GETTEXT_PREFIX}/local/bin/msgfmt ; then
GETTEXT_BINDIR=${GETTEXT_PREFIX}/local/bin
else
AC_MSG_NOTICE("could not find msgfmt tool")
# Use a (bad) fall back value
GETTEXT_BINDIR=${GETTEXT_PREFIX}/bin
fi
AC_SUBST(GETTEXT_BINDIR)
AM_CONDITIONAL([HAVE_GETTEXT], [test "$HAVE_GETTEXT" = "yes"])
dnl Looking for how to do thread-local variables
AC_ARG_WITH(threads,
[ --with-threads=[STYLE] Specify style of thread-local support (none)],
[THREAD_LOCAL=$withval],
[THREAD_LOCAL=unknown],
)
AC_MSG_CHECKING([thread-locals are ${THREAD_LOCAL}])
if test "$THREAD_LOCAL" = "unknown"; then
AC_LINK_IFELSE([AC_LANG_SOURCE([[]
[__thread int foo; int main() { foo++; return foo; }]])],
[THREAD_LOCAL=before],
[THREAD_LOCAL=unknown])
AC_MSG_RESULT([$THREAD_LOCAL])
fi
if test "$THREAD_LOCAL" = "unknown"; then
AC_LINK_IFELSE([AC_LANG_SOURCE([[]
[int __thread foo; int main() { foo++; return foo; }]])],
[THREAD_LOCAL=after],
[THREAD_LOCAL=unknown])
AC_MSG_RESULT([$THREAD_LOCAL])
fi
if test "$THREAD_LOCAL" = "unknown"; then
AC_LINK_IFELSE([AC_LANG_SOURCE([[]
[__declspec(int) foo; int main() { foo++; return foo; }]])],
[THREAD_LOCAL=declspec],
[THREAD_LOCAL=unknown])
AC_MSG_RESULT([$THREAD_LOCAL])
fi
if test "$THREAD_LOCAL" != "unknown"; then
AC_DEFINE_UNQUOTED([HAVE_THREAD_LOCAL],
THREAD_LOCAL_${THREAD_LOCAL}, [thread-local setting])
fi
dnl Looking for libcrypto....
AC_CHECK_LIB([crypto], [MD5_Init])
AM_CONDITIONAL([HAVE_LIBCRYPTO], [test "$HAVE_LIBCRYPTO" != "no"])
AC_CHECK_MEMBER([struct sockaddr_un.sun_len],
[HAVE_SUN_LEN=yes ;
AC_DEFINE([HAVE_SUN_LEN], [1], [Have struct sockaddr_un.sun_len])],
[HAS_SUN_LEN=no], [[#include <sys/un.h>]])
AC_CHECK_DECLS([__isthreaded], [], [], [#include <stdio.h>])
HAVE_ISTHREADED=${ac_cv_have_decl___isthreaded}
dnl
dnl Some packages need to be checked against version numbers so we
dnl define a function here for later use
dnl
AC_DEFUN([VERSION_TO_NUMBER],
[`$1 | sed -e 's/lib.* //' | awk 'BEGIN { FS = "."; } { printf "%d", ([$]1 * 1000 + [$]2) * 1000 + [$]3;}'`])
LIBSLAX_CONFIG_PREFIX=""
LIBSLAX_SRC=""
AC_ARG_WITH(libslax-prefix,
[ --with-libslax-prefix=[PFX] Specify location of libslax config],
LIBSLAX_CONFIG_PREFIX=$withval
)
AC_MSG_CHECKING(for libslax)
if test "x$LIBSLAX_CONFIG_PREFIX" != "x"
then
SLAX_CONFIG=${LIBSLAX_CONFIG_PREFIX}/bin/slax-config
else
SLAX_CONFIG=slax-config
fi
dnl
dnl make sure slax-config is executable,
dnl test version and init our variables
dnl
if ${SLAX_CONFIG} --libs > /dev/null 2>&1
then
LIBSLAX_VERSION=`$SLAX_CONFIG --version`
SLAX_BINDIR="`$SLAX_CONFIG --bindir | head -1`"
SLAX_OXTRADOCDIR="`$SLAX_CONFIG --oxtradoc | head -1`"
AC_MSG_RESULT($LIBSLAX_VERSION found)
HAVE_OXTRADOC=yes
else
LIBSLAX_VERSION=
SLAX_BINDIR=
SLAX_OXTRADOCDIR=
AC_MSG_RESULT([no])
HAVE_OXTRADOC=no
fi
AM_CONDITIONAL([HAVE_OXTRADOC], [test "$HAVE_OXTRADOC" != "no"])
AC_SUBST(SLAX_BINDIR)
AC_SUBST(SLAX_OXTRADOCDIR)
AC_MSG_CHECKING([whether to build with warnings])
AC_ARG_ENABLE([warnings],
[ --enable-warnings Turn on compiler warnings],
[LIBXO_WARNINGS=$enableval],
[LIBXO_WARNINGS=no])
AC_MSG_RESULT([$LIBXO_WARNINGS])
AM_CONDITIONAL([LIBXO_WARNINGS_HIGH], [test "$LIBXO_WARNINGS" != "no"])
AC_MSG_CHECKING([whether to build with debugging])
AC_ARG_ENABLE([debug],
[ --enable-debug Turn on debugging],
[LIBXO_DEBUG=yes; AC_DEFINE([LIBXO_DEBUG], [1], [Enable debugging])],
[LIBXO_DEBUG=no])
AC_MSG_RESULT([$LIBXO_DEBUG])
AM_CONDITIONAL([LIBXO_DEBUG], [test "$LIBXO_DEBUG" != "no"])
AC_MSG_CHECKING([whether to use int return codes])
AC_ARG_ENABLE([int-return-codes],
[ --enable-int-return-codes Use int return codes (instead of ssize_t)],
[USE_INT_RETURN_CODES=yes; AC_DEFINE([USE_INT_RETURN_CODES], [1], [Use int return codes])],
[USE_INT_RETURN_CODES=no])
AC_MSG_RESULT([$USE_INT_RETURN_CODES])
AC_MSG_CHECKING([whether to build with text-only rendering])
AC_ARG_ENABLE([text-only],
[ --enable-text-only Turn on text-only rendering],
[LIBXO_TEXT_ONLY=yes; AC_DEFINE([LIBXO_TEXT_ONLY], [1], [Enable text-only rendering])],
[LIBXO_TEXT_ONLY=no])
AC_MSG_RESULT([$LIBXO_TEXT_ONLY])
AM_CONDITIONAL([LIBXO_TEXT_ONLY], [test "$LIBXO_TEXT_ONLY" != "no"])
AC_MSG_CHECKING([whether to build with local wcwidth implementation])
AC_ARG_ENABLE([wcwidth],
[ --disable-wcwidth Disable local wcwidth implementation],
[LIBXO_WCWIDTH=$enableval],
[LIBXO_WCWIDTH=yes])
AC_MSG_RESULT([$LIBXO_WCWIDTH])
if test "${LIBXO_WCWIDTH}" != "no"; then
AC_DEFINE([LIBXO_WCWIDTH], [1], [Enable local wcwidth implementation])
fi
AC_MSG_CHECKING([retain hash bucket size])
AC_ARG_WITH(retain-size,
[ --with-retain-size=[DIR] Specify retain hash bucket size (in bits)],
[XO_RETAIN_SIZE=$withval],
[XO_RETAIN_SIZE=default]
)
AC_MSG_RESULT([$XO_RETAIN_SIZE])
if test "${XO_RETAIN_SIZE}" != "default"; then
AC_DEFINE_UNQUOTED([XO_RETAIN_SIZE], ${XO_RETAIN_SIZE}, [Retain hash bucket size])
fi
AC_CHECK_LIB([m], [lrint])
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`
if test "${HAVE_GCC}" != ""; then
HAVE_GCC=yes
else
HAVE_GCC=no
fi
fi
AC_MSG_RESULT([$HAVE_GCC])
AM_CONDITIONAL([HAVE_GCC], [test "$HAVE_GCC" = "yes"])
AC_MSG_CHECKING([whether to build with printflike])
AC_ARG_ENABLE([printflike],
[ --enable-printflike Enable use of GCC __printflike attribute],
[HAVE_PRINTFLIKE=yes;
AC_DEFINE([HAVE_PRINTFLIKE], [1], [Support printflike])],
[HAVE_PRINTFLIKE=no])
AC_MSG_RESULT([$HAVE_PRINTFLIKE])
AM_CONDITIONAL([HAVE_PRINTFLIKE], [test "$HAVE_PRINTFLIKE" != ""])
AC_MSG_CHECKING([whether to build with LIBXO_OPTIONS])
AC_ARG_ENABLE([libxo-options],
[ --disable-libxo-options Turn off support for LIBXO_OPTIONS],
[LIBXO_OPTS=$enableval],
[LIBXO_OPTS=yes])
AC_MSG_RESULT([$LIBXO_OPTS])
AM_CONDITIONAL([NO_LIBXO_OPTIONS], [test "$LIBXO_OPTS" != "yes"])
case $host_os in
darwin*)
LIBTOOL=glibtool
XO_LIBEXT=dylib
;;
Linux*|linux*)
CFLAGS="-D_GNU_SOURCE $CFLAGS"
LDFLAGS=-ldl
XO_LIBEXT=so
;;
cygwin*|CYGWIN*)
LDFLAGS=-no-undefined
XO_LIBEXT=ddl
;;
esac
case $prefix in
NONE)
prefix=/usr/local
;;
esac
XO_LIBS=-lxo
XO_SRCDIR=${srcdir}
XO_LIBDIR=${libdir}
XO_BINDIR=${bindir}
XO_INCLUDEDIR=${includedir}
XO_CFLAGS="${CFLAGS}"
AC_SUBST(XO_LIBS)
AC_SUBST(XO_SRCDIR)
AC_SUBST(XO_LIBDIR)
AC_SUBST(XO_BINDIR)
AC_SUBST(XO_INCLUDEDIR)
AC_SUBST(XO_LIBEXT)
AC_SUBST(XO_CFLAGS)
AC_ARG_WITH(encoder-dir,
[ --with-encoder-dir=[DIR] Specify location of encoder libraries],
[XO_ENCODERDIR=$withval],
[XO_ENCODERDIR=$libdir/libxo/encoder]
)
AC_SUBST(XO_ENCODERDIR)
AC_ARG_WITH(share-dir,
[ --with-share-dir=[DIR] Specify location of shared files],
[XO_SHAREDIR=$withval],
[XO_SHAREDIR=$datarootdir/libxo]
)
XO_SHAREDIR=`echo $XO_SHAREDIR | sed "s;\\${prefix};$prefix;"`
AC_SUBST(XO_SHAREDIR)
dnl for the spec file
RELDATE=`date +'%Y-%m-%d%n'`
AC_SUBST(RELDATE)
AC_MSG_RESULT(Using configure dir $ac_abs_confdir)
if test -d $ac_abs_confdir/.git ; then
extra=`git branch | awk '/\*/ { print $2 }'`
if test "$extra" != "" -a "$extra" != "master"
then
LIBXO_VERSION_EXTRA="-git-$extra"
fi
fi
LIBXO_VERSION=$PACKAGE_VERSION
LIBXO_VERSION_NUMBER=VERSION_TO_NUMBER(echo $PACKAGE_VERSION)
AC_SUBST(LIBXO_VERSION)
AC_SUBST(LIBXO_VERSION_NUMBER)
AC_SUBST(LIBXO_VERSION_EXTRA)
AC_DEFINE_UNQUOTED(LIBXO_VERSION, ["$LIBXO_VERSION"],
[Version number as dotted value])
AC_DEFINE_UNQUOTED(LIBXO_VERSION_NUMBER, [$LIBXO_VERSION_NUMBER],
[Version number as a number])
AC_DEFINE_UNQUOTED(LIBXO_VERSION_STRING, ["$LIBXO_VERSION_NUMBER"],
[Version number as string])
AC_DEFINE_UNQUOTED(LIBXO_VERSION_EXTRA, ["$LIBXO_VERSION_EXTRA"],
[Version number extra information])
AC_CONFIG_HEADERS([libxo/xo_config.h])
AC_CONFIG_FILES([
Makefile
libxo-config
xohtml/xohtml.sh
libxo/Makefile
libxo/add.man
encoder/Makefile
encoder/cbor/Makefile
encoder/test/Makefile
xo/Makefile
xolint/Makefile
xohtml/Makefile
xopo/Makefile
packaging/libxo.pc
doc/Makefile
tests/Makefile
tests/core/Makefile
tests/gettext/Makefile
tests/xo/Makefile
packaging/libxo.spec
packaging/libxo.rb.base
])
AC_OUTPUT
AC_MSG_NOTICE([summary of build options:
libxo version: ${VERSION} ${LIBXO_VERSION_EXTRA}
host type: ${host} / ${host_os}
install prefix: ${prefix}
srcdir: ${XO_SRCDIR}
libdir: ${XO_LIBDIR}
bindir: ${XO_BINDIR}
includedir: ${XO_INCLUDEDIR}
share dir: ${XO_SHAREDIR}
extensions dir: ${XO_ENCODERDIR}
oxtradoc dir: ${SLAX_OXTRADOCDIR}
compiler: ${CC} (${HAVE_GCC:-no})
compiler flags: ${CFLAGS}
library types: Shared=${enable_shared}, Static=${enable_static}
warnings: ${LIBXO_WARNINGS:-no}
debug: ${LIBXO_DEBUG:-no}
printf-like: ${HAVE_PRINTFLIKE:-no}
libxo-options: ${LIBXO_OPTS:-no}
text-only: ${LIBXO_TEXT_ONLY:-no}
gettext: ${HAVE_GETTEXT:-no} (${GETTEXT_PREFIX})
isthreaded: ${HAVE_ISTHREADED:-no}
thread-local: ${THREAD_LOCAL:-no}
local wcwidth: ${LIBXO_WCWIDTH:-no}
retain size: ${XO_RETAIN_SIZE:-no}
])

75
0.9.0/doc/Makefile.am Normal file
View File

@ -0,0 +1,75 @@
#
# $Id$
#
# Copyright 2014, 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 HAVE_OXTRADOC
OXTRADOC_DIR = ${SLAX_OXTRADOCDIR}
OXTRADOC_PREFIX = ${OXTRADOC_DIR}
OXTRADOC = ${OXTRADOC_DIR}/oxtradoc
SLAXPROC_BINDIR = ${SLAX_BINDIR}
XML2RFC = ${OXTRADOC_DIR}/xml2rfc.tcl
XML2HTMLDIR = ${OXTRADOC_DIR}
XML2HTMLBIN = ${XML2HTMLDIR}/rfc2629-to-html.slax
SLAXPROC = ${SLAX_BINDIR}/slaxproc
SLAXPROC_ARGS = \
-a oxtradoc-dir ${OXTRADOC_DIR} \
-a oxtradoc-install-dir ${OXTRADOC_DIR} \
-a anchor-prefix docs
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
html sphinx sphinx-html:
${SPHINX} -M html ${srcdir} .

657
0.9.0/doc/_static/basic.css_t vendored Normal file
View File

@ -0,0 +1,657 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: {{ theme_sidebarwidth|toint }}px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox input[type="text"] {
width: 170px;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li div.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
blockquote.epigraph p.attribution {
margin-left: 50%;
}
blockquote.epigraph {
background-color: #eee;
padding: 0.5em;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, .figure.align-right, object.align-right {
/* clear: right; */
float: right;
margin-left: 1em;
}
img.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar {
margin: 1em 1em 1em 1em;
border: 1px solid #ddb;
padding: 7px 7px 0 7px;
background-color: #ffe;
width: 40%;
float: right;
}
p.sidebar-title {
font-weight: bold;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px 7px 0 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
div.admonition dl {
margin-bottom: 0;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
border: 0;
border-collapse: collapse;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
dl.function table.docutils th.field-name {
width: 100px;
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 1px solid #aaa;
border-left: 1px solid #aaa;
border-right: 1px solid #aaa;
border-bottom: 1px solid #aaa;
}
table.docutils th {
border-bottom: 2px solid #aaa;
background-color: #f2f2f2;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
/* -- figures --------------------------------------------------------------- */
div.figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption {
padding: 0.3em;
}
div.figure p.caption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
dl {
margin-bottom: 15px;
}
dd p {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dt:target, .highlighted {
background-color: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
}
td.linenos pre {
padding: 5px 0px;
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
margin-left: 0.5em;
}
table.highlighttable td {
padding: 0 0.5em 0 0.5em;
}
div.code-block-caption {
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
div.code-block-caption + div > div.highlight > pre {
margin-top: 0;
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
padding: 1em 1em 0;
}
div.literal-block-wrapper div.highlight {
margin: 0;
}
code.descname {
background-color: transparent;
font-weight: bold;
font-size: 1.2em;
}
code.descclassname {
background-color: transparent;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
span.eqno a.headerlink {
position: relative;
left: 0px;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print {
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

14
0.9.0/doc/_templates/localtoc.html vendored Normal file
View File

@ -0,0 +1,14 @@
{#
basic/localtoc.html
~~~~~~~~~~~~~~~~~~~
Sphinx sidebar template: local table of contents.
:copyright: Copyright 2007-2017 by the Sphinx team, see AUTHORS.
:license: BSD, see LICENSE for details.
#}
{%- if display_toc %}
<h3><a href="{{ pathto(master_doc) }}">{{ _('On This Page') }}</a></h3>
{{ toc }}
<h3><a href="{{ pathto(master_doc) }}">{{ _('Full Documentation') }}</a></h3>
{%- endif %}

1620
0.9.0/doc/api.rst Normal file

File diff suppressed because it is too large Load Diff

178
0.9.0/doc/conf.py Normal file
View File

@ -0,0 +1,178 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# JuniperStory documentation build configuration file, created by
# sphinx-quickstart on Tue Oct 10 10:18:55 2017.
#
# This file is execfile()d with the current directory set to its
# containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
# import os
# import sys
# sys.path.insert(0, os.path.abspath('.'))
# -- General configuration ------------------------------------------------
# If your documentation needs a minimal Sphinx version, state it here.
#
# needs_sphinx = '1.0'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = []
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix(es) of source filenames.
# You can specify multiple suffix as a list of string:
#
# source_suffix = ['.rst', '.md']
source_suffix = '.rst'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = 'libxo'
copyright = '2017, Juniper Networks'
author = 'Phil Shafer'
default_role = 'code'
primary_domain = 'c'
smart_quotes = False
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '0.8.4'
# The full version, including alpha/beta/rc tags.
release = '0.8.4'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#
# This is also used if you do content translation via gettext catalogs.
# Usually you set "language" from the command line for these cases.
language = None
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This patterns also effect to html_static_path and html_extra_path
exclude_patterns = []
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# If true, `todo` and `todoList` produce output, else they produce nothing.
todo_include_todos = False
# -- Options for HTML output ----------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinxdoc'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
# html_theme_options = {}
html_theme_options = {
"sidebarwidth": 320,
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Custom sidebar templates, must be a dictionary that maps document names
# to template names.
#
# This is required for the alabaster theme
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
alabaster_html_sidebars = {
'**': [
'about.html',
'navigation.html',
'relations.html', # needs 'show_related': True theme option to display
'searchbox.html',
'donate.html',
]
}
# -- Options for HTMLHelp output ------------------------------------------
# Output file base name for HTML help builder.
htmlhelp_basename = 'libxo-manual'
# -- Options for LaTeX output ---------------------------------------------
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#
# 'papersize': 'letterpaper',
# The font size ('10pt', '11pt' or '12pt').
#
# 'pointsize': '10pt',
# Additional stuff for the LaTeX preamble.
#
# 'preamble': '',
# Latex figure (float) alignment
#
# 'figure_align': 'htbp',
}
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
(master_doc, 'libxo.tex', 'libxo Documentation',
'Phil Shafer', 'manual'),
]
# -- Options for manual page output ---------------------------------------
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
(master_doc, 'libxo', 'libxo Documentation',
[author], 1)
]
# -- Options for Texinfo output -------------------------------------------
# Grouping the document tree into Texinfo files. List of tuples
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
(master_doc, 'libxo', 'libxo Documentation',
author, 'libxo', 'A Library for Generating Text, XML, JSON, and HTML Output',
'Miscellaneous'),
]

694
0.9.0/doc/example.rst Normal file
View File

@ -0,0 +1,694 @@
Examples
========
Unit Test
---------
Here is one of the unit tests as an example::
int
main (int argc, char **argv)
{
static char base_grocery[] = "GRO";
static char base_hardware[] = "HRD";
struct item {
const char *i_title;
int i_sold;
int i_instock;
int i_onorder;
const char *i_sku_base;
int i_sku_num;
};
struct item list[] = {
{ "gum", 1412, 54, 10, base_grocery, 415 },
{ "rope", 85, 4, 2, base_hardware, 212 },
{ "ladder", 0, 2, 1, base_hardware, 517 },
{ "bolt", 4123, 144, 42, base_hardware, 632 },
{ "water", 17, 14, 2, base_grocery, 2331 },
{ NULL, 0, 0, 0, NULL, 0 }
};
struct item list2[] = {
{ "fish", 1321, 45, 1, base_grocery, 533 },
};
struct item *ip;
xo_info_t info[] = {
{ "in-stock", "number", "Number of items in stock" },
{ "name", "string", "Name of the item" },
{ "on-order", "number", "Number of items on order" },
{ "sku", "string", "Stock Keeping Unit" },
{ "sold", "number", "Number of items sold" },
{ NULL, NULL, NULL },
};
int info_count = (sizeof(info) / sizeof(info[0])) - 1;
argc = xo_parse_args(argc, argv);
if (argc < 0)
exit(EXIT_FAILURE);
xo_set_info(NULL, info, info_count);
xo_open_container_h(NULL, "top");
xo_open_container("data");
xo_open_list("item");
for (ip = list; ip->i_title; ip++) {
xo_open_instance("item");
xo_emit("{L:Item} '{k:name/%s}':\n", ip->i_title);
xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
ip->i_sold, ip->i_sold ? ".0" : "");
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
ip->i_instock);
xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
ip->i_onorder);
xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
ip->i_sku_base, ip->i_sku_num);
xo_close_instance("item");
}
xo_close_list("item");
xo_close_container("data");
xo_open_container("data");
xo_open_list("item");
for (ip = list2; ip->i_title; ip++) {
xo_open_instance("item");
xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
xo_emit("{P: }{L:Total sold}: {n:sold/%u%s}\n",
ip->i_sold, ip->i_sold ? ".0" : "");
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
ip->i_instock);
xo_emit("{P: }{Lwc:On order}{:on-order/%u}\n",
ip->i_onorder);
xo_emit("{P: }{L:SKU}: {q:sku/%s-000-%u}\n",
ip->i_sku_base, ip->i_sku_num);
xo_close_instance("item");
}
xo_close_list("item");
xo_close_container("data");
xo_close_container_h(NULL, "top");
return 0;
}
Text output::
% ./testxo --libxo text
Item 'gum':
Total sold: 1412.0
In stock: 54
On order: 10
SKU: GRO-000-415
Item 'rope':
Total sold: 85.0
In stock: 4
On order: 2
SKU: HRD-000-212
Item 'ladder':
Total sold: 0
In stock: 2
On order: 1
SKU: HRD-000-517
Item 'bolt':
Total sold: 4123.0
In stock: 144
On order: 42
SKU: HRD-000-632
Item 'water':
Total sold: 17.0
In stock: 14
On order: 2
SKU: GRO-000-2331
Item 'fish':
Total sold: 1321.0
In stock: 45
On order: 1
SKU: GRO-000-533
JSON output::
% ./testxo --libxo json,pretty
"top": {
"data": {
"item": [
{
"name": "gum",
"sold": 1412.0,
"in-stock": 54,
"on-order": 10,
"sku": "GRO-000-415"
},
{
"name": "rope",
"sold": 85.0,
"in-stock": 4,
"on-order": 2,
"sku": "HRD-000-212"
},
{
"name": "ladder",
"sold": 0,
"in-stock": 2,
"on-order": 1,
"sku": "HRD-000-517"
},
{
"name": "bolt",
"sold": 4123.0,
"in-stock": 144,
"on-order": 42,
"sku": "HRD-000-632"
},
{
"name": "water",
"sold": 17.0,
"in-stock": 14,
"on-order": 2,
"sku": "GRO-000-2331"
}
]
},
"data": {
"item": [
{
"name": "fish",
"sold": 1321.0,
"in-stock": 45,
"on-order": 1,
"sku": "GRO-000-533"
}
]
}
}
XML output::
% ./testxo --libxo pretty,xml
<top>
<data>
<item>
<name>gum</name>
<sold>1412.0</sold>
<in-stock>54</in-stock>
<on-order>10</on-order>
<sku>GRO-000-415</sku>
</item>
<item>
<name>rope</name>
<sold>85.0</sold>
<in-stock>4</in-stock>
<on-order>2</on-order>
<sku>HRD-000-212</sku>
</item>
<item>
<name>ladder</name>
<sold>0</sold>
<in-stock>2</in-stock>
<on-order>1</on-order>
<sku>HRD-000-517</sku>
</item>
<item>
<name>bolt</name>
<sold>4123.0</sold>
<in-stock>144</in-stock>
<on-order>42</on-order>
<sku>HRD-000-632</sku>
</item>
<item>
<name>water</name>
<sold>17.0</sold>
<in-stock>14</in-stock>
<on-order>2</on-order>
<sku>GRO-000-2331</sku>
</item>
</data>
<data>
<item>
<name>fish</name>
<sold>1321.0</sold>
<in-stock>45</in-stock>
<on-order>1</on-order>
<sku>GRO-000-533</sku>
</item>
</data>
</top>
HMTL output::
% ./testxo --libxo pretty,html
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">gum</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">1412.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">54</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">10</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">GRO-000-415</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">rope</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">85.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">4</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">HRD-000-212</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">ladder</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">HRD-000-517</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">bolt</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">4123.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">144</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">42</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">HRD-000-632</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">water</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">17.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">14</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">GRO-000-2331</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name">fish</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">1321.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">45</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku">GRO-000-533</div>
</div>
HTML output with xpath and info flags::
% ./testxo --libxo pretty,html,xpath,info
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">gum</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">1412.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">54</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">10</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">GRO-000-415</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">rope</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">85.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">4</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">HRD-000-212</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">ladder</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">HRD-000-517</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">bolt</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">4123.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">144</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">42</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">HRD-000-632</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">water</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">17.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">14</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">GRO-000-2331</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name"
data-xpath="/top/data/item/name" data-type="string"
data-help="Name of the item">fish</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold"
data-xpath="/top/data/item/sold" data-type="number"
data-help="Number of items sold">1321.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock" data-type="number"
data-help="Number of items in stock">45</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order"
data-xpath="/top/data/item/on-order" data-type="number"
data-help="Number of items on order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku"
data-xpath="/top/data/item/sku" data-type="string"
data-help="Stock Keeping Unit">GRO-000-533</div>
</div>

209
0.9.0/doc/faq.rst Normal file
View File

@ -0,0 +1,209 @@
FAQs
====
This section contains the set of questions that users typically ask,
along with answers that might be helpful.
General
-------
Can you share the history of libxo?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In 2001, we added an XML API to the JUNOS operating system, which is
built on top of FreeBSD_. Eventually this API became standardized as
the NETCONF API (:RFC:`6241`). As part of this effort, we modified many
FreeBSD utilities to emit XML, typically via a "-X" switch. The
results were mixed. The cost of maintaining this code, updating it,
and carrying it were non-trivial, and contributed to our expense (and
the associated delay) with upgrading the version of FreeBSD on which
each release of JUNOS is based.
.. _FreeBSD: https://www.freebsd.org
A recent (2014) effort within JUNOS aims at removing our modifications
to the underlying FreeBSD code as a means of reducing the expense and
delay in tracking HEAD. JUNOS is structured to have system components
generate XML that is rendered by the CLI (think: login shell) into
human-readable text. This allows the API to use the same plumbing as
the CLI, and ensures that all components emit XML, and that it is
emitted with knowledge of the consumer of that XML, yielding an API
that have no incremental cost or feature delay.
libxo is an effort to mix the best aspects of the JUNOS strategy into
FreeBSD in a seemless way, allowing commands to make printf-like
output calls with a single code path.
Did the complex semantics of format strings evolve over time?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The history is both long and short: libxo's functionality is based
on what JUNOS does in a data modeling language called ODL (output
definition language). In JUNOS, all subcomponents generate XML,
which is feed to the CLI, where data from the ODL files tell is
how to render that XML into text. ODL might had a set of tags
like::
tag docsis-state {
help "State of the DOCSIS interface";
type string;
}
tag docsis-mode {
help "DOCSIS mode (2.0/3.0) of the DOCSIS interface";
type string;
}
tag docsis-upstream-speed {
help "Operational upstream speed of the interface";
type string;
}
tag downstream-scanning {
help "Result of scanning in downstream direction";
type string;
}
tag ranging {
help "Result of ranging action";
type string;
}
tag signal-to-noise-ratio {
help "Signal to noise ratio for all channels";
type string;
}
tag power {
help "Operational power of the signal on all channels";
type string;
}
format docsis-status-format {
picture "
State : @, Mode: @, Upstream speed: @
Downstream scanning: @, Ranging: @
Signal to noise ratio: @
Power: @
";
line {
field docsis-state;
field docsis-mode;
field docsis-upstream-speed;
field downstream-scanning;
field ranging;
field signal-to-noise-ratio;
field power;
}
}
These tag definitions are compiled into field definitions
that are triggered when matching XML elements are seen. ODL
also supports other means of defining output.
The roles and modifiers describe these details.
In moving these ideas to bsd, two things had to happen: the
formatting had to happen at the source since BSD won't have
a JUNOS-like CLI to do the rendering, and we can't depend on
external data models like ODL, which was seen as too hard a
sell to the BSD community.
The results were that the xo_emit strings are used to encode the
roles, modifiers, names, and formats. They are dense and a bit
cryptic, but not so unlike printf format strings that developers will
be lost.
libxo is a new implementation of these ideas and is distinct from
the previous implementation in JUNOS.
.. index:: XOF_UNDERSCORES
.. _good-field-names:
What makes a good field name?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To make useful, consistent field names, follow these guidelines:
Use lower case, even for TLAs
Lower case is more civilized. Even TLAs should be lower case
to avoid scenarios where the differences between "XPath" and
"Xpath" drive your users crazy. Using "xpath" is simpler and better.
Use hyphens, not underscores
Use of hyphens is traditional in XML, and the XOF_UNDERSCORES
flag can be used to generate underscores in JSON, if desired.
But the raw field name should use hyphens.
Use full words
Don't abbreviate especially when the abbreviation is not obvious or
not widely used. Use "data-size", not "dsz" or "dsize". Use
"interface" instead of "ifname", "if-name", "iface", "if", or "intf".
Use <verb>-<units>
Using the form <verb>-<units> or <verb>-<classifier>-<units> helps in
making consistent, useful names, avoiding the situation where one app
uses "sent-packet" and another "packets-sent" and another
"packets-we-have-sent". The <units> can be dropped when it is
obvious, as can obvious words in the classification.
Use "receive-after-window-packets" instead of
"received-packets-of-data-after-window".
Reuse existing field names
Nothing's worse than writing expressions like::
if ($src1/process[pid == $pid]/name ==
$src2/proc-table/proc-list
/prc-entry[prcss-id == $pid]/proc-name) {
...
}
Find someone else who is expressing similar data and follow their
fields and hierarchy. Remember the quote is not "Consistency is the
hobgoblin of little minds", but "A *foolish* consistency is the
hobgoblin of little minds". Consistency rocks!
Use containment as scoping
In the previous example, all the names are prefixed with "proc-",
which is redundant given that they are nested under the process table.
Think about your users
Have empathy for your users, choosing clear and useful fields that
contain clear and useful data. You may need to augment the display
content with xo_attr() calls (:ref:`xo_attr`) or "{e:}"
fields (:ref:`encoding-modifier`) to make the data useful.
Don't use an arbitrary number postfix
What does "errors2" mean? No one will know. "errors-after-restart"
would be a better choice. Think of your users, and think of the
future. If you make "errors2", the next guy will happily make
"errors3" and before you know it, someone will be asking what's the
difference between errors37 and errors63.
Be consistent, uniform, unsurprising, and predictable
Think of your field vocabulary as an API. You want it useful,
expressive, meaningful, direct, and obvious. You want the client
application's programmer to move between without the need to
understand a variety of opinions on how fields are named. They
should see the system as a single cohesive whole, not a sack of
cats.
Field names constitute the means by which client programmers interact
with our system. By choosing wise names now, you are making their
lives better.
After using `xolint` to find errors in your field descriptors, use
"`xolint -V`" to spell check your field names and to help you detect
different names for the same data. "dropped-short" and
"dropped-too-short" are both reasonable names, but using them both
will lead users to ask the difference between the two fields. If
there is no difference, use only one of the field names. If there is
a difference, change the names to make that difference more obvious.
.. ignore for now, since we want can't have generated content
What does this message mean?
----------------------------
!!include-file xolint.txt

View File

@ -0,0 +1,370 @@
.. index:: Field Formatting
Field Formatting
----------------
The field format is similar to the format string for printf(3). Its
use varies based on the role of the field, but generally is used to
format the field's contents.
If the format string is not provided for a value field, it defaults to
"%s".
Note a field definition can contain zero or more printf-style
'directives', which are sequences that start with a '%' and end with
one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive
is matched by one of more arguments to the xo_emit function.
The format string has the form::
'%' format-modifier * format-character
The format-modifier can be:
- a '#' character, indicating the output value should be prefixed
with '0x', typically to indicate a base 16 (hex) value.
- a minus sign ('-'), indicating the output value should be padded on
the right instead of the left.
- a leading zero ('0') indicating the output value should be padded on the
left with zeroes instead of spaces (' ').
- one or more digits ('0' - '9') indicating the minimum width of the
argument. If the width in columns of the output value is less than
the minimum width, the value will be padded to reach the minimum.
- a period followed by one or more digits indicating the maximum
number of bytes which will be examined for a string argument, or the maximum
width for a non-string argument. When handling ASCII strings this
functions as the field width but for multi-byte characters, a single
character may be composed of multiple bytes.
xo_emit will never dereference memory beyond the given number of bytes.
- a second period followed by one or more digits indicating the maximum
width for a string argument. This modifier cannot be given for non-string
arguments.
- one or more 'h' characters, indicating shorter input data.
- one or more 'l' characters, indicating longer input data.
- a 'z' character, indicating a 'size_t' argument.
- a 't' character, indicating a 'ptrdiff_t' argument.
- a ' ' character, indicating a space should be emitted before
positive numbers.
- a '+' character, indicating sign should emitted before any number.
Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be
removed eventually.
The format character is described in the following table:
===== ================= ======================
Ltr Argument Type Format
===== ================= ======================
d int base 10 (decimal)
i int base 10 (decimal)
o int base 8 (octal)
u unsigned base 10 (decimal)
x unsigned base 16 (hex)
X unsigned long base 16 (hex)
D long base 10 (decimal)
O unsigned long base 8 (octal)
U unsigned long base 10 (decimal)
e double [-]d.ddde+-dd
E double [-]d.dddE+-dd
f double [-]ddd.ddd
F double [-]ddd.ddd
g double as 'e' or 'f'
G double as 'E' or 'F'
a double [-]0xh.hhhp[+-]d
A double [-]0Xh.hhhp[+-]d
c unsigned char a character
C wint_t a character
s char \* a UTF-8 string
S wchar_t \* a unicode/WCS string
p void \* '%#lx'
===== ================= ======================
The 'h' and 'l' modifiers affect the size and treatment of the
argument:
===== ============= ====================
Mod d, i o, u, x, X
===== ============= ====================
hh signed char unsigned char
h short unsigned short
l long unsigned long
ll long long unsigned long long
j intmax_t uintmax_t
t ptrdiff_t ptrdiff_t
z size_t size_t
q quad_t u_quad_t
===== ============= ====================
.. index:: UTF-8
.. index:: Locale
.. _utf-8:
UTF-8 and Locale Strings
~~~~~~~~~~~~~~~~~~~~~~~~
For strings, the 'h' and 'l' modifiers affect the interpretation of
the bytes pointed to argument. The default '%s' string is a 'char \*'
pointer to a string encoded as UTF-8. Since UTF-8 is compatible with
ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a
'wchar_t \*' pointer to a wide-character string, encoded as a 32-bit
Unicode values. '%hs' expects a 'char \*' pointer to a multi-byte
string encoded with the current locale, as given by the LC_CTYPE,
LANG, or LC_ALL environment varibles. The first of this list of
variables is used and if none of the variables are set, the locale
defaults to "UTF-8".
libxo will convert these arguments as needed to either UTF-8 (for XML,
JSON, and HTML styles) or locale-based strings for display in text
style::
xo_emit("All strings are utf-8 content {:tag/%ls}",
L"except for wide strings");
======== ================== ===============================
Format Argument Type Argument Contents
======== ================== ===============================
%s const char \* UTF-8 string
%S const char \* UTF-8 string (alias for '%ls')
%ls const wchar_t \* Wide character UNICODE string
%hs const char * locale-based string
======== ================== ===============================
.. admonition:: "Long", not "locale"
The "*l*" in "%ls" is for "*long*", following the convention of "%ld".
It is not "*locale*", a common mis-mnemonic. "%S" is equivalent to
"%ls".
For example, the following function is passed a locale-base name, a
hat size, and a time value. The hat size is formatted in a UTF-8
(ASCII) string, and the time value is formatted into a wchar_t
string::
void print_order (const char *name, int size,
struct tm *timep) {
char buf[32];
const char *size_val = "unknown";
if (size > 0)
snprintf(buf, sizeof(buf), "%d", size);
size_val = buf;
}
wchar_t when[32];
wcsftime(when, sizeof(when), L"%d%b%y", timep);
xo_emit("The hat for {:name/%hs} is {:size/%s}.\n",
name, size_val);
xo_emit("It was ordered on {:order-time/%ls}.\n",
when);
}
It is important to note that xo_emit will perform the conversion
required to make appropriate output. Text style output uses the
current locale (as described above), while XML, JSON, and HTML use
UTF-8.
UTF-8 and locale-encoded strings can use multiple bytes to encode one
column of data. The traditional "precision'" (aka "max-width") value
for "%s" printf formatting becomes overloaded since it specifies both
the number of bytes that can be safely referenced and the maximum
number of columns to emit. xo_emit uses the precision as the former,
and adds a third value for specifying the maximum number of columns.
In this example, the name field is printed with a minimum of 3 columns
and a maximum of 6. Up to ten bytes of data at the location given by
'name' are in used in filling those columns::
xo_emit("{:name/%3.10.6s}", name);
Characters Outside of Field Definitions
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Characters in the format string that are not part of a field
definition are copied to the output for the TEXT style, and are
ignored for the JSON and XML styles. For HTML, these characters are
placed in a <div> with class "text"::
EXAMPLE:
xo_emit("The hat is {:size/%s}.\n", size_val);
TEXT:
The hat is extra small.
XML:
<size>extra small</size>
JSON:
"size": "extra small"
HTML:
<div class="text">The hat is </div>
<div class="data" data-tag="size">extra small</div>
<div class="text">.</div>
.. index:: errno
"%m" Is Supported
~~~~~~~~~~~~~~~~~
libxo supports the '%m' directive, which formats the error message
associated with the current value of "errno". It is the equivalent
of "%s" with the argument strerror(errno)::
xo_emit("{:filename} cannot be opened: {:error/%m}", filename);
xo_emit("{:filename} cannot be opened: {:error/%s}",
filename, strerror(errno));
"%n" Is Not Supported
~~~~~~~~~~~~~~~~~~~~~
libxo does not support the '%n' directive. It's a bad idea and we
just don't do it.
The Encoding Format (eformat)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The "eformat" string is the format string used when encoding the field
for JSON and XML. If not provided, it defaults to the primary format
with any minimum width removed. If the primary is not given, both
default to "%s".
Content Strings
~~~~~~~~~~~~~~~
For padding and labels, the content string is considered the content,
unless a format is given.
.. index:: printf-like
Argument Validation
~~~~~~~~~~~~~~~~~~~
Many compilers and tool chains support validation of printf-like
arguments. When the format string fails to match the argument list,
a warning is generated. This is a valuable feature and while the
formatting strings for libxo differ considerably from printf, many of
these checks can still provide build-time protection against bugs.
libxo provide variants of functions that provide this ability, if the
"--enable-printflike" option is passed to the "configure" script.
These functions use the "_p" suffix, like "xo_emit_p()",
xo_emit_hp()", etc.
The following are features of libxo formatting strings that are
incompatible with printf-like testing:
- implicit formats, where "{:tag}" has an implicit "%s";
- the "max" parameter for strings, where "{:tag/%4.10.6s}" means up to
ten bytes of data can be inspected to fill a minimum of 4 columns and
a maximum of 6;
- percent signs in strings, where "{:filled}%" makes a single,
trailing percent sign;
- the "l" and "h" modifiers for strings, where "{:tag/%hs}" means
locale-based string and "{:tag/%ls}" means a wide character string;
- distinct encoding formats, where "{:tag/#%s/%s}" means the display
styles (text and HTML) will use "#%s" where other styles use "%s";
If none of these features are in use by your code, then using the "_p"
variants might be wise:
================== ========================
Function printf-like Equivalent
================== ========================
xo_emit_hv xo_emit_hvp
xo_emit_h xo_emit_hp
xo_emit xo_emit_p
xo_emit_warn_hcv xo_emit_warn_hcvp
xo_emit_warn_hc xo_emit_warn_hcp
xo_emit_warn_c xo_emit_warn_cp
xo_emit_warn xo_emit_warn_p
xo_emit_warnx xo_emit_warnx_p
xo_emit_err xo_emit_err_p
xo_emit_errx xo_emit_errx_p
xo_emit_errc xo_emit_errc_p
================== ========================
.. index:: performance
.. index:: XOEF_RETAIN
.. _retain:
Retaining Parsed Format Information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
libxo can retain the parsed internal information related to the given
format string, allowing subsequent xo_emit calls, the retained
information is used, avoiding repetitive parsing of the format string::
SYNTAX:
int xo_emit_f(xo_emit_flags_t flags, const char fmt, ...);
EXAMPLE:
xo_emit_f(XOEF_RETAIN, "{:some/%02d}{:thing/%-6s}{:fancy}\n",
some, thing, fancy);
To retain parsed format information, use the XOEF_RETAIN flag to the
xo_emit_f() function. A complete set of xo_emit_f functions exist to
match all the xo_emit function signatures (with handles, varadic
argument, and printf-like flags):
================== ========================
Function Flags Equivalent
================== ========================
xo_emit_hv xo_emit_hvf
xo_emit_h xo_emit_hf
xo_emit xo_emit_f
xo_emit_hvp xo_emit_hvfp
xo_emit_hp xo_emit_hfp
xo_emit_p xo_emit_fp
================== ========================
The format string must be immutable across multiple calls to xo_emit_f(),
since the library retains the string. Typically this is done by using
static constant strings, such as string literals. If the string is not
immutable, the XOEF_RETAIN flag must not be used.
The functions xo_retain_clear() and xo_retain_clear_all() release
internal information on either a single format string or all format
strings, respectively. Neither is required, but the library will
retain this information until it is cleared or the process exits::
const char *fmt = "{:name} {:count/%d}\n";
for (i = 0; i < 1000; i++) {
xo_open_instance("item");
xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
}
xo_retain_clear(fmt);
The retained information is kept as thread-specific data.
Example
~~~~~~~
In this example, the value for the number of items in stock is emitted::
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n",
instock);
This call will generate the following output::
TEXT:
In stock: 144
XML:
<in-stock>144</in-stock>
JSON:
"in-stock": 144,
HTML:
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">144</div>
</div>
Clearly HTML wins the verbosity award, and this output does
not include XOF_XPATH or XOF_INFO data, which would expand the
penultimate line to::
<div class="data" data-tag="in-stock"
data-xpath="/top/data/item/in-stock"
data-type="number"
data-help="Number of items in stock">144</div>

View File

@ -0,0 +1,353 @@
.. index:: Field Modifiers
.. _field-modifiers:
Field Modifiers
~~~~~~~~~~~~~~~
Field modifiers are flags which modify the way content emitted for
particular output styles:
=== =============== ===================================================
M Name Description
=== =============== ===================================================
a argument The content appears as a 'const char \*' argument
c colon A colon (":") is appended after the label
d display Only emit field for display styles (text/HTML)
e encoding Only emit for encoding styles (XML/JSON)
g gettext Call gettext on field's render content
h humanize (hn) Format large numbers in human-readable style
\ hn-space Humanize: Place space between numeric and unit
\ hn-decimal Humanize: Add a decimal digit, if number < 10
\ hn-1000 Humanize: Use 1000 as divisor instead of 1024
k key Field is a key, suitable for XPath predicates
l leaf-list Field is a leaf-list
n no-quotes Do not quote the field when using JSON style
p plural Gettext: Use comma-separated plural form
q quotes Quote the field when using JSON style
t trim Trim leading and trailing whitespace
w white A blank (" ") is appended after the label
=== =============== ===================================================
Roles and modifiers can also use more verbose names, when preceded by
a comma. For example, the modifier string "Lwc" (or "L,white,colon")
means the field has a label role (text that describes the next field)
and should be followed by a colon ('c') and a space ('w'). The
modifier string "Vkq" (or ":key,quote") means the field has a value
role (the default role), that it is a key for the current instance,
and that the value should be quoted when encoded for JSON.
.. index:: Field Modifiers; Argument
.. _argument-modifier:
The Argument Modifier ({a:})
++++++++++++++++++++++++++++
.. index:: Field Modifiers; Argument
The argument modifier indicates that the content of the field
descriptor will be placed as a UTF-8 string (const char \*) argument
within the xo_emit parameters::
EXAMPLE:
xo_emit("{La:} {a:}\n", "Label text", "label", "value");
TEXT:
Label text value
JSON:
"label": "value"
XML:
<label>value</label>
The argument modifier allows field names for value fields to be passed
on the stack, avoiding the need to build a field descriptor using
snprintf. For many field roles, the argument modifier is not needed,
since those roles have specific mechanisms for arguments, such as
"{C:fg-%s}".
.. index:: Field Modifiers; Colon
.. _colon-modifier:
The Colon Modifier ({c:})
+++++++++++++++++++++++++
.. index:: Field Modifiers; Colon
The colon modifier appends a single colon to the data value::
EXAMPLE:
xo_emit("{Lc:Name}{:name}\n", "phil");
TEXT:
Name:phil
The colon modifier is only used for the TEXT and HTML output
styles. It is commonly combined with the space modifier ('{w:}').
It is purely a convenience feature.
.. index:: Field Modifiers; Display
.. _display-modifier:
The Display Modifier ({d:})
+++++++++++++++++++++++++++
.. index:: Field Modifiers; Display
The display modifier indicated the field should only be generated for
the display output styles, TEXT and HTML::
EXAMPLE:
xo_emit("{Lcw:Name}{d:name} {:id/%d}\n", "phil", 1);
TEXT:
Name: phil 1
XML:
<id>1</id>
The display modifier is the opposite of the encoding modifier, and
they are often used to give to distinct views of the underlying data.
.. index:: Field Modifiers; Encoding
.. _encoding-modifier:
The Encoding Modifier ({e:})
++++++++++++++++++++++++++++
.. index:: Field Modifiers; Encoding
The display modifier indicated the field should only be generated for
the display output styles, TEXT and HTML::
EXAMPLE:
xo_emit("{Lcw:Name}{:name} {e:id/%d}\n", "phil", 1);
TEXT:
Name: phil
XML:
<name>phil</name><id>1</id>
The encoding modifier is the opposite of the display modifier, and
they are often used to give to distinct views of the underlying data.
.. index:: Field Modifiers; Gettext
.. _gettext-modifier:
The Gettext Modifier ({g:})
+++++++++++++++++++++++++++
.. index:: Field Modifiers; Gettext
.. index:: gettext
The gettext modifier is used to translate individual fields using the
gettext domain (typically set using the "`{G:}`" role) and current
language settings. Once libxo renders the field value, it is passed
to gettext(3), where it is used as a key to find the native language
translation.
In the following example, the strings "State" and "full" are passed
to gettext() to find locale-based translated strings::
xo_emit("{Lgwc:State}{g:state}\n", "full");
See :ref:`gettext-role`, :ref:`plural-modifier`, and
:ref:`i18n` for additional details.
.. index:: Field Modifiers; Humanize
.. _humanize-modifier:
The Humanize Modifier ({h:})
++++++++++++++++++++++++++++
.. index:: Field Modifiers; Humanize
The humanize modifier is used to render large numbers as in a
human-readable format. While numbers like "44470272" are completely
readable to computers and savants, humans will generally find "44M"
more meaningful.
"hn" can be used as an alias for "humanize".
The humanize modifier only affects display styles (TEXT and HMTL).
The "`no-humanize`" option (See :ref:`options`) will block
the function of the humanize modifier.
There are a number of modifiers that affect details of humanization.
These are only available in as full names, not single characters. The
"`hn-space`" modifier places a space between the number and any
multiplier symbol, such as "M" or "K" (ex: "44 K"). The
"`hn-decimal`" modifier will add a decimal point and a single tenths
digit when the number is less than 10 (ex: "4.4K"). The "`hn-1000`"
modifier will use 1000 as divisor instead of 1024, following the
JEDEC-standard instead of the more natural binary powers-of-two
tradition::
EXAMPLE:
xo_emit("{h:input/%u}, {h,hn-space:output/%u}, "
"{h,hn-decimal:errors/%u}, {h,hn-1000:capacity/%u}, "
"{h,hn-decimal:remaining/%u}\n",
input, output, errors, capacity, remaining);
TEXT:
21, 57 K, 96M, 44M, 1.2G
In the HTML style, the original numeric value is rendered in the
"data-number" attribute on the <div> element::
<div class="data" data-tag="errors"
data-number="100663296">96M</div>
.. index:: Field Modifiers; Key
.. _key-modifier:
The Key Modifier ({k:})
+++++++++++++++++++++++
.. index:: Field Modifiers; Key
The key modifier is used to indicate that a particular field helps
uniquely identify an instance of list data::
EXAMPLE:
xo_open_list("user");
for (i = 0; i < num_users; i++) {
xo_open_instance("user");
xo_emit("User {k:name} has {:count} tickets\n",
user[i].u_name, user[i].u_tickets);
xo_close_instance("user");
}
xo_close_list("user");
.. index:: XOF_XPATH
Currently the key modifier is only used when generating XPath value
for the HTML output style when XOF_XPATH is set, but other uses are
likely in the near future.
.. index:: Field Modifiers; Leaf-List
.. _leaf-list:
The Leaf-List Modifier ({l:})
+++++++++++++++++++++++++++++
.. index:: Field Modifiers; Leaf-List
The leaf-list modifier is used to distinguish lists where each
instance consists of only a single value. In XML, these are
rendered as single elements, where JSON renders them as arrays::
EXAMPLE:
for (i = 0; i < num_users; i++) {
xo_emit("Member {l:user}\n", user[i].u_name);
}
XML:
<user>phil</user>
<user>pallavi</user>
JSON:
"user": [ "phil", "pallavi" ]
The name of the field must match the name of the leaf list.
.. index:: Field Modifiers; No-Quotes
.. _no-quotes-modifier:
The No-Quotes Modifier ({n:})
+++++++++++++++++++++++++++++
.. index:: Field Modifiers; No-Quotes
The no-quotes modifier (and its twin, the 'quotes' modifier) affect
the quoting of values in the JSON output style. JSON uses quotes for
string value, but no quotes for numeric, boolean, and null data.
xo_emit applies a simple heuristic to determine whether quotes are
needed, but often this needs to be controlled by the caller::
EXAMPLE:
const char *bool = is_true ? "true" : "false";
xo_emit("{n:fancy/%s}", bool);
JSON:
"fancy": true
.. index:: Field Modifiers; Plural
.. _plural-modifier:
The Plural Modifier ({p:})
++++++++++++++++++++++++++
.. index:: Field Modifiers; Plural
.. index:: gettext
The plural modifier selects the appropriate plural form of an
expression based on the most recent number emitted and the current
language settings. The contents of the field should be the singular
and plural English values, separated by a comma::
xo_emit("{:bytes} {Ngp:byte,bytes}\n", bytes);
The plural modifier is meant to work with the gettext modifier ({g:})
but can work independently. See :ref:`gettext-modifier`.
When used without the gettext modifier or when the message does not
appear in the message catalog, the first token is chosen when the last
numeric value is equal to 1; otherwise the second value is used,
mimicking the simple pluralization rules of English.
When used with the gettext modifier, the ngettext(3) function is
called to handle the heavy lifting, using the message catalog to
convert the singular and plural forms into the native language.
.. index:: Field Modifiers; Quotes
.. _quotes-modifier:
The Quotes Modifier ({q:})
++++++++++++++++++++++++++
.. index:: Field Modifiers; Quotes
The quotes modifier (and its twin, the 'no-quotes' modifier) affect
the quoting of values in the JSON output style. JSON uses quotes for
string value, but no quotes for numeric, boolean, and null data.
xo_emit applies a simple heuristic to determine whether quotes are
needed, but often this needs to be controlled by the caller::
EXAMPLE:
xo_emit("{q:time/%d}", 2014);
JSON:
"year": "2014"
The heuristic is based on the format; if the format uses any of the
following conversion specifiers, then no quotes are used::
d i o u x X D O U e E f F g G a A c C p
.. index:: Field Modifiers; Trim
.. _trim-modifier:
The Trim Modifier ({t:})
++++++++++++++++++++++++
.. index:: Field Modifiers; Trim
The trim modifier removes any leading or trailing whitespace from
the value::
EXAMPLE:
xo_emit("{t:description}", " some input ");
JSON:
"description": "some input"
.. index:: Field Modifiers; White Space
.. _white-space-modifier:
The White Space Modifier ({w:})
+++++++++++++++++++++++++++++++
.. index:: Field Modifiers; White Space
The white space modifier appends a single space to the data value::
EXAMPLE:
xo_emit("{Lw:Name}{:name}\n", "phil");
TEXT:
Name phil
The white space modifier is only used for the TEXT and HTML output
styles. It is commonly combined with the colon modifier ('{c:}').
It is purely a convenience feature.
Note that the sense of the 'w' modifier is reversed for the units role
({Uw:}); a blank is added before the contents, rather than after it.

310
0.9.0/doc/field-roles.rst Normal file
View File

@ -0,0 +1,310 @@
.. index:: Field Roles
.. _field-roles:
Field Roles
~~~~~~~~~~~
Field roles are optional, and indicate the role and formatting of the
content. The roles are listed below; only one role is permitted:
=== ============== =================================================
R Name Description
=== ============== =================================================
C color Field has color and effect controls
D decoration Field is non-text (e.g., colon, comma)
E error Field is an error message
G gettext Call gettext(3) on the format string
L label Field is text that prefixes a value
N note Field is text that follows a value
P padding Field is spaces needed for vertical alignment
T title Field is a title value for headings
U units Field is the units for the previous value field
V value Field is the name of field (the default)
W warning Field is a warning message
[ start-anchor Begin a section of anchored variable-width text
] stop-anchor End a section of anchored variable-width text
=== ============== =================================================
EXAMPLE:
xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\n",
free_blocks);
When a role is not provided, the "*value*" role is used as the default.
Roles and modifiers can also use more verbose names, when preceded by
a comma::
EXAMPLE:
xo_emit("{,label:Free}{,decoration::}{,padding: }"
"{,value:free/%u} {,units:Blocks}\n",
free_blocks);
.. index:: Field Roles; Color
.. _color-role:
The Color Role ({C:})
+++++++++++++++++++++
Colors and effects control how text values are displayed; they are
used for display styles (TEXT and HTML)::
xo_emit("{C:bold}{:value}{C:no-bold}\n", value);
Colors and effects remain in effect until modified by other "C"-role
fields::
xo_emit("{C:bold}{C:inverse}both{C:no-bold}only inverse\n");
If the content is empty, the "*reset*" action is performed::
xo_emit("{C:both,underline}{:value}{C:}\n", value);
The content should be a comma-separated list of zero or more colors or
display effects::
xo_emit("{C:bold,inverse}Ugly{C:no-bold,no-inverse}\n");
The color content can be either static, when placed directly within
the field descriptor, or a printf-style format descriptor can be used,
if preceded by a slash ("/"):
xo_emit("{C:/%s%s}{:value}{C:}", need_bold ? "bold" : "",
need_underline ? "underline" : "", value);
Color names are prefixed with either "fg-" or "bg-" to change the
foreground and background colors, respectively::
xo_emit("{C:/fg-%s,bg-%s}{Lwc:Cost}{:cost/%u}{C:reset}\n",
fg_color, bg_color, cost);
The following table lists the supported effects:
=============== =================================================
Name Description
=============== =================================================
bg-XXXXX Change background color
bold Start bold text effect
fg-XXXXX Change foreground color
inverse Start inverse (aka reverse) text effect
no-bold Stop bold text effect
no-inverse Stop inverse (aka reverse) text effect
no-underline Stop underline text effect
normal Reset effects (only)
reset Reset colors and effects (restore defaults)
underline Start underline text effect
=============== =================================================
The following color names are supported:
========= ============================================
Name Description
========= ============================================
black
blue
cyan
default Default color for foreground or background
green
magenta
red
white
yellow
========= ============================================
When using colors, the developer should remember that users will
change the foreground and background colors of terminal session
according to their own tastes, so assuming that "blue" looks nice is
never safe, and is a constant annoyance to your dear author. In
addition, a significant percentage of users (1 in 12) will be color
blind. Depending on color to convey critical information is not a
good idea. Color should enhance output, but should not be used as the
sole means of encoding information.
.. index:: Field Roles; Decoration
.. _decoration-role:
The Decoration Role ({D:})
++++++++++++++++++++++++++
Decorations are typically punctuation marks such as colons,
semi-colons, and commas used to decorate the text and make it simpler
for human readers. By marking these distinctly, HTML usage scenarios
can use CSS to direct their display parameters::
xo_emit("{D:((}{:name}{D:))}\n", name);
.. index:: Field Roles; Gettext
.. _gettext-role:
The Gettext Role ({G:})
+++++++++++++++++++++++
libxo supports internationalization (i18n) through its use of
gettext(3). Use the "{G:}" role to request that the remaining part of
the format string, following the "{G:}" field, be handled using
gettext().
Since gettext() uses the string as the key into the message catalog,
libxo uses a simplified version of the format string that removes
unimportant field formatting and modifiers, stopping minor formatting
changes from impacting the expensive translation process. A developer
change such as changing "/%06d" to "/%08d" should not force hand
inspection of all .po files.
The simplified version can be generated for a single message using the
"`xopo -s $text`" command, or an entire .pot can be translated using
the "`xopo -f $input -o $output`" command.
xo_emit("{G:}Invalid token\n");
The {G:} role allows a domain name to be set. gettext calls will
continue to use that domain name until the current format string
processing is complete, enabling a library function to emit strings
using it's own catalog. The domain name can be either static as the
content of the field, or a format can be used to get the domain name
from the arguments.
xo_emit("{G:libc}Service unavailable in restricted mode\n");
See :ref:`i18n` for additional details.
.. index:: Field Roles; Label
.. _label-role:
The Label Role ({L:})
+++++++++++++++++++++
Labels are text that appears before a value::
xo_emit("{Lwc:Cost}{:cost/%u}\n", cost);
.. index:: Field Roles; Note
.. _note-role:
The Note Role ({N:})
++++++++++++++++++++
Notes are text that appears after a value::
xo_emit("{:cost/%u} {N:per year}\n", cost);
.. index:: Field Roles; Padding
.. _padding-role:
The Padding Role ({P:})
+++++++++++++++++++++++
Padding represents whitespace used before and between fields.
The padding content can be either static, when placed directly within
the field descriptor, or a printf-style format descriptor can be used,
if preceded by a slash ("/")::
xo_emit("{P: }{Lwc:Cost}{:cost/%u}\n", cost);
xo_emit("{P:/%30s}{Lwc:Cost}{:cost/%u}\n", "", cost);
.. index:: Field Roles; Title
.. _title-role:
The Title Role ({T:})
+++++++++++++++++++++
Title are heading or column headers that are meant to be displayed to
the user. The title can be either static, when placed directly within
the field descriptor, or a printf-style format descriptor can be used,
if preceded by a slash ("/")::
xo_emit("{T:Interface Statistics}\n");
xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost");
Title fields have an extra convenience feature; if both content and
format are specified, instead of looking to the argument list for a
value, the content is used, allowing a mixture of format and content
within the field descriptor::
xo_emit("{T:Name/%20s}{T:Count/%6s}\n");
Since the incoming argument is a string, the format must be "%s" or
something suitable.
.. index:: Field Roles; Units
.. index:: XOF_UNITS
.. _units-role:
The Units Role ({U:})
+++++++++++++++++++++
Units are the dimension by which values are measured, such as degrees,
miles, bytes, and decibels. The units field carries this information
for the previous value field::
xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\n", miles);
Note that the sense of the 'w' modifier is reversed for units;
a blank is added before the contents, rather than after it.
When the XOF_UNITS flag is set, units are rendered in XML as the
"units" attribute::
<distance units="miles">50</distance>
Units can also be rendered in HTML as the "data-units" attribute::
<div class="data" data-tag="distance" data-units="miles"
data-xpath="/top/data/distance">50</div>
.. index:: Field Roles; Value
.. _value-role:
The Value Role ({V:} and {:})
+++++++++++++++++++++++++++++
The value role is used to represent the a data value that is
interesting for the non-display output styles (XML and JSON). Value
is the default role; if no other role designation is given, the field
is a value. The field name must appear within the field descriptor,
followed by one or two format descriptors. The first format
descriptor is used for display styles (TEXT and HTML), while the
second one is used for encoding styles (XML and JSON). If no second
format is given, the encoding format defaults to the first format,
with any minimum width removed. If no first format is given, both
format descriptors default to "%s"::
xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\n",
length, width, height);
xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n,
author, poem, year);
.. index:: Field Roles; Anchor
.. _anchor-role:
The Anchor Roles ({[:} and {]:})
++++++++++++++++++++++++++++++++
The anchor roles allow a set of strings by be padded as a group,
but still be visible to xo_emit as distinct fields. Either the start
or stop anchor can give a field width and it can be either directly in
the descriptor or passed as an argument. Any fields between the start
and stop anchor are padded to meet the minimum width given.
To give a width directly, encode it as the content of the anchor tag::
xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\n", min, max);
To pass a width as an argument, use "%d" as the format, which must
appear after the "/". Note that only "%d" is supported for widths.
Using any other value could ruin your day::
xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\n", width, min, max);
If the width is negative, padding will be added on the right, suitable
for left justification. Otherwise the padding will be added to the
left of the fields between the start and stop anchors, suitable for
right justification. If the width is zero, nothing happens. If the
number of columns of output between the start and stop anchors is less
than the absolute value of the given width, nothing happens.
.. index:: XOF_WARN
Widths over 8k are considered probable errors and not supported. If
XOF_WARN is set, a warning will be generated.

View File

@ -0,0 +1,47 @@
.. index:: Format Strings
.. _format-strings:
Format Strings
--------------
libxo uses format strings to control the rendering of data into the
various output styles. Each format string contains a set of zero or
more field descriptions, which describe independent data fields. Each
field description contains a set of modifiers, a content string, and
zero, one, or two format descriptors. The modifiers tell libxo what
the field is and how to treat it, while the format descriptors are
formatting instructions using printf-style format strings, telling
libxo how to format the field. The field description is placed inside
a set of braces, with a colon (":") after the modifiers and a slash
("/") before each format descriptors. Text may be intermixed with
field descriptions within the format string.
The field description is given as follows::
'{' [ role | modifier ]* [',' long-names ]* ':' [ content ]
[ '/' field-format [ '/' encoding-format ]] '}'
The role describes the function of the field, while the modifiers
enable optional behaviors. The contents, field-format, and
encoding-format are used in varying ways, based on the role. These
are described in the following sections.
In the following example, three field descriptors appear. The first
is a padding field containing three spaces of padding, the second is a
label ("In stock"), and the third is a value field ("in-stock"). The
in-stock field has a "%u" format that will parse the next argument
passed to the xo_emit function as an unsigned integer::
xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 65);
This single line of code can generate text (" In stock: 65\n"), XML
("<in-stock>65</in-stock>"), JSON ('"in-stock": 6'), or HTML (too
lengthy to be listed here).
While roles and modifiers typically use single character for brevity,
there are alternative names for each which allow more verbose
formatting strings. These names must be preceded by a comma, and may
follow any single-character values::
xo_emit("{L,white,colon:In stock}{,key:in-stock/%u}\n", 65);

165
0.9.0/doc/formatting.rst Normal file
View File

@ -0,0 +1,165 @@
Formatting with libxo
=====================
Most unix commands emit text output aimed at humans. It is designed
to be parsed and understood by a user. Humans are gifted at
extracting details and pattern matching in such output. Often
programmers need to extract information from this human-oriented
output. Programmers use tools like grep, awk, and regular expressions
to ferret out the pieces of information they need. Such solutions are
fragile and require maintenance when output contents change or evolve,
along with testing and validation.
Modern tool developers favor encoding schemes like XML and JSON,
which allow trivial parsing and extraction of data. Such formats are
simple, well understood, hierarchical, easily parsed, and often
integrate easier with common tools and environments. Changes to
content can be done in ways that do not break existing users of the
data, which can reduce maintenance costs and increase feature velocity.
In addition, modern reality means that more output ends up in web
browsers than in terminals, making HTML output valuable.
libxo allows a single set of function calls in source code to generate
traditional text output, as well as XML and JSON formatted data. HTML
can also be generated; "<div>" elements surround the traditional text
output, with attributes that detail how to render the data.
A single libxo function call in source code is all that's required::
xo_emit("Connecting to {:host}.{:domain}...\n", host, domain);
TEXT:
Connecting to my-box.example.com...
XML:
<host>my-box</host>
<domain>example.com</domain>
JSON:
"host": "my-box",
"domain": "example.com"
HTML:
<div class="line">
<div class="text">Connecting to </div>
<div class="data" data-tag="host"
data-xpath="/top/host">my-box</div>
<div class="text">.</div>
<div class="data" data-tag="domain"
data-xpath="/top/domain">example.com</div>
<div class="text">...</div>
</div>
Encoding Styles
---------------
There are four encoding styles supported by libxo:
- TEXT output can be display on a terminal session, allowing
compatibility with traditional command line usage.
- XML output is suitable for tools like XPath and protocols like
NETCONF.
- JSON output can be used for RESTful APIs and integration with
languages like Javascript and Python.
- HTML can be matched with a small CSS file to permit rendering in any
HTML5 browser.
In general, XML and JSON are suitable for encoding data, while TEXT is
suited for terminal output and HTML is suited for display in a web
browser (see :ref:`xohtml`).
Text Output
~~~~~~~~~~~
Most traditional programs generate text output on standard output,
with contents like::
36 ./src
40 ./bin
90 .
In this example (taken from *du* source code), the code to generate this
data might look like::
printf("%d\t%s\n", num_blocks, path);
Simple, direct, obvious. But it's only making text output. Imagine
using a single code path to make TEXT, XML, JSON or HTML, deciding at
run time which to generate.
libxo expands on the idea of printf format strings to make a single
format containing instructions for creating multiple output styles::
xo_emit("{:blocks/%d}\t{:path/%s}\n", num_blocks, path);
This line will generate the same text output as the earlier printf
call, but also has enough information to generate XML, JSON, and HTML.
The following sections introduce the other formats.
XML Output
~~~~~~~~~~
XML output consists of a hierarchical set of elements, each encoded
with a start tag and an end tag. The element should be named for data
value that it is encoding::
<item>
<blocks>36</blocks>
<path>./src</path>
</item>
<item>
<blocks>40</blocks>
<path>./bin</path>
</item>
<item>
<blocks>90</blocks>
<path>.</path>
</item>
`XML`_ is the W3C standard for encoding data.
.. _XML: https://w3c.org/TR/xml
JSON Output
~~~~~~~~~~~
JSON output consists of a hierarchical set of objects and lists, each
encoded with a quoted name, a colon, and a value. If the value is a
string, it must be quoted, but numbers are not quoted. Objects are
encoded using braces; lists are encoded using square brackets.
Data inside objects and lists is separated using commas::
items: [
{ "blocks": 36, "path" : "./src" },
{ "blocks": 40, "path" : "./bin" },
{ "blocks": 90, "path" : "./" }
]
HTML Output
~~~~~~~~~~~
HTML output is designed to allow the output to be rendered in a web
browser with minimal effort. Each piece of output data is rendered
inside a <div> element, with a class name related to the role of the
data. By using a small set of class attribute values, a CSS
stylesheet can render the HTML into rich text that mirrors the
traditional text content.
Additional attributes can be enabled to provide more details about the
data, including data type, description, and an XPath location::
<div class="line">
<div class="data" data-tag="blocks">36</div>
<div class="padding"> </div>
<div class="data" data-tag="path">./src</div>
</div>
<div class="line">
<div class="data" data-tag="blocks">40</div>
<div class="padding"> </div>
<div class="data" data-tag="path">./bin</div>
</div>
<div class="line">
<div class="data" data-tag="blocks">90</div>
<div class="padding"> </div>
<div class="data" data-tag="path">./</div>
</div>

185
0.9.0/doc/getting.rst Normal file
View File

@ -0,0 +1,185 @@
.. index:: Getting libxo
Getting libxo
=============
libxo now ships as part of the FreeBSD Operating System (as of Release
11).
libxo source code lives on github:
https://github.com/Juniper/libxo
The latest release of libxo is available at:
https://github.com/Juniper/libxo/releases
We're using `Semantic Versioning`_ to number our releases. libxo is
open source, distributed under the BSD license. We follow the
branching scheme from `A Successful Git Branching Model`_:
we do development under the "*develop*" branch, and release from
the "*master*" branch. To clone a developer tree, run the following
command::
git clone https://github.com/Juniper/libxo.git -b develop
.. _Semantic Versioning: http://semver.org/spec/v2.0.0.html
.. _A Successful Git Branching Model:
http://nvie.com/posts/a-successful-git-branching-model
Issues, problems, and bugs should be directly to the issues page on
our github site.
Downloading libxo Source Code
-----------------------------
You can retrieve the source for libxo in two ways:
A. Use a "distfile" for a specific release. We use github to maintain
our releases. Visit the `release page`_ to see the list of
releases. To download the latest, look for the release witeh the
green "Latest release" button and the green "libxo-RELEASE.tar.gz"
button under that section.
.. _release page: https://github.com/Juniper/libxo/releases
After downloading that release's distfile, untar it as follows::
tar -zxf libxo-RELEASE.tar.gz
cd libxo-RELEASE
.. admonition:: Solaris Users
Note: for Solaris users, your "`tar`" command lacks the "-z" flag,
so you'll need to substitute "`gzip -dc $file | tar xf -`" instead
of "`tar -zxf $file`".
B. Use the current build from github. This gives you the most recent
source code, which might be less stable than a specific release. To
build libxo from the git repo::
git clone https://github.com/Juniper/libxo.git
cd libxo
.. admonition:: Be Aware
The github repository does **not** contain the files generated by
"*autoreconf*", with the notable exception of the "*m4*" directory.
Since these files (depcomp, configure, missing, install-sh, etc) are
generated files, we keep them out of the source code repository.
This means that if you download the a release distfile, these files
will be ready and you'll just need to run "configure", but if you
download the source code from svn, then you'll need to run
"*autoreconf*" by hand. This step is done for you by the "*setup.sh*"
script, described in the next section.
.. _building:
Building libxo
--------------
To build libxo, you'll need to set up the build, run the "*configure*"
script, run the "*make*" command, and run the regression tests.
The following is a summary of the commands needed. These commands are
explained in detail in the rest of this section::
sh bin/setup.sh
cd build
../configure
make
make test
sudo make install
The following sections will walk through each of these steps with
additional details and options, but the above directions should be all
that's needed.
Setting up the build
~~~~~~~~~~~~~~~~~~~~
.. admonition: Note
If you downloaded a distfile, you can skip this step.
Run the "*setup.sh*" script to set up the build. This script runs the
"*autoreconf*" command to generate the "*configure*" script and other
generated files::
sh bin/setup.sh
Note: We're are currently using autoreconf version 2.69.
Running the "configure" Script
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Configure (and autoconf in general) provides a means of building
software in diverse environments. Our configure script supports
a set of options that can be used to adjust to your operating
environment. Use "`configure --help`" to view these options.
We use the "*build*" directory to keep object files and generated files
away from the source tree.
To run the configure script, change into the "*build*" directory, and
run the "*configure*" script. Add any required options to the
"`../configure`" command line::
cd build
../configure
Expect to see the "*configure*" script generate the following error::
/usr/bin/rm: cannot remove `libtoolT': No such file or directory
This error is harmless and can be safely ignored.
By default, libxo installs architecture-independent files, including
extension library files, in the /usr/local directories. To specify an
installation prefix other than /usr/local for all installation files,
include the --prefix=prefix option and specify an alternate
location. To install just the extension library files in a different,
user-defined location, include the "*--with-extensions-dir=dir*" option
and specify the location where the extension libraries will live::
cd build
../configure [OPTION]... [VAR=VALUE]...
Running the "make" Command
++++++++++++++++++++++++++
Once the "*configure*" script is run, build the images using the
"`make`" command::
make
Running the Regression Tests
++++++++++++++++++++++++++++
libxo includes a set of regression tests that can be run to ensure
the software is working properly. These test are optional, but will
help determine if there are any issues running libxo on your
machine. To run the regression tests::
make test
Installing libxo
~~~~~~~~~~~~~~~~
Once the software is built, you'll need to install libxo using the
"`make install`" command. If you are the root user, or the owner of
the installation directory, simply issue the command::
make install
If you are not the "*root*" user and are using the "*sudo*" package, use::
sudo make install
Verify the installation by viewing the output of "`xo --version`"::
% xo --version
libxo version 0.3.5-git-develop
xo version 0.3.5-git-develop

394
0.9.0/doc/howto.rst Normal file
View File

@ -0,0 +1,394 @@
Howtos: Focused Directions
==========================
This section provides task-oriented instructions for selected tasks.
If you have a task that needs instructions, please open a request as
an enhancement issue on github.
Howto: Report bugs
------------------
libxo uses github to track bugs or request enhancements. Please use
the following URL:
https://github.com/Juniper/libxo/issues
Howto: Install libxo
--------------------
libxo is open source, under a new BSD license. Source code is
available on github, as are recent releases. To get the most
current release, please visit:
https://github.com/Juniper/libxo/releases
After downloading and untarring the source code, building involves the
following steps::
sh bin/setup.sh
cd build
../configure
make
make test
sudo make install
libxo uses a distinct "*build*" directory to keep generated files
separated from source files.
.. index:: configure
Use "`../configure --help`" to display available configuration
options, which include the following::
--enable-warnings Turn on compiler warnings
--enable-debug Turn on debugging
--enable-text-only Turn on text-only rendering
--enable-printflike Enable use of GCC __printflike attribute
--disable-libxo-options Turn off support for LIBXO_OPTIONS
--with-gettext=PFX Specify location of gettext installation
--with-libslax-prefix=PFX Specify location of libslax config
Compiler warnings are a very good thing, but recent compiler version
have added some very pedantic checks. While every attempt is made to
keep libxo code warning-free, warnings are now optional. If you are
doing development work on libxo, it is required that you
use --enable-warnings to keep the code warning free, but most users
need not use this option.
.. index:: --enable-text-only
libxo provides the `--enable-text-only` option to reduce the
footprint of the library for smaller installations. XML, JSON, and
HTML rendering logic is removed.
.. index:: --with-gettext
The gettext library does not provide a simple means of learning its
location, but libxo will look for it in /usr and /opt/local. If
installed elsewhere, the installer will need to provide this
information using the "`--with-gettext=/dir/path`" option.
.. index:: libslax
libslax is not required by libxo; it contains the "oxtradoc" program
used to format documentation.
For additional information, see :ref:`building`.
Howto: Convert command line applications
----------------------------------------
Common question: How do I convert an existing command line application?
There are four basic steps for converting command line application to
use libxo::
- Setting up the context
- Converting printf calls
- Creating hierarchy
- Converting error functions
Setting up the context
~~~~~~~~~~~~~~~~~~~~~~
To use libxo, you'll need to include the "xo.h" header file in your
source code files::
#include <libxo/xo.h>
In your main() function, you'll need to call xo_parse_args to handling
argument parsing (:ref:`xo_parse_args`). This function removes
libxo-specific arguments the program's argv and returns either the
number of remaining arguments or -1 to indicate an error::
int
main (int argc, char **argv)
{
argc = xo_parse_args(argc, argv);
if (argc < 0)
return argc;
....
}
.. index:: atexit
.. index:: xo_finish_atexit
At the bottom of your main(), you'll need to call xo_finish() to
complete output processing for the default handle (:ref:`handles`). This
is required to flush internal information buffers. libxo provides the
xo_finish_atexit function that is suitable for use with the
:manpage:`atexit(3)` function::
atexit(xo_finish_atexit);
Converting printf Calls
~~~~~~~~~~~~~~~~~~~~~~~
The second task is inspecting code for :manpage:`printf(3)` calls and
replacing them with xo_emit() calls. The format strings are similar
in task, but libxo format strings wrap output fields in braces. The
following two calls produce identical text output::
OLD::
printf("There are %d %s events\n", count, etype);
NEW::
xo_emit("There are {:count/%d} {:event} events\n", count, etype);
"count" and "event" are used as names for JSON and XML output. The
"count" field uses the format "%d" and "event" uses the default "%s"
format. Both are "value" roles, which is the default role.
Since text outside of output fields is passed verbatim, other roles
are less important, but their proper use can help make output more
useful. The "note" and "label" roles allow HTML output to recognize
the relationship between text and the associated values, allowing
appropriate "hover" and "onclick" behavior. Using the "units" role
allows the presentation layer to perform conversions when needed. The
"warning" and "error" roles allows use of color and font to draw
attention to warnings. The "padding" role makes the use of vital
whitespace more clear (:ref:`padding-role`).
The "*title*" role indicates the headings of table and sections. This
allows HTML output to use CSS to make this relationship more obvious::
OLD::
printf("Statistics:\n");
NEW::
xo_emit("{T:Statistics}:\n");
The "*color*" roles controls foreground and background colors, as well
as effects like bold and underline (see :ref:`color-role`)::
NEW::
xo_emit("{C:bold}required{C:}\n");
Finally, the start- and stop-anchor roles allow justification and
padding over multiple fields (see :ref:`anchor-role`)::
OLD::
snprintf(buf, sizeof(buf), "(%u/%u/%u)", min, ave, max);
printf("%30s", buf);
NEW::
xo_emit("{[:30}({:minimum/%u}/{:average/%u}/{:maximum/%u}{]:}",
min, ave, max);
Creating Hierarchy
~~~~~~~~~~~~~~~~~~
Text output doesn't have any sort of hierarchy, but XML and JSON
require this. Typically applications use indentation to represent
these relationship::
OLD::
printf("table %d\n", tnum);
for (i = 0; i < tmax; i++) {
printf(" %s %d\n", table[i].name, table[i].size);
}
NEW::
xo_emit("{T:/table %d}\n", tnum);
xo_open_list("table");
for (i = 0; i < tmax; i++) {
xo_open_instance("table");
xo_emit("{P: }{k:name} {:size/%d}\n",
table[i].name, table[i].size);
xo_close_instance("table");
}
xo_close_list("table");
The open and close list functions are used before and after the list,
and the open and close instance functions are used before and after
each instance with in the list.
Typically these developer looks for a "for" loop as an indication of
where to put these calls.
In addition, the open and close container functions allow for
organization levels of hierarchy::
OLD::
printf("Paging information:\n");
printf(" Free: %lu\n", free);
printf(" Active: %lu\n", active);
printf(" Inactive: %lu\n", inactive);
NEW::
xo_open_container("paging-information");
xo_emit("{P: }{L:Free: }{:free/%lu}\n", free);
xo_emit("{P: }{L:Active: }{:active/%lu}\n", active);
xo_emit("{P: }{L:Inactive: }{:inactive/%lu}\n", inactive);
xo_close_container("paging-information");
Converting Error Functions
~~~~~~~~~~~~~~~~~~~~~~~~~~
libxo provides variants of the standard error and warning functions,
:manpage:`err(3)` and :manpage:`warn(3)`. There are two variants, one
for putting the errors on standard error, and the other writes the
errors and warnings to the handle using the appropriate encoding
style::
OLD::
err(1, "cannot open output file: %s", file);
NEW::
xo_err(1, "cannot open output file: %s", file);
xo_emit_err(1, "cannot open output file: {:filename}", file);
.. index:: xo_finish
Call xo_finish
~~~~~~~~~~~~~~
One important item: call `xo_finish` at the end of your program so
ensure that all buffered data is written out. You can call it
explicitly call it, or use :manpage:`atexit(3)` to have
`xo_finish_atexit` called implicitly on exit::
OLD::
exit(0);
NEW::
xo_finish();
exit(0);
Howto: Use "xo" in Shell Scripts
--------------------------------
.. admonition:: Needed
Documentation is needed for this area.
.. index:: Internationalization (i18n)
.. index:: gettext
.. index:: xopo
.. _i18n:
Howto: Internationalization (i18n)
-----------------------------------------------
How do I use libxo to support internationalization?
libxo allows format and field strings to be used a keys into message
catalogs to enable translation into a user's native language by
invoking the standard :manpage:`gettext(3)` functions.
gettext setup is a bit complicated: text strings are extracted from
source files into "*portable object template*" (.pot) files using the
`xgettext` command. For each language, this template file is used as
the source for a message catalog in the "*portable object*" (.po)
format, which are translated by hand and compiled into "*machine
object*" (.mo) files using the `msgfmt` command. The .mo files are
then typically installed in the /usr/share/locale or
/opt/local/share/locale directories. At run time, the user's language
settings are used to select a .mo file which is searched for matching
messages. Text strings in the source code are used as keys to look up
the native language strings in the .mo file.
Since the xo_emit format string is used as the key into the message
catalog, libxo removes unimportant field formatting and modifiers from
the format string before use so that minor formatting changes will not
impact the expensive translation process. We don't want a developer
change such as changing "/%06d" to "/%08d" to force hand inspection of
all .po files. The simplified version can be generated for a single
message using the `xopo -s $text` command, or an entire .pot can be
translated using the `xopo -f $input -o $output` command::
EXAMPLE:
% xopo -s "There are {:count/%u} {:event/%.6s} events\n"
There are {:count} {:event} events\n
Recommended workflow:
# Extract text messages
xgettext --default-domain=foo --no-wrap \
--add-comments --keyword=xo_emit --keyword=xo_emit_h \
--keyword=xo_emit_warn -C -E -n --foreign-user \
-o foo.pot.raw foo.c
# Simplify format strings for libxo
xopo -f foo.pot.raw -o foo.pot
# For a new language, just copy the file
cp foo.pot po/LC/my_lang/foo.po
# For an existing language:
msgmerge --no-wrap po/LC/my_lang/foo.po \
foo.pot -o po/LC/my_lang/foo.po.new
# Now the hard part: translate foo.po using tools
# like poedit or emacs' po-mode
# Compile the finished file; Use of msgfmt's "-v" option is
# strongly encouraged, so that "fuzzy" entries are reported.
msgfmt -v -o po/my_lang/LC_MESSAGES/foo.mo po/my_lang/foo.po
# Install the .mo file
sudo cp po/my_lang/LC_MESSAGES/foo.mo \
/opt/local/share/locale/my_lang/LC_MESSAGE/
Once these steps are complete, you can use the `gettext` command to
test the message catalog::
gettext -d foo -e "some text"
i18n and xo_emit
~~~~~~~~~~~~~~~~
There are three features used in libxo used to support i18n:
- The "{G:}" role looks for a translation of the format string.
- The "{g:}" modifier looks for a translation of the field.
- The "{p:}" modifier looks for a pluralized version of the field.
Together these three flags allows a single function call to give
native language support, as well as libxo's normal XML, JSON, and HTML
support::
printf(gettext("Received %zu %s from {g:server} server\n"),
counter, ngettext("byte", "bytes", counter),
gettext("web"));
xo_emit("{G:}Received {:received/%zu} {Ngp:byte,bytes} "
"from {g:server} server\n", counter, "web");
libxo will see the "{G:}" role and will first simplify the format
string, removing field formats and modifiers::
"Received {:received} {N:byte,bytes} from {:server} server\n"
libxo calls :manpage:`gettext(3)` with that string to get a localized
version. If your language were *Pig Latin*, the result might look
like::
"Eceivedray {:received} {N:byte,bytes} omfray "
"{:server} erversay\n"
Note the field names do not change and they should not be translated.
The contents of the note ("byte,bytes") should also not be translated,
since the "g" modifier will need the untranslated value as the key for
the message catalog.
The field "{g:server}" requests the rendered value of the field be
translated using :manpage:`gettext(3)`. In this example, "web" would
be used.
The field "{Ngp:byte,bytes}" shows an example of plural form using the
"{p:}" modifier with the "{g:}" modifier. The base singular and plural
forms appear inside the field, separated by a comma. At run time,
libxo uses the previous field's numeric value to decide which form to
use by calling :manpage:`ngettext(3)`.
If a domain name is needed, it can be supplied as the content of the
{G:} role. Domain names remain in use throughout the format string
until cleared with another domain name::
printf(dgettext("dns", "Host %s not found: %d(%s)\n"),
name, errno, dgettext("strerror", strerror(errno)));
xo_emit("{G:dns}Host {:hostname} not found: "
"%d({G:strerror}{g:%m})\n", name, errno);

53
0.9.0/doc/index.rst Normal file
View File

@ -0,0 +1,53 @@
.. #
# Copyright (c) 2014, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
# Phil Shafer, July 2014
#
.. default-role:: code
libxo - A Library for Generating Text, XML, JSON, and HTML Output
===================================================================
The libxo library allows an application to generate text, XML, JSON,
and HTML output, suitable for both command line use and for web
applications. The application decides at run time which output style
should be produced. By using libxo, a single source code path can
emit multiple styles of output using command line options to select
the style, along with optional behaviors. libxo includes support for
multiple output streams, pluralization, color, syslog,
:manpage:`humanized(3)` output, internationalization, and UTF-8. The
library aims to minimize the cost of migrating code to libxo.
libxo ships as part of FreeBSD.
.. toctree::
:maxdepth: 3
:caption: Documentation Contents:
intro
getting
formatting
options
format-strings
field-roles
field-modifiers
field-formatting
api
xo
xolint
xohtml
xopo
faq
howto
example
Indices and tables
==================
* :ref:`genindex`
* :ref:`search`

90
0.9.0/doc/intro.rst Normal file
View File

@ -0,0 +1,90 @@
Introducing libxo
=================
The libxo library allows an application to generate text, XML, JSON,
and HTML output using a common set of function calls. The application
decides at run time which output style should be produced. The
application calls a function "xo_emit" to product output that is
described in a format string. A "field descriptor" tells libxo what
the field is and what it means. Each field descriptor is placed in
braces with printf-like :ref:`format-strings`::
xo_emit(" {:lines/%7ju} {:words/%7ju} "
"{:characters/%7ju} {d:filename/%s}\n",
linect, wordct, charct, file);
Each field can have a role, with the 'value' role being the default,
and the role tells libxo how and when to render that field (see
:ref:`field-roles` for details). Modifiers change how the field is
rendered in different output styles (see :ref:`field-modifiers` for
details. Output can then be generated in various style, using the
"--libxo" option::
% wc /etc/motd
25 165 1140 /etc/motd
% wc --libxo xml,pretty,warn /etc/motd
<wc>
<file>
<lines>25</lines>
<words>165</words>
<characters>1140</characters>
<filename>/etc/motd</filename>
</file>
</wc>
% wc --libxo json,pretty,warn /etc/motd
{
"wc": {
"file": [
{
"lines": 25,
"words": 165,
"characters": 1140,
"filename": "/etc/motd"
}
]
}
}
% wc --libxo html,pretty,warn /etc/motd
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines"> 25</div>
<div class="text"> </div>
<div class="data" data-tag="words"> 165</div>
<div class="text"> </div>
<div class="data" data-tag="characters"> 1140</div>
<div class="text"> </div>
<div class="data" data-tag="filename">/etc/motd</div>
</div>
Same code path, same format strings, same information, but it's
rendered in distinct styles based on run-time flags.
.. admonition:: Tale of Two Code Paths
You want to prepare for the future, but you need to live in the
present. You'd love a flying car, but need to get work done today.
You want to support features like XML, JSON, and HTML rendering to
allow integration with NETCONF, REST, and web browsers, but you need
to make text output for command line users.
And you don't want multiple code paths that can't help but get out
of sync::
/* None of this "if (xml) {... } else {...}" logic */
if (xml) {
/* some code to make xml */
} else {
/* other code to make text */
/* oops! forgot to add something on both clauses! */
}
/* And ifdefs are right out. */
#ifdef MAKE_XML
/* icky */
#else
/* pooh */
#endif
But you'd really, really like all the fancy features that modern
encoding formats can provide. libxo can help.

27436
0.9.0/doc/libxo-manual.html Normal file

File diff suppressed because it is too large Load Diff

3995
0.9.0/doc/libxo.txt Normal file

File diff suppressed because it is too large Load Diff

164
0.9.0/doc/options.rst Normal file
View File

@ -0,0 +1,164 @@
.. index:: --libxo
.. index:: Options
.. _options:
Command-line Arguments
======================
libxo uses command line options to trigger rendering behavior. There
are multiple conventions for passing options, all using the
"`--libxo`" option::
--libxo <options>
--libxo=<options>
--libxo:<brief-options>
The *brief-options* is a series of single letter abbrevations, where
the *options* is a comma-separated list of words. Both provide access
to identical functionality. The following invocations are all
identical in outcome::
my-app --libxo warn,pretty arg1
my-app --libxo=warn,pretty arg1
my-app --libxo:WP arg1
Programs using libxo are expecting to call the xo_parse_args function
to parse these arguments. See :ref:`xo_parse_args` for details.
Option Keywords
---------------
Options is a comma-separated list of tokens that correspond to output
styles, flags, or features:
=============== =======================================================
Token Action
=============== =======================================================
color Enable colors/effects for display styles (TEXT, HTML)
colors=xxxx Adjust color output values
dtrt Enable "Do The Right Thing" mode
flush Flush after every libxo function call
flush-line Flush after every line (line-buffered)
html Emit HTML output
indent=xx Set the indentation level
info Add info attributes (HTML)
json Emit JSON output
keys Emit the key attribute for keys (XML)
log-gettext Log (via stderr) each gettext(3) string lookup
log-syslog Log (via stderr) each syslog message (via xo_syslog)
no-humanize Ignore the {h:} modifier (TEXT, HTML)
no-locale Do not initialize the locale setting
no-retain Prevent retaining formatting information
no-top Do not emit a top set of braces (JSON)
not-first Pretend the 1st output item was not 1st (JSON)
pretty Emit pretty-printed output
retain Force retaining formatting information
text Emit TEXT output
underscores Replace XML-friendly "-"s with JSON friendly "_"s
units Add the 'units' (XML) or 'data-units (HTML) attribute
warn Emit warnings when libxo detects bad calls
warn-xml Emit warnings in XML
xml Emit XML output
xpath Add XPath expressions (HTML)
=============== =======================================================
Most of these option are simple and direct, but some require
additional details:
- "colors" is described in :ref:`color-mapping`.
- "flush-line" performs line buffering, even when the output is not
directed to a TTY device.
- "info" generates additional data for HTML, encoded in attributes
using names that state with "data-".
- "keys" adds a "key" attribute for XML output to indicate that a leaf
is an identifier for the list member.
- "no-humanize" avoids "humanizing" numeric output (see
:ref:`humanize-modifier` for details).
- "no-locale" instructs libxo to avoid translating output to the
current locale.
- "no-retain" disables the ability of libxo to internally retain
"compiled" information about formatting strings (see :ref:`retain`
for details).
- "underscores" can be used with JSON output to change XML-friendly
names with dashes into JSON-friendly name with underscores.
- "warn" allows libxo to emit warnings on stderr when application code
make incorrect calls.
- "warn-xml" causes those warnings to be placed in XML inside the
output.
Brief Options
-------------
The brief options are simple single-letter aliases to the normal
keywords, as detailed below:
======== =============================================
Option Action
======== =============================================
c Enable color/effects for TEXT/HTML
F Force line-buffered flushing
H Enable HTML output (XO_STYLE_HTML)
I Enable info output (XOF_INFO)
i<num> Indent by <number>
J Enable JSON output (XO_STYLE_JSON)
k Add keys to XPATH expressions in HTML
n Disable humanization (TEXT, HTML)
P Enable pretty-printed output (XOF_PRETTY)
T Enable text output (XO_STYLE_TEXT)
U Add units to HTML output
u Change "-"s to "_"s in element names (JSON)
W Enable warnings (XOF_WARN)
X Enable XML output (XO_STYLE_XML)
x Enable XPath data (XOF_XPATH)
======== =============================================
.. index:: Colors
.. _color-mapping:
Color Mapping
-------------
The "colors" option takes a value that is a set of mappings from the
pre-defined set of colors to new foreground and background colors.
The value is a series of "fg/bg" values, separated by a "+". Each
pair of "fg/bg" values gives the colors to which a basic color is
mapped when used as a foreground or background color. The order is
the mappings is:
- black
- red
- green
- yellow
- blue
- magenta
- cyan
- white
Pairs may be skipped, leaving them mapped as normal, as are missing
pairs or single colors.
For example consider the following xo_emit call::
xo_emit("{C:fg-red,bg-green}Merry XMas!!{C:}\n");
To turn all colored output to red-on-blue, use eight pairs of
"red/blue" mappings separated by "+"s::
--libxo colors=red/blue+red/blue+red/blue+red/blue+\
red/blue+red/blue+red/blue+red/blue
To turn the red-on-green text to magenta-on-cyan, give a "magenta"
foreground value for red (the second mapping) and a "cyan" background
to green (the third mapping)::
--libxo colors=+magenta+/cyan
Consider the common situation where blue output looks unreadable on a
terminal session with a black background. To turn both "blue"
foreground and background output to "yellow", give only the fifth
mapping, skipping the first four mappings with bare "+"s::
--libxo colors=++++yellow/yellow

125
0.9.0/doc/xo.rst Normal file
View File

@ -0,0 +1,125 @@
.. index:: --libxo, xo
The "xo" Utility
================
The `xo` utility allows command line access to the functionality of
the libxo library. Using `xo`, shell scripts can emit XML, JSON, and
HTML using the same commands that emit text output.
The style of output can be selected using a specific option: "-X" for
XML, "-J" for JSON, "-H" for HTML, or "-T" for TEXT, which is the
default. The "--style <style>" option can also be used. The standard
set of "--libxo" options are available (see :ref:`options`), as well
as the `LIBXO_OPTIONS`_ environment variable.
.. _`LIBXO_OPTIONS`: :ref:`libxo-options`
The `xo` utility accepts a format string suitable for `xo_emit` and
a set of zero or more arguments used to supply data for that string::
xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6
TEXT:
The fish weighs 6 pounds.
XML:
<name>fish</name>
<weight>6</weight>
JSON:
"name": "fish",
"weight": 6
HTML:
<div class="line">
<div class="text">The </div>
<div class="data" data-tag="name">fish</div>
<div class="text"> weighs </div>
<div class="data" data-tag="weight">6</div>
<div class="text"> pounds.</div>
</div>
The `--wrap $path` option can be used to wrap emitted content in a
specific hierarchy. The path is a set of hierarchical names separated
by the '/' character::
xo --wrap top/a/b/c '{:tag}' value
XML:
<top>
<a>
<b>
<c>
<tag>value</tag>
</c>
</b>
</a>
</top>
JSON:
"top": {
"a": {
"b": {
"c": {
"tag": "value"
}
}
}
}
The `--open $path` and `--close $path` can be used to emit
hierarchical information without the matching close and open
tag. This allows a shell script to emit open tags, data, and
then close tags. The `--depth` option may be used to set the
depth for indentation. The `--leading-xpath` may be used to
prepend data to the XPath values used for HTML output style::
EXAMPLE;
#!/bin/sh
xo --open top/data
xo --depth 2 '{tag}' value
xo --close top/data
XML:
<top>
<data>
<tag>value</tag>
</data>
</top>
JSON:
"top": {
"data": {
"tag": "value"
}
}
Command Line Options
--------------------
::
Usage: xo [options] format [fields]
--close <path> Close tags for the given path
--depth <num> Set the depth for pretty printing
--help Display this help text
--html OR -H Generate HTML output
--json OR -J Generate JSON output
--leading-xpath <path> Add a prefix to generated XPaths (HTML)
--open <path> Open tags for the given path
--pretty OR -p Make 'pretty' output (add indent, newlines)
--style <style> Generate given style (xml, json, text, html)
--text OR -T Generate text output (the default style)
--version Display version information
--warn OR -W Display warnings in text on stderr
--warn-xml Display warnings in xml on stdout
--wrap <path> Wrap output in a set of containers
--xml OR -X Generate XML output
--xpath Add XPath data to HTML output);
Example
-------
::
% xo 'The {:product} is {:status}\n' stereo "in route"
The stereo is in route
% ./xo/xo -p -X 'The {:product} is {:status}\n' stereo "in route"
<product>stereo</product>
<status>in route</status>

30
0.9.0/doc/xohtml.rst Normal file
View File

@ -0,0 +1,30 @@
.. index:: xohtml
.. _xohtml:
xohtml
======
`xohtml` is a tool for turning the output of libxo-enabled commands into
html files suitable for display in modern HTML web browsers. It can
be used to test and debug HTML output, as well as to make the user
ache to escape the world of '70s terminal devices.
`xohtml` is given a command, either on the command line or via the "-c"
option. If not command is given, standard input is used. The
command's output is wrapped in HTML tags, with references to
supporting CSS and Javascript files, and written to standard output or
the file given in the "-f" option. The "-b" option can be used to
provide an alternative base path for the support files:
============== ===================================================
Option Meaning
============== ===================================================
-b <base> Base path for finding css/javascript files
-c <command> Command to execute
-f <file> Output file name
============== ===================================================
The "-c" option takes a full command with arguments, including
any libxo options needed to generate html (`--libxo=html`). This
value must be quoted if it consists of multiple tokens.

40
0.9.0/doc/xolint.rst Normal file
View File

@ -0,0 +1,40 @@
xolint
======
`xolint` is a tool for reporting common mistakes in format strings
in source code that invokes `xo_emit`. It allows these errors
to be diagnosed at build time, rather than waiting until runtime.
`xolint` takes the one or more C files as arguments, and reports
and errors, warning, or informational messages as needed:
============ ===================================================
Option Meaning
============ ===================================================
-c Invoke 'cpp' against the input file
-C <flags> Flags that are passed to 'cpp
-d Enable debug output
-D Generate documentation for all xolint messages
-I Generate info table code
-p Print the offending lines after the message
-V Print vocabulary of all field names
-X Extract samples from xolint, suitable for testing
============ ===================================================
The output message will contain the source filename and line number, the
class of the message, the message, and, if -p is given, the
line that contains the error::
% xolint.pl -t xolint.c
xolint.c: 16: error: anchor format should be "%d"
16 xo_emit("{[:/%s}");
The "-I" option will generate a table of `xo_info_t`_ structures,
suitable for inclusion in source code.
.. _xo_info_t: :ref:`field-information`
The "-V" option does not report errors, but prints a complete list of
all field names, sorted alphabetically. The output can help spot
inconsistencies and spelling errors.

45
0.9.0/doc/xopo.rst Normal file
View File

@ -0,0 +1,45 @@
xopo
====
The `xopo` utility filters ".pot" files generated by the
:manpage:`xgettext(1)` utility to remove formatting information
suitable for use with the "{G:}" modifier. This means that when the
developer changes the formatting portion of the field definitions, or
the fields modifiers, the string passed to :manpage:`gettext(3)` is
unchanged, avoiding the expense of updating any existing translation
files (".po" files).
The syntax for the xopo command is one of two forms; it can be used as
a filter for processing a .po or .pot file, rewriting the "*msgid*"
strings with a simplified message string. In this mode, the input is
either standard input or a file given by the "-f" option, and the
output is either standard output or a file given by the "-o" option.
In the second mode, a simple message given using the "-s" option on
the command, and the simplified version of that message is printed on
stdout:
=========== =================================
Option Meaning
=========== =================================
-o <file> Output file name
-f <file> Use the given .po file as input
-s <text> Simplify a format string
=========== =================================
::
EXAMPLE:
% xopo -s "There are {:count/%u} {:event/%.6s} events\n"
There are {:count} {:event} events\n
% xgettext --default-domain=foo --no-wrap \
--add-comments --keyword=xo_emit --keyword=xo_emit_h \
--keyword=xo_emit_warn -C -E -n --foreign-user \
-o foo.pot.raw foo.c
% xopo -f foo.pot.raw -o foo.pot
Use of the `--no-wrap` option for `xgettext` is required to
ensure that incoming msgid strings are not wrapped across multiple
lines.

View File

@ -0,0 +1,9 @@
#
# Copyright 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.
SUBDIRS = cbor test

View File

@ -0,0 +1,51 @@
#
# $Id$
#
# Copyright 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.
if LIBXO_WARNINGS_HIGH
LIBXO_WARNINGS = HIGH
endif
if HAVE_GCC
GCC_WARNINGS = yes
endif
include ${top_srcdir}/warnings.mk
enc_cborincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir}/libxo \
-I${top_builddir}/libxo \
${WARNINGS}
LIBNAME = libenc_cbor
pkglib_LTLIBRARIES = libenc_cbor.la
LIBS = \
-L${top_builddir}/libxo -lxo
LDADD = ${top_builddir}/libxo/libxo.la
libenc_cbor_la_SOURCES = \
enc_cbor.c
pkglibdir = ${XO_ENCODERDIR}
UGLY_NAME = cbor.enc
install-exec-hook:
@DLNAME=`sh -c '. ./libenc_cbor.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,365 @@
/*
* 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
*/
/*
* CBOR (RFC 7049) mades a suitable test case for libxo's external
* encoder API. It's simple, streaming, well documented, and an
* IETF standard.
*
* This encoder uses the "pretty" flag for diagnostics, which isn't
* really kosher, but it's example code.
*/
#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"
/*
* memdump(): dump memory contents in hex/ascii
0 1 2 3 4 5 6 7
0123456789012345678901234567890123456789012345678901234567890123456789012345
XX XX XX XX XX XX XX XX - XX XX XX XX XX XX XX XX abcdefghijklmnop
*/
static void
cbor_memdump (FILE *fp, const char *title, const char *data,
size_t len, const char *tag, int indent)
{
enum { MAX_PER_LINE = 16 };
char buf[ 80 ];
char text[ 80 ];
char *bp, *tp;
size_t i;
#if 0
static const int ends[ MAX_PER_LINE ] = { 2, 5, 8, 11, 15, 18, 21, 24,
29, 32, 35, 38, 42, 45, 48, 51 };
#endif
if (fp == NULL)
fp = stdout;
if (tag == NULL)
tag = "";
fprintf(fp, "%*s[%s] @ %p (%lx/%lu)\n", indent + 1, tag,
title, data, (unsigned long) len, (unsigned long) len);
while (len > 0) {
bp = buf;
tp = text;
for (i = 0; i < MAX_PER_LINE && i < len; i++) {
if (i && (i % 4) == 0) *bp++ = ' ';
if (i == 8) {
*bp++ = '-';
*bp++ = ' ';
}
sprintf(bp, "%02x ", (unsigned char) *data);
bp += strlen(bp);
*tp++ = (isprint((int) *data) && *data >= ' ') ? *data : '.';
data += 1;
}
*tp = 0;
*bp = 0;
fprintf(fp, "%*s%-54s%s\n", indent + 1, tag, buf, text);
len -= i;
}
}
/*
* CBOR breaks the first byte into two pieces, the major type in the
* top 3 bits and the minor value in the low 5 bits. The value can be
* a small value (0 .. 23), an 8-bit value (24), a 16-bit value (25),
* a 32-bit value (26), or a 64-bit value (27). A value of 31
* represents an unknown length, which we'll use extensively for
* streaming our content.
*/
#define CBOR_MAJOR_MASK 0xE0
#define CBOR_MINOR_MASK 0x1F
#define CBOR_MAJOR_SHIFT 5
#define CBOR_MAJOR(_x) ((_x) & CBOR_MAJOR_MASK)
#define CBOR_MAJOR_VAL(_x) ((_x) << CBOR_MAJOR_SHIFT)
#define CBOR_MINOR_VAL(_x) ((_x) & CBOR_MINOR_MASK)
/* Major type codes */
#define CBOR_UNSIGNED CBOR_MAJOR_VAL(0) /* 0x00 */
#define CBOR_NEGATIVE CBOR_MAJOR_VAL(1) /* 0x20 */
#define CBOR_BYTES CBOR_MAJOR_VAL(2) /* 0x40 */
#define CBOR_STRING CBOR_MAJOR_VAL(3) /* 0x60 */
#define CBOR_ARRAY CBOR_MAJOR_VAL(4) /* 0x80 */
#define CBOR_MAP CBOR_MAJOR_VAL(5) /* 0xa0 */
#define CBOR_SEMANTIC CBOR_MAJOR_VAL(6) /* 0xc0 */
#define CBOR_SPECIAL CBOR_MAJOR_VAL(7) /* 0xe0 */
#define CBOR_ULIMIT 24 /* Largest unsigned value */
#define CBOR_NLIMIT 23 /* Largest negative value */
#define CBOR_BREAK 0xFF
#define CBOR_INDEF 0x1F
#define CBOR_FALSE 0xF4
#define CBOR_TRUE 0xF5
#define CBOR_NULL 0xF6
#define CBOR_UNDEF 0xF7
#define CBOR_LEN8 0x18 /* 24 - 8-bit value */
#define CBOR_LEN16 0x19 /* 25 - 16-bit value */
#define CBOR_LEN32 0x1a /* 26 - 32-bit value */
#define CBOR_LEN64 0x1b /* 27 - 64-bit value */
#define CBOR_LEN128 0x1c /* 28 - 128-bit value */
typedef struct cbor_private_s {
xo_buffer_t c_data; /* Our data buffer */
unsigned c_indent; /* Indent level */
unsigned c_open_leaf_list; /* Open leaf list construct? */
} cbor_private_t;
static void
cbor_encode_uint (xo_buffer_t *xbp, uint64_t minor, unsigned limit)
{
char *bp = xbp->xb_curp;
int i, m;
if (minor > (1ULL << 32)) {
*bp++ |= CBOR_LEN64;
m = 64;
} else if (minor > (1<<16)) {
*bp++ |= CBOR_LEN32;
m = 32;
} else if (minor > (1<<8)) {
*bp++ |= CBOR_LEN16;
m = 16;
} else if (minor > limit) {
*bp++ |= CBOR_LEN8;
m = 8;
} else {
*bp++ |= minor & CBOR_MINOR_MASK;
m = 0;
}
if (m) {
for (i = m - 8; i >= 0; i -= 8)
*bp++ = minor >> i;
}
xbp->xb_curp = bp;
}
static void
cbor_append (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp,
unsigned major, unsigned minor, const char *data)
{
if (!xo_buf_has_room(xbp, minor + 2))
return;
unsigned offset = xo_buf_offset(xbp);
*xbp->xb_curp = major;
cbor_encode_uint(xbp, minor, CBOR_ULIMIT);
if (data)
xo_buf_append(xbp, data, minor);
if (xo_get_flags(xop) & XOF_PRETTY)
cbor_memdump(stdout, "append", xo_buf_data(xbp, offset),
xbp->xb_curp - xbp->xb_bufp - offset, "",
cbor->c_indent * 2);
}
static int
cbor_create (xo_handle_t *xop)
{
cbor_private_t *cbor = xo_realloc(NULL, sizeof(*cbor));
if (cbor == NULL)
return -1;
bzero(cbor, sizeof(*cbor));
xo_buf_init(&cbor->c_data);
xo_set_private(xop, cbor);
cbor_append(xop, cbor, &cbor->c_data, CBOR_MAP | CBOR_INDEF, 0, NULL);
return 0;
}
static int
cbor_content (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp,
const char *value)
{
int rc = 0;
unsigned offset = xo_buf_offset(xbp);
if (value == NULL || *value == '\0' || strcmp(value, "true") == 0)
cbor_append(xop, cbor, &cbor->c_data, CBOR_TRUE, 0, NULL);
else if (strcmp(value, "false") == 0)
cbor_append(xop, cbor, &cbor->c_data, CBOR_FALSE, 0, NULL);
else {
int negative = 0;
if (*value == '-') {
value += 1;
negative = 1;
}
char *ep;
unsigned long long ival;
ival = strtoull(value, &ep, 0);
if (ival == ULLONG_MAX) /* Sometimes a string is just a string */
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(value), value);
else {
*xbp->xb_curp = negative ? CBOR_NEGATIVE : CBOR_UNSIGNED;
if (negative)
ival -= 1; /* Don't waste a negative zero */
cbor_encode_uint(xbp, ival, negative ? CBOR_NLIMIT : CBOR_ULIMIT);
}
}
if (xo_get_flags(xop) & XOF_PRETTY)
cbor_memdump(stdout, "content", xo_buf_data(xbp, offset),
xbp->xb_curp - xbp->xb_bufp - offset, "",
cbor->c_indent * 2);
return rc;
}
static int
cbor_handler (XO_ENCODER_HANDLER_ARGS)
{
int rc = 0;
cbor_private_t *cbor = private;
xo_buffer_t *xbp = cbor ? &cbor->c_data : NULL;
if (xo_get_flags(xop) & XOF_PRETTY) {
printf("%*sop %s: [%s] [%s]\n", cbor ? cbor->c_indent * 2 + 4 : 0, "",
xo_encoder_op_name(op), name, value);
fflush(stdout);
}
/* If we don't have private data, we're sunk */
if (cbor == NULL && op != XO_OP_CREATE)
return -1;
switch (op) {
case XO_OP_CREATE: /* Called when the handle is init'd */
rc = cbor_create(xop);
break;
case XO_OP_OPEN_CONTAINER:
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
cbor_append(xop, cbor, xbp, CBOR_MAP | CBOR_INDEF, 0, NULL);
cbor->c_indent += 1;
break;
case XO_OP_CLOSE_CONTAINER:
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
cbor->c_indent -= 1;
break;
case XO_OP_OPEN_LIST:
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
cbor_append(xop, cbor, xbp, CBOR_ARRAY | CBOR_INDEF, 0, NULL);
cbor->c_indent += 1;
break;
case XO_OP_CLOSE_LIST:
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
cbor->c_indent -= 1;
break;
case XO_OP_OPEN_LEAF_LIST:
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
cbor_append(xop, cbor, xbp, CBOR_ARRAY | CBOR_INDEF, 0, NULL);
cbor->c_indent += 1;
cbor->c_open_leaf_list = 1;
break;
case XO_OP_CLOSE_LEAF_LIST:
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
cbor->c_indent -= 1;
cbor->c_open_leaf_list = 0;
break;
case XO_OP_OPEN_INSTANCE:
cbor_append(xop, cbor, xbp, CBOR_MAP | CBOR_INDEF, 0, NULL);
cbor->c_indent += 1;
break;
case XO_OP_CLOSE_INSTANCE:
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
cbor->c_indent -= 1;
break;
case XO_OP_STRING: /* Quoted UTF-8 string */
if (!cbor->c_open_leaf_list)
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(value), value);
break;
case XO_OP_CONTENT: /* Other content */
if (!cbor->c_open_leaf_list)
cbor_append(xop, cbor, xbp, CBOR_STRING, strlen(name), name);
/*
* It's content, not string, so we need to look at the
* string and build some content. Turns out we only
* care about true, false, null, and numbers.
*/
cbor_content(xop, cbor, xbp, value);
break;
case XO_OP_FINISH: /* Clean up function */
cbor_append(xop, cbor, xbp, CBOR_BREAK, 0, NULL);
cbor->c_indent -= 1;
break;
case XO_OP_FLUSH: /* Clean up function */
if (xo_get_flags(xop) & XOF_PRETTY)
cbor_memdump(stdout, "cbor",
xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp,
">", 0);
else {
rc = write(1, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp);
if (rc > 0)
rc = 0;
}
break;
case XO_OP_DESTROY: /* Clean up function */
break;
case XO_OP_ATTRIBUTE: /* Attribute name/value */
break;
case XO_OP_VERSION: /* Version string */
break;
}
return rc;
}
int
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
{
arg->xei_handler = cbor_handler;
return 0;
}

View File

@ -0,0 +1,51 @@
#
# $Id$
#
# Copyright 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.
if LIBXO_WARNINGS_HIGH
LIBXO_WARNINGS = HIGH
endif
if HAVE_GCC
GCC_WARNINGS = yes
endif
include ${top_srcdir}/warnings.mk
enc_testincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir}/libxo \
-I${top_builddir}/libxo \
${WARNINGS}
LIBNAME = libenc_test
pkglib_LTLIBRARIES = libenc_test.la
LIBS = \
-L${top_builddir}/libxo -lxo
LDADD = ${top_builddir}/libxo/libxo.la
libenc_test_la_SOURCES = \
enc_test.c
pkglibdir = ${XO_ENCODERDIR}
UGLY_NAME = test.enc
install-exec-hook:
@DLNAME=`sh -c '. ./libenc_test.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,30 @@
/*
* 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
*/
#include "xo.h"
#include "xo_encoder.h"
static int
test_handler (XO_ENCODER_HANDLER_ARGS)
{
printf("op %s: [%s] [%s] [%#llx]\n", xo_encoder_op_name(op),
name ?: "", value ?: "", flags);
return 0;
}
int
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
{
arg->xei_version = XO_ENCODER_VERSION;
arg->xei_handler = test_handler;
return 0;
}

119
0.9.0/libxo-config.in Normal file
View File

@ -0,0 +1,119 @@
#! /bin/sh
#
# $Id$
#
# Copyright 2011-2014, 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.
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
libdir=@libdir@
usage()
{
cat <<EOF
Usage: libxo-config [OPTION]
Known values for OPTION are:
--prefix=DIR change libxo prefix [default $prefix]
--exec-prefix=DIR change libxo exec prefix [default $exec_prefix]
--libs print library linking information
--bindir print the bin directory
--cflags print pre-processor and compiler flags
--share print share directory
--help display this help and exit
--version output version information
EOF
exit $1
}
if test $# -eq 0; then
usage 1
fi
cflags=false
libs=false
while test $# -gt 0; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case "$1" in
--prefix=*)
prefix=$optarg
includedir=$prefix/include
libdir=$prefix/lib
;;
--prefix)
echo $prefix
;;
--exec-prefix=*)
exec_prefix=$optarg
libdir=$exec_prefix/lib
;;
--exec-prefix)
echo $exec_prefix
;;
--version)
echo @VERSION@
exit 0
;;
--help)
usage 0
;;
--cflags)
echo -I@XO_INCLUDEDIR@ @XO_CFLAGS@
;;
--share)
echo @XO_SHAREDIR@
;;
--bindir)
echo @XO_BINDIR@
;;
--libdir)
echo @XO_LIBDIR@
;;
--libs)
if [ "`uname`" = "Linux" ]
then
if [ "@XO_LIBDIR@" = "-L/usr/lib" -o "@XO_LIBDIR@" = "-L/usr/lib64" ]
then
echo @XO_LIBS@
else
echo -L@XO_LIBDIR@ @XO_LIBS@
fi
else
echo -L@XO_LIBDIR@ @XO_LIBS@
fi
;;
*)
usage
exit 1
;;
esac
shift
done
exit 0

94
0.9.0/libxo/Makefile.am Normal file
View File

@ -0,0 +1,94 @@
#
# Copyright 2014, 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
libxoincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir} \
${WARNINGS} \
${GETTEXT_CFLAGS}
AM_CFLAGS += \
-DXO_ENCODERDIR=\"${XO_ENCODERDIR}\"
lib_LTLIBRARIES = libxo.la
LIBS = \
${GETTEXT_LIBS}
libxoinc_HEADERS = \
xo.h \
xo_encoder.h
noinst_HEADERS = \
xo_buf.h \
xo_humanize.h \
xo_wcwidth.h
libxo_la_SOURCES = \
libxo.c \
xo_encoder.c \
xo_syslog.c
man3_files = \
libxo.3 \
xo_attr.3 \
xo_create.3 \
xo_emit.3 \
xo_emit_err.3 \
xo_err.3 \
xo_error.3 \
xo_finish.3 \
xo_flush.3 \
xo_message.3 \
xo_no_setlocale.3 \
xo_open_container.3 \
xo_open_list.3 \
xo_open_marker.3 \
xo_parse_args.3 \
xo_set_allocator.3 \
xo_set_flags.3 \
xo_set_info.3 \
xo_set_options.3 \
xo_set_style.3 \
xo_set_syslog_enterprise_id.3 \
xo_set_version.3 \
xo_set_writer.3 \
xo_syslog.3
man5_files = \
xo_format.5
man7_files = \
xo_options.7
man_MANS = ${man3_files} ${man5_files} ${man7_files}
EXTRA_DIST = \
${man_MANS}
call-graph:
${RM} libxo.o
${MAKE} CC="clang -Xclang -analyze -Xclang \
-analyzer-checker=debug.ViewCallGraph" libxo.o
install-data-hook:
for file in ${man3_files}; do \
cat ../libxo/add.man >> ${DESTDIR}${man3dir}/$$file ; done
for file in ${man5_files}; do \
cat ../libxo/add.man >> ${DESTDIR}${man5dir}/$$file ; done
for file in ${man7_files}; do \
cat ../libxo/add.man >> ${DESTDIR}${man7dir}/$$file ; done

29
0.9.0/libxo/add.man.in Normal file
View File

@ -0,0 +1,29 @@
.Sh ADDITIONAL DOCUMENTATION
.Fx
uses
.Nm libxo
version @LIBXO_VERSION@.
Complete documentation can be found on github:
.Bd -literal -offset indent
http://juniper.github.io/libxo/@LIBXO_VERSION@/libxo\-manual.html
.Ed
.Pp
.Nm libxo
lives on github as:
.Bd -literal -offset indent
https://github.com/Juniper/libxo
.Ed
.Pp
The latest release of
.Nm libxo
is available at:
.Bd -literal -offset indent
https://github.com/Juniper/libxo/releases
.Ed
.Sh HISTORY
The
.Nm libxo
library was added in
.Fx 11.0 .
.Sh AUTHOR
Phil Shafer

76
0.9.0/libxo/gen-wide.sh Executable file
View File

@ -0,0 +1,76 @@
#!/bin/sh
FILE=$1
SYMBOLS="
xo_buffer_s
xo_buffer_t
xo_stack_s
xo_stack_t
xo_handle_s
xo_handle_t
xo_default_handle
xo_default_inited
xo_realloc
xo_free
xo_write_to_file
xo_close_file
xo_buf_init
xo_init_handle
xo_default_init
xo_buf_has_room
xo_printf
xo_escape_xml
xo_escape_json
xo_buf_append
xo_buf_escape
xo_data_append
xo_data_escape
xo_default
xo_indent
xo_warn
xo_create
xo_create_to_file
xo_destroy
xo_set_style
xo_set_flags
xo_set_info
xo_set_formatter
xo_clear_flags
xo_buf_indent
xo_line_ensure_open
xo_line_close
xo_info_compare
xo_info_find
xo_format_data
xo_buf_append_div
xo_format_text
xo_format_label
xo_format_title
xo_format_prep
xo_format_value
xo_format_decoration
xo_format_padding
xo_do_emit
xo_emit_hv
xo_emit_h
xo_emit
xo_attr_hv
xo_attr_h
xo_attr
xo_depth_change
xo_open_container_h
xo_open_container
xo_close_container_h
xo_close_container
xo_open_list_h
xo_open_list
xo_close_list_h
xo_close_list
xo_open_instance_h
xo_open_instance
xo_close_instance_h
xo_close_instance
xo_set_writer
xo_set_allocator
"

323
0.9.0/libxo/libxo.3 Normal file
View File

@ -0,0 +1,323 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 8, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm libxo
.Nd library for emitting text, XML, JSON, or HTML output
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Sh DESCRIPTION
The functions defined in
.Nm
are used to generate a choice of
.Em TEXT ,
.Em XML ,
.Em JSON ,
or
.Em HTML
output.
A common set of functions are used, with
command line switches passed to the library to control the details of
the output.
.Pp
Most commands emit text output aimed at humans.
It is designed
to be parsed and understood by a user.
Humans are gifted at extracting
details and pattern matching.
Often programmers need to extract
information from this human-oriented output.
Programmers use tools
like
.Xr grep 1 ,
.Xr awk 1 ,
and regular expressions to ferret out the pieces of
information they need.
Such solutions are fragile and require
updates when output contents change or evolve, requiring testing and
validation.
.Pp
Modern tool developers favor encoding schemes like XML and JSON,
which allow trivial parsing and extraction of data.
Such formats are
simple, well understood, hierarchical, easily parsed, and often
integrate easier with common tools and environments.
.Pp
In addition, modern reality means that more output ends up in web
browsers than in terminals, making HTML output valuable.
.Pp
.Nm
allows a single set of function calls in source code to generate
traditional text output, as well as XML and JSON formatted data.
HTML
can also be generated; "<div>" elements surround the traditional text
output, with attributes that detail how to render the data.
.Pp
There are four encoding styles supported by
.Nm :
.Bl -bullet
.It
TEXT output can be display on a terminal session, allowing
compatibility with traditional command line usage.
.It
XML output is suitable for tools like XPath and protocols like
NETCONF.
.It
JSON output can be used for RESTful APIs and integration with
languages like Javascript and Python.
.It
HTML can be matched with a small CSS file to permit rendering in any
HTML5 browser.
.El
.Pp
In general, XML and JSON are suitable for encoding data, while TEXT is
suited for terminal output and HTML is suited for display in a web
browser (see
.Xr xohtml 1 ).
.Pp
The
.Nm
library allows an application to generate text, XML, JSON,
and HTML output using a common set of function calls.
The application
decides at run time which output style should be produced.
The
application calls a function
.Xr xo_emit 3
to product output that is
described in a format string.
A
.Dq field descriptor
tells
.Nm
what the field is and what it means.
Each field descriptor is placed in
braces with a printf-like format string:
.Bd -literal -offset indent
xo_emit(" {:lines/%7ju} {:words/%7ju} "
"{:characters/%7ju}{d:filename/%s}\\n",
linect, wordct, charct, file);
.Ed
.Pp
Each field can have a role, with the 'value' role being the default,
and the role tells
.Nm
how and when to render that field, as well as
a
.Xr printf 3 Ns -like
format string.
.Pp
Output
can then be generated in various style, using the "--libxo" option.
.Sh DEFAULT HANDLE
Handles give an abstraction for
.Nm
that encapsulates the state of a
stream of output.
Handles have the data type "xo_handle_t" and are
opaque to the caller.
.Pp
The library has a default handle that is automatically initialized.
By default, this handle will send text style output to standard output.
The
.Xr xo_set_style 3
and
.Xr xo_set_flags 3
functions can be used to change this
behavior.
.Pp
Many
.Nm
functions take a handle as their first parameter; most that
do not use the default handle.
Any function taking a handle can
be passed
.Dv NULL
to access the default handle.
.Pp
For the typical command that is generating output on standard output,
there is no need to create an explicit handle, but they are available
when needed, e.g., for daemons that generate multiple streams of
output.
.Sh FUNCTION OVERVIEW
The
.Nm
library includes the following functions:
.Bl -tag -width "xo_close_container_hd"
.It Sy "Function Description"
.It Fn xo_attr
.It Fn xo_attr_h
.It Fn xo_attr_hv
Allows the caller to emit XML attributes with the next open element.
.It Fn xo_create
.It Fn xo_create_to_file
Allow the caller to create a new handle.
Note that
.Nm
has a default handle that allows the caller to avoid use of an
explicitly created handle.
Only callers writing to files other than
.Dv stdout
would need to call
.Fn xo_create .
.It Fn xo_destroy
Frees any resources associated with the handle, including the handle
itself.
.It Fn xo_emit
.It Fn xo_emit_h
.It Fn xo_emit_hv
Emit formatted output.
The
.Fa fmt
string controls the conversion of the remaining arguments into
formatted output.
See
.Xr xo_format 5
for details.
.It Fn xo_emit_warn
.It Fn xo_emit_warnx
.It Fn xo_emit_warn_c
.It Fn xo_emit_warn_hc
.It Fn xo_emit_err
.It Fn xo_emit_errc
.It Fn xo_emit_errx
These functions are mildly compatible with their standard libc
namesakes, but use the format string defined in
.Xr xo_format 5 .
While there is an increased cost for converting the strings, the
output provided can be richer and more useful. See also
.Xr xo_err 3
.It Fn xo_warn
.It Fn xo_warnx
.It Fn xo_warn_c
.It Fn xo_warn_hc
.It Fn xo_err
.It Fn xo_errc
.It Fn xo_errx
.It Fn xo_message
.It Fn xo_message_c
.It Fn xo_message_hc
.It Fn xo_message_hcv
These functions are meant to be compatible with their standard libc namesakes.
.It Fn xo_finish
.It Fn xo_finish_h
Flush output, close open construct, and complete any pending
operations.
.It Fn xo_flush
.It Fn xo_flush_h
Allow the caller to flush any pending output for a handle.
.It Fn xo_no_setlocale
Direct
.Nm
to avoid initializing the locale.
This function should be called before any other
.Nm
function is called.
.It Fn xo_open_container
.It Fn xo_open_container_h
.It Fn xo_open_container_hd
.It Fn xo_open_container_d
.It Fn xo_close_container
.It Fn xo_close_container_h
.It Fn xo_close_container_hd
.It Fn xo_close_container_d
Containers a singleton levels of hierarchy, typically used to organize
related content.
.It Fn xo_open_list_h
.It Fn xo_open_list
.It Fn xo_open_list_hd
.It Fn xo_open_list_d
.It Fn xo_open_instance_h
.It Fn xo_open_instance
.It Fn xo_open_instance_hd
.It Fn xo_open_instance_d
.It Fn xo_close_instance_h
.It Fn xo_close_instance
.It Fn xo_close_instance_hd
.It Fn xo_close_instance_d
.It Fn xo_close_list_h
.It Fn xo_close_list
.It Fn xo_close_list_hd
.It Fn xo_close_list_d
Lists are levels of hierarchy that can appear multiple times within
the same parent.
Two calls are needed to encapsulate them, one for
the list and one for each instance of that list.
Typically
.Fn xo_open_list
and
.Fn xo_close_list
are called outside a
for-loop, where
.Fn xo_open_instance
it called at the top of the loop, and
.Fn xo_close_instance
is called at the bottom of the loop.
.It Fn xo_parse_args
Inspects command line arguments for directions to
.Nm .
This function should be called before
.Va argv
is inspected by the application.
.It Fn xo_set_allocator
Instructs
.Nm
to use an alternative memory allocator and deallocator.
.It Fn xo_set_flags
.It Fn xo_clear_flags
Change the flags set for a handle.
.It Fn xo_set_info
Provides additional information about elements for use with HTML
rendering.
.It Fn xo_set_options
Changes formatting options used by handle.
.It Fn xo_set_style
.It Fn xo_set_style_name
Changes the output style used by a handle.
.It Fn xo_set_writer
Instructs
.Nm
to use an alternative set of low-level output functions.
.El
.Sh SEE ALSO
.Xr xo 1 ,
.Xr xolint 1 ,
.Xr xo_attr 3 ,
.Xr xo_create 3 ,
.Xr xo_emit 3 ,
.Xr xo_emit_err 3 ,
.Xr xo_err 3 ,
.Xr xo_finish 3 ,
.Xr xo_flush 3 ,
.Xr xo_no_setlocale 3 ,
.Xr xo_open_container 3 ,
.Xr xo_open_list 3 ,
.Xr xo_parse_args 3 ,
.Xr xo_set_allocator 3 ,
.Xr xo_set_flags 3 ,
.Xr xo_set_info 3 ,
.Xr xo_set_options 3 ,
.Xr xo_set_style 3 ,
.Xr xo_set_writer 3 ,
.Xr xo_format 5
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

8404
0.9.0/libxo/libxo.c Normal file

File diff suppressed because it is too large Load Diff

683
0.9.0/libxo/xo.h Normal file
View File

@ -0,0 +1,683 @@
/*
* Copyright (c) 2014-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, July 2014
*/
/**
* libxo provides a means of generating text, XML, JSON, and HTML output
* using a single set of function calls, maximizing the value of output
* while minimizing the cost/impact on the code.
*
* Full documentation is available in ./doc/libxo.txt or online at:
* http://juniper.github.io/libxo/libxo-manual.html
*/
#ifndef INCLUDE_XO_H
#define INCLUDE_XO_H
#include <stdio.h>
#include <sys/types.h>
#include <stdarg.h>
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#ifdef __dead2
#define NORETURN __dead2
#else
#define NORETURN
#endif /* __dead2 */
/*
* Normally we'd use the HAVE_PRINTFLIKE define triggered by the
* --enable-printflike option to configure, but we don't install
* our internal "xoconfig.h", and I'd rather not. Taking the
* coward's path, we'll turn it on inside a #if that allows
* others to turn it off where needed. Not ideal, but functional.
*/
#if !defined(NO_PRINTFLIKE)
#if defined(__linux) && !defined(__printflike)
#define __printflike(_x, _y) __attribute__((__format__ (__printf__, _x, _y)))
#endif
#define PRINTFLIKE(_x, _y) __printflike(_x, _y)
#else
#define PRINTFLIKE(_x, _y)
#endif /* NO_PRINTFLIKE */
/** Formatting types */
typedef unsigned short xo_style_t;
#define XO_STYLE_TEXT 0 /** Generate text output */
#define XO_STYLE_XML 1 /** Generate XML output */
#define XO_STYLE_JSON 2 /** Generate JSON output */
#define XO_STYLE_HTML 3 /** Generate HTML output */
#define XO_STYLE_SDPARAMS 4 /* Generate syslog structured data params */
#define XO_STYLE_ENCODER 5 /* Generate calls to external encoder */
/** Flags for libxo */
typedef unsigned long long xo_xof_flags_t;
#define XOF_BIT(_n) ((xo_xof_flags_t) 1 << (_n))
#define XOF_CLOSE_FP XOF_BIT(0) /** Close file pointer on xo_close() */
#define XOF_PRETTY XOF_BIT(1) /** Make 'pretty printed' output */
#define XOF_LOG_SYSLOG XOF_BIT(2) /** Log (on stderr) our syslog content */
#define XOF_RESV3 XOF_BIT(3) /* Unused */
#define XOF_WARN XOF_BIT(4) /** Generate warnings for broken calls */
#define XOF_XPATH XOF_BIT(5) /** Emit XPath attributes in HTML */
#define XOF_INFO XOF_BIT(6) /** Emit additional info fields (HTML) */
#define XOF_WARN_XML XOF_BIT(7) /** Emit warnings in XML (on stdout) */
#define XOF_NO_ENV XOF_BIT(8) /** Don't look at LIBXO_OPTIONS env var */
#define XOF_NO_VA_ARG XOF_BIT(9) /** Don't advance va_list w/ va_arg() */
#define XOF_DTRT XOF_BIT(10) /** Enable "do the right thing" mode */
#define XOF_KEYS XOF_BIT(11) /** Flag 'key' fields for xml and json */
#define XOF_IGNORE_CLOSE XOF_BIT(12) /** Ignore errors on close tags */
#define XOF_NOT_FIRST XOF_BIT(13) /* Not the first item (JSON) */
#define XOF_NO_LOCALE XOF_BIT(14) /** Don't bother with locale */
#define XOF_RESV15 XOF_BIT(15) /* Unused */
#define XOF_NO_TOP XOF_BIT(16) /** Don't emit the top braces in JSON */
#define XOF_RESV17 XOF_BIT(17) /* Unused */
#define XOF_UNITS XOF_BIT(18) /** Encode units in XML */
#define XOF_RESV19 XOF_BIT(19) /* Unused */
#define XOF_UNDERSCORES XOF_BIT(20) /** Replace dashes with underscores (JSON)*/
#define XOF_COLUMNS XOF_BIT(21) /** xo_emit should return a column count */
#define XOF_FLUSH XOF_BIT(22) /** Flush after each xo_emit call */
#define XOF_FLUSH_LINE XOF_BIT(23) /** Flush after each newline */
#define XOF_NO_CLOSE XOF_BIT(24) /** xo_finish won't close open elements */
#define XOF_COLOR_ALLOWED XOF_BIT(25) /** Allow color/effects to be enabled */
#define XOF_COLOR XOF_BIT(26) /** Enable color and effects */
#define XOF_NO_HUMANIZE XOF_BIT(27) /** Block the {h:} modifier */
#define XOF_LOG_GETTEXT XOF_BIT(28) /** Log (stderr) gettext lookup strings */
#define XOF_UTF8 XOF_BIT(29) /** Force text output to be UTF8 */
#define XOF_RETAIN_ALL XOF_BIT(30) /** Force use of XOEF_RETAIN */
#define XOF_RETAIN_NONE XOF_BIT(31) /** Prevent use of XOEF_RETAIN */
#define XOF_COLOR_MAP XOF_BIT(32) /** Color map has been initialized */
typedef unsigned xo_emit_flags_t; /* Flags to xo_emit() and friends */
#define XOEF_RETAIN (1<<0) /* Retain parsed formatting information */
/*
* The xo_info_t structure provides a mapping between names and
* additional data emitted via HTML.
*/
typedef struct xo_info_s {
const char *xi_name; /* Name of the element */
const char *xi_type; /* Type of field */
const char *xi_help; /* Description of field */
} xo_info_t;
#define XO_INFO_NULL NULL, NULL, NULL /* Use '{ XO_INFO_NULL }' to end lists */
struct xo_handle_s; /* Opaque structure forward */
typedef struct xo_handle_s xo_handle_t; /* Handle for XO output */
/*
* Early versions of the API used "int" instead of "size_t" for buffer
* sizes. We want to fix this but allow for backwards compatibility
* where needed.
*/
#ifdef USE_INT_RETURN_CODES
typedef int xo_ssize_t; /* Buffer size */
#else /* USE_INT_RETURN_CODES */
typedef ssize_t xo_ssize_t; /* Buffer size */
#endif /* USE_INT_RETURN_CODES */
typedef xo_ssize_t (*xo_write_func_t)(void *, const char *);
typedef void (*xo_close_func_t)(void *);
typedef int (*xo_flush_func_t)(void *);
typedef void *(*xo_realloc_func_t)(void *, size_t);
typedef void (*xo_free_func_t)(void *);
/*
* The formatter function mirrors "vsnprintf", with an additional argument
* of the xo handle. The caller should return the number of bytes _needed_
* to fit the data, even if this exceeds 'len'.
*/
typedef xo_ssize_t (*xo_formatter_t)(xo_handle_t *, char *, xo_ssize_t,
const char *, va_list);
typedef void (*xo_checkpointer_t)(xo_handle_t *, va_list, int);
xo_handle_t *
xo_create (xo_style_t style, xo_xof_flags_t flags);
xo_handle_t *
xo_create_to_file (FILE *fp, xo_style_t style, xo_xof_flags_t flags);
void
xo_destroy (xo_handle_t *xop);
void
xo_set_writer (xo_handle_t *xop, void *opaque, xo_write_func_t write_func,
xo_close_func_t close_func, xo_flush_func_t flush_func);
void
xo_set_allocator (xo_realloc_func_t realloc_func, xo_free_func_t free_func);
void
xo_set_style (xo_handle_t *xop, xo_style_t style);
xo_style_t
xo_get_style (xo_handle_t *xop);
int
xo_set_style_name (xo_handle_t *xop, const char *style);
int
xo_set_options (xo_handle_t *xop, const char *input);
xo_xof_flags_t
xo_get_flags (xo_handle_t *xop);
void
xo_set_flags (xo_handle_t *xop, xo_xof_flags_t flags);
void
xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags);
int
xo_set_file_h (xo_handle_t *xop, FILE *fp);
int
xo_set_file (FILE *fp);
void
xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count);
void
xo_set_formatter (xo_handle_t *xop, xo_formatter_t func, xo_checkpointer_t);
void
xo_set_depth (xo_handle_t *xop, int depth);
xo_ssize_t
xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap);
xo_ssize_t
xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
xo_ssize_t
xo_emit (const char *fmt, ...);
xo_ssize_t
xo_emit_hvf (xo_handle_t *xop, xo_emit_flags_t flags,
const char *fmt, va_list vap);
xo_ssize_t
xo_emit_hf (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...);
xo_ssize_t
xo_emit_f (xo_emit_flags_t flags, const char *fmt, ...);
PRINTFLIKE(2, 0)
static inline int
xo_emit_hvp (xo_handle_t *xop, const char *fmt, va_list vap)
{
return xo_emit_hv(xop, fmt, vap);
}
PRINTFLIKE(2, 3)
static inline int
xo_emit_hp (xo_handle_t *xop, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
int rc = xo_emit_hv(xop, fmt, vap);
va_end(vap);
return rc;
}
PRINTFLIKE(1, 2)
static inline int
xo_emit_p (const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
int rc = xo_emit_hv(NULL, fmt, vap);
va_end(vap);
return rc;
}
PRINTFLIKE(3, 0)
static inline int
xo_emit_hvfp (xo_handle_t *xop, xo_emit_flags_t flags,
const char *fmt, va_list vap)
{
return xo_emit_hvf(xop, flags, fmt, vap);
}
PRINTFLIKE(3, 4)
static inline int
xo_emit_hfp (xo_handle_t *xop, xo_emit_flags_t flags, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
int rc = xo_emit_hvf(xop, flags, fmt, vap);
va_end(vap);
return rc;
}
PRINTFLIKE(2, 3)
static inline int
xo_emit_fp (xo_emit_flags_t flags, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
int rc = xo_emit_hvf(NULL, flags, fmt, vap);
va_end(vap);
return rc;
}
xo_ssize_t
xo_open_container_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_container (const char *name);
xo_ssize_t
xo_open_container_hd (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_container_d (const char *name);
xo_ssize_t
xo_close_container_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_close_container (const char *name);
xo_ssize_t
xo_close_container_hd (xo_handle_t *xop);
xo_ssize_t
xo_close_container_d (void);
xo_ssize_t
xo_open_list_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_list (const char *name);
xo_ssize_t
xo_open_list_hd (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_list_d (const char *name);
xo_ssize_t
xo_close_list_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_close_list (const char *name);
xo_ssize_t
xo_close_list_hd (xo_handle_t *xop);
xo_ssize_t
xo_close_list_d (void);
xo_ssize_t
xo_open_instance_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_instance (const char *name);
xo_ssize_t
xo_open_instance_hd (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_instance_d (const char *name);
xo_ssize_t
xo_close_instance_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_close_instance (const char *name);
xo_ssize_t
xo_close_instance_hd (xo_handle_t *xop);
xo_ssize_t
xo_close_instance_d (void);
xo_ssize_t
xo_open_marker_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_open_marker (const char *name);
xo_ssize_t
xo_close_marker_h (xo_handle_t *xop, const char *name);
xo_ssize_t
xo_close_marker (const char *name);
xo_ssize_t
xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...);
xo_ssize_t
xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap);
xo_ssize_t
xo_attr (const char *name, const char *fmt, ...);
void
xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap);
void
xo_error_h (xo_handle_t *xop, const char *fmt, ...);
void
xo_error (const char *fmt, ...);
xo_ssize_t
xo_flush_h (xo_handle_t *xop);
xo_ssize_t
xo_flush (void);
xo_ssize_t
xo_finish_h (xo_handle_t *xop);
xo_ssize_t
xo_finish (void);
void
xo_finish_atexit (void);
void
xo_set_leading_xpath (xo_handle_t *xop, const char *path);
void
xo_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
void
xo_warn_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
void
xo_warn (const char *fmt, ...) PRINTFLIKE(1, 2);
void
xo_warnx (const char *fmt, ...) PRINTFLIKE(1, 2);
void
xo_err (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
void
xo_errx (int eval, const char *fmt, ...) NORETURN PRINTFLIKE(2, 3);
void
xo_errc (int eval, int code, const char *fmt, ...) NORETURN PRINTFLIKE(3, 4);
void
xo_message_hcv (xo_handle_t *xop, int code, const char *fmt, va_list vap) PRINTFLIKE(3, 0);
void
xo_message_hc (xo_handle_t *xop, int code, const char *fmt, ...) PRINTFLIKE(3, 4);
void
xo_message_c (int code, const char *fmt, ...) PRINTFLIKE(2, 3);
void
xo_message_e (const char *fmt, ...) PRINTFLIKE(1, 2);
void
xo_message (const char *fmt, ...) PRINTFLIKE(1, 2);
void
xo_emit_warn_hcv (xo_handle_t *xop, int as_warning, int code,
const char *fmt, va_list vap);
void
xo_emit_warn_hc (xo_handle_t *xop, int code, const char *fmt, ...);
void
xo_emit_warn_c (int code, const char *fmt, ...);
void
xo_emit_warn (const char *fmt, ...);
void
xo_emit_warnx (const char *fmt, ...);
void
xo_emit_err (int eval, const char *fmt, ...) NORETURN;
void
xo_emit_errx (int eval, const char *fmt, ...) NORETURN;
void
xo_emit_errc (int eval, int code, const char *fmt, ...) NORETURN;
PRINTFLIKE(4, 0)
static inline void
xo_emit_warn_hcvp (xo_handle_t *xop, int as_warning, int code,
const char *fmt, va_list vap)
{
xo_emit_warn_hcv(xop, as_warning, code, fmt, vap);
}
PRINTFLIKE(3, 4)
static inline void
xo_emit_warn_hcp (xo_handle_t *xop, int code, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(xop, 1, code, fmt, vap);
va_end(vap);
}
PRINTFLIKE(2, 3)
static inline void
xo_emit_warn_cp (int code, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
va_end(vap);
}
PRINTFLIKE(1, 2)
static inline void
xo_emit_warn_p (const char *fmt, ...)
{
int code = errno;
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 1, code, fmt, vap);
va_end(vap);
}
PRINTFLIKE(1, 2)
static inline void
xo_emit_warnx_p (const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 1, -1, fmt, vap);
va_end(vap);
}
NORETURN PRINTFLIKE(2, 3)
static inline void
xo_emit_err_p (int eval, const char *fmt, ...)
{
int code = errno;
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 0, code, fmt, vap);
va_end(vap);
exit(eval);
}
PRINTFLIKE(2, 3)
static inline void
xo_emit_errx_p (int eval, const char *fmt, ...)
{
va_list vap;
va_start(vap, fmt);
xo_emit_warn_hcv(NULL, 0, -1, fmt, vap);
va_end(vap);
exit(eval);
}
PRINTFLIKE(3, 4)
static inline void
xo_emit_errc_p (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);
exit(eval);
}
void
xo_emit_err_v (int eval, int code, const char *fmt, va_list vap) NORETURN PRINTFLIKE(3, 0);
void
xo_no_setlocale (void);
/**
* @brief Lift libxo-specific arguments from a set of arguments
*
* libxo-enable programs typically use command line options to enable
* all the nifty-cool libxo features. xo_parse_args() makes this simple
* by pre-processing the command line arguments given to main(), handling
* and removing the libxo-specific ones, meaning anything starting with
* "--libxo". A full description of these arguments is in the base
* documentation.
* @param[in] argc Number of arguments (ala #main())
* @param[in] argc Array of argument strings (ala #main())
* @return New number of arguments, or -1 for failure.
*/
int
xo_parse_args (int argc, char **argv);
/**
* This is the "magic" number returned by libxo-supporting commands
* when passed the equally magic "--libxo-check" option. If you
* return this, we can (unsafely) assume that since you know the magic
* handshake, you'll happily handle future --libxo options and not do
* something violent like reboot the box or create another hole in the
* ozone layer.
*/
#define XO_HAS_LIBXO 121
/**
* externs for libxo's version number strings
*/
extern const char xo_version[]; /** Base version triple string */
extern const char xo_version_extra[]; /** Extra version magic content */
/**
* @brief Dump the internal stack of a libxo handle.
*
* This diagnostic function is something I will ask you to call from
* your program when you write to tell me libxo has gone bat-stink
* crazy and has discarded your list or container or content. Output
* content will be what we lovingly call "developer entertainment".
* @param[in] xop A valid libxo handle, or NULL for the default handle
*/
void
xo_dump_stack (xo_handle_t *xop);
/**
* @brief Recode the name of the program, suitable for error output.
*
* libxo will record the given name for use while generating error
* messages. The contents are not copied, so the value must continue
* to point to a valid memory location. This allows the caller to change
* the value, but requires the caller to manage the memory. Typically
* this is called with argv[0] from main().
* @param[in] name The name of the current application program
*/
void
xo_set_program (const char *name);
/**
* @brief Add a version string to the output, where possible.
*
* Adds a version number to the output, suitable for tracking
* changes in the content. This is only important for the "encoding"
* format styles (XML and JSON) and allows a user of the data to
* discern which version of the data model is in use.
* @param[in] version The version number, encoded as a string
*/
void
xo_set_version (const char *version);
/**
* #xo_set_version with a handle.
* @param[in] xop A valid libxo handle, or NULL for the default handle
* @param[in] version The version number, encoded as a string
*/
void
xo_set_version_h (xo_handle_t *xop, const char *version);
void
xo_open_log (const char *ident, int logopt, int facility);
void
xo_close_log (void);
int
xo_set_logmask (int maskpri);
void
xo_set_unit_test_mode (int value);
void
xo_syslog (int priority, const char *name, const char *message, ...);
void
xo_vsyslog (int priority, const char *name, const char *message, va_list args);
typedef void (*xo_syslog_open_t)(void);
typedef void (*xo_syslog_send_t)(const char *full_msg,
const char *v0_hdr, const char *text_only);
typedef void (*xo_syslog_close_t)(void);
void
xo_set_syslog_handler (xo_syslog_open_t open_func, xo_syslog_send_t send_func,
xo_syslog_close_t close_func);
void
xo_set_syslog_enterprise_id (unsigned short eid);
typedef void (*xo_simplify_field_func_t)(const char *, unsigned, int);
char *
xo_simplify_format (xo_handle_t *xop, const char *fmt, int with_numbers,
xo_simplify_field_func_t field_cb);
xo_ssize_t
xo_emit_field_hv (xo_handle_t *xop, const char *rolmod, const char *contents,
const char *fmt, const char *efmt,
va_list vap);
xo_ssize_t
xo_emit_field_h (xo_handle_t *xop, const char *rolmod, const char *contents,
const char *fmt, const char *efmt, ...);
xo_ssize_t
xo_emit_field (const char *rolmod, const char *contents,
const char *fmt, const char *efmt, ...);
void
xo_retain_clear_all (void);
void
xo_retain_clear (const char *fmt);
#endif /* INCLUDE_XO_H */

70
0.9.0/libxo/xo_attr.3 Normal file
View File

@ -0,0 +1,70 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd July, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_attr , xo_attr_h , xo_attr_hv
.Nd Add attribute name/value pairs to formatted output
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_attr "const char *name" "const char *fmt" "..."
.Ft int
.Fn xo_attr_h "xo_handle_t *handle" "const char *name, const char *fmt" "..."
.Ft int
.Fn xo_attr_hv "xo_handle_t *handle" "const char *name" "const char *fmt" "va_list vap"
.Sh DESCRIPTION
The
.Fn xo_attr
function emits attributes for the XML output style. The attribute
value is recorded in the
.Fa handle
and is attached to the next field that is emitted via a
.Xr xo_emit 3
call.
.Pp
The
.Fa name
parameter give the name of the attribute to be encoded. The
.Fa fmt
parameter gives a printf-style format string used to format the
value of the attribute using any remaining arguments, or the
.Fa vap
parameter as passed to
.Fn xo_attr_hv .
.Bd -literal -offset indent
EXAMPLE:
xo_attr("seconds", "%ld", (unsigned long) login_time);
struct tm *tmp = localtime(login_time);
strftime(buf, sizeof(buf), "%R", tmp);
xo_emit("Logged in at {:login-time}\\n", buf);
XML:
<login-time seconds="1408336270">00:14</login-time>
.Ed
.Pp
Since attributes are only emitted in XML, their use should be limited
to meta-data and additional or redundant representations of data
already emitted in other form.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

158
0.9.0/libxo/xo_buf.h Normal file
View File

@ -0,0 +1,158 @@
/*
* 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
*/
/*
* This file is an _internal_ part of the libxo plumbing, not suitable
* for external use. It is not considered part of the libxo API and
* will not be a stable part of that API. Mine, not your's, dude...
* The real hope is that something like this will become a standard part
* of libc and I can kill this off.
*/
#ifndef XO_BUF_H
#define XO_BUF_H
#define XO_BUFSIZ (8*1024) /* Initial buffer size */
#define XO_BUF_HIGH_WATER (XO_BUFSIZ - 512) /* When to auto-flush */
/*
* xo_buffer_t: a memory buffer that can be grown as needed. We
* use them for building format strings and output data.
*/
typedef struct xo_buffer_s {
char *xb_bufp; /* Buffer memory */
char *xb_curp; /* Current insertion point */
ssize_t xb_size; /* Size of buffer */
} xo_buffer_t;
/*
* Initialize the contents of an xo_buffer_t.
*/
static inline void
xo_buf_init (xo_buffer_t *xbp)
{
xbp->xb_size = XO_BUFSIZ;
xbp->xb_bufp = xo_realloc(NULL, xbp->xb_size);
xbp->xb_curp = xbp->xb_bufp;
}
/*
* Reset the buffer to empty
*/
static inline void
xo_buf_reset (xo_buffer_t *xbp)
{
xbp->xb_curp = xbp->xb_bufp;
}
/*
* Return the number of bytes left in the buffer
*/
static inline int
xo_buf_left (xo_buffer_t *xbp)
{
return xbp->xb_size - (xbp->xb_curp - xbp->xb_bufp);
}
/*
* See if the buffer to empty
*/
static inline int
xo_buf_is_empty (xo_buffer_t *xbp)
{
return (xbp->xb_curp == xbp->xb_bufp);
}
/*
* Return the current offset
*/
static inline unsigned
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)
{
if (xbp == NULL)
return NULL;
return xbp->xb_bufp + offset;
}
static inline char *
xo_buf_cur (xo_buffer_t *xbp)
{
if (xbp == NULL)
return NULL;
return xbp->xb_curp;
}
/*
* Initialize the contents of an xo_buffer_t.
*/
static inline void
xo_buf_cleanup (xo_buffer_t *xbp)
{
if (xbp->xb_bufp)
xo_free(xbp->xb_bufp);
bzero(xbp, sizeof(*xbp));
}
/*
* Does the buffer have room for the given number of bytes of data?
* If not, realloc the buffer to make room. If that fails, we
* return 0 to tell the caller they are in trouble.
*/
static inline int
xo_buf_has_room (xo_buffer_t *xbp, ssize_t len)
{
if (xbp->xb_curp + len >= xbp->xb_bufp + xbp->xb_size) {
ssize_t sz = xbp->xb_size + XO_BUFSIZ;
char *bp = xo_realloc(xbp->xb_bufp, sz);
if (bp == NULL)
return 0;
xbp->xb_curp = bp + (xbp->xb_curp - xbp->xb_bufp);
xbp->xb_bufp = bp;
xbp->xb_size = sz;
}
return 1;
}
/*
* Append the given string to the given buffer
*/
static inline void
xo_buf_append (xo_buffer_t *xbp, const char *str, ssize_t len)
{
if (str == NULL || len == 0 || !xo_buf_has_room(xbp, len))
return;
memcpy(xbp->xb_curp, str, len);
xbp->xb_curp += len;
}
/*
* Append the given NUL-terminated string to the given buffer
*/
static inline void
xo_buf_append_str (xo_buffer_t *xbp, const char *str)
{
ssize_t len = strlen(str);
if (!xo_buf_has_room(xbp, len))
return;
memcpy(xbp->xb_curp, str, len);
xbp->xb_curp += len;
}
#endif /* XO_BUF_H */

77
0.9.0/libxo/xo_create.3 Normal file
View File

@ -0,0 +1,77 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_create , xo_create_to_file , xo_destroy
.Nd create and destroy libxo output handles
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft xo_handle_t *
.Fn xo_create "unsigned style" "unsigned flags"
.Ft xo_handle_t *
.Fn xo_create_to_file "FILE *fp" "unsigned style" "unsigned flags"
.Ft void
.Fn xo_destroy "xo_handle_t *handle"
.Sh DESCRIPTION
A
.Nm libxo
handle can be allocated using the
.Fn xo_create
function.
.Bd -literal -offset indent
Example:
xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN);
....
xo_emit_h(xop, "testing\n");
.Ed
.Pp
By default,
.Nm libxo
writes output to standard output.
A convenience
function is provided for situations when output should be written to a
different file.
.Pp
Use the
.Dv XOF_CLOSE_FP
flag to trigger a call to
.Xr fclose 3
for the
.Dv FILE
pointer when the handle is destroyed.
.Pp
The
.Fn xo_destroy
function releases a handle and any resources it is
using.
Calling
.Fn xo_destroy
with a
.Dv NULL
handle will release any
resources associated with the default handle.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr xo_set_options 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

114
0.9.0/libxo/xo_emit.3 Normal file
View File

@ -0,0 +1,114 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_emit , xo_emit_h , xo_emit_hv
.Nd emit formatted output based on format string and arguments
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_emit "const char *fmt" "..."
.Ft int
.Fn xo_emit_h "xo_handle_t *xop" "const char *fmt" "..."
.Ft int
.Fn xo_emit_hv "xo_handle_t *xop" "const char *fmt" "va_list vap"
.Sh DESCRIPTION
The
.Fn xo_emit
function emits formatted output using the description in a format
string along with a set of zero or more arguments, in a style similar
to
.Xr printf 3
but using a more complex format description string, as described in
.Xr xo_format 5 .
.Pp
.Fn xo_emit
uses the default output handle, as described in
.Xr libxo 3 ,
where
.Fn xo_emit_h
uses an explicit handle.
.Fn xo_emit_hv
accepts a
.Fa va_list
for additional flexibility.
.Sh EXAMPLES
In this example, a set of four values is emitted using the following
source code:
.Bd -literal -offset indent
xo_emit(" {:lines/%7ju} {:words/%7ju} "
"{:characters/%7ju} {d:filename/%s}\n",
linect, wordct, charct, file);
.Ed
Output can then be generated in various style, using
the "--libxo" option:
.Bd -literal -offset indent
% wc /etc/motd
25 165 1140 /etc/motd
% wc --libxo xml,pretty,warn /etc/motd
<wc>
<file>
<lines>25</lines>
<words>165</words>
<characters>1140</characters>
<filename>/etc/motd</filename>
</file>
</wc>
% wc --libxo json,pretty,warn /etc/motd
{
"wc": {
"file": [
{
"lines": 25,
"words": 165,
"characters": 1140,
"filename": "/etc/motd"
}
]
}
}
% wc --libxo html,pretty,warn /etc/motd
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines"> 25</div>
<div class="text"> </div>
<div class="data" data-tag="words"> 165</div>
<div class="text"> </div>
<div class="data" data-tag="characters"> 1140</div>
<div class="text"> </div>
<div class="data" data-tag="filename">/etc/motd</div>
</div>
.Ed
.Sh RETURN CODE
.Nm
returns a negative value on error. If the
.Nm XOF_COLUMNS
flag has been turned on for the specific handle using
.Xr xo_set_flags 3 ,
then the number of display columns consumed by the output will be returned.
.Sh SEE ALSO
.Xr xo_open_container 3 ,
.Xr xo_open_list 3 ,
.Xr xo_format 5 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

82
0.9.0/libxo/xo_emit_err.3 Normal file
View File

@ -0,0 +1,82 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_emit_err , xo_emit_errc , xo_emit_errx
.Nm xo_emit_warn , xo_emit_warnx , xo_emit_warn_c , xo_emit_warn_hc
.Nd emit errors and warnings in multiple output styles
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_emit_warn "const char *fmt" "..."
.Ft void
.Fn xo_emit_warnx "const char *fmt" "..."
.Ft void
.Fn xo_emit_warn_c "int code" "const char *fmt" "..."
.Ft void
.Fn xo_emit_warn_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
.Ft void
.Fn xo_emit_err "int eval" "const char *fmt" "..."
.Ft void
.Fn xo_emit_errc "int eval" "int code" "const char *fmt" "..."
.Ft void
.Fn xo_emit_errx "int eval" "const char *fmt" "..."
.Sh DESCRIPTION
Many programs make use of the standard library functions
.Xr err 3
and
.Xr warn 3
to generate errors and warnings for the user.
.Nm libxo
wants to
pass that information via the current output style, and provides
compatible functions to allow this.
.Pp
The
.Fa fmt
argument is one compatible with
.Xr xo_emit 3
which allows these functions make structured data.
To generate unstructured data,
use the
.Xr xo_err 3
functions.
.Pp
These functions display the program name, a colon, a formatted message
based on the arguments, and then optionally a colon and an error
message associated with either
.Fa errno
or the
.Fa code
parameter.
.Bd -literal -offset indent
EXAMPLE:
if (open(filename, O_RDONLY) < 0)
xo_err(1, "cannot open file '%s'", filename);
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr xo_format 5 ,
.Xr xo_err 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

121
0.9.0/libxo/xo_emit_f.3 Normal file
View File

@ -0,0 +1,121 @@
.\" #
.\" # Copyright (c) 2016, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, April 2016
.\"
.Dd April 15, 2016
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_emit_f , xo_emit_hf , xo_emit_hvf
.Nd emit formatted output based on format string and arguments
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_emit_f "xo_emit_flags_t flags" "const char *fmt" "..."
.Ft int
.Fn xo_emit_hf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "..."
.Ft int
.Fn xo_emit_hvf "xo_handle_t *xop" "xo_emit_flags_t flags" "const char *fmt" "va_list vap"
.Ft void
.Fn xo_retain_clear_all "void"
.Ft void
.Fn xo_retain_clear "const char *fmt"
.Sh DESCRIPTION
These functions allow callers to pass a set of flags to
.Nm
emitting functions. These processing of arguments, except for
.Fa flags ,
is identical to the base functions.
See
.Xr xo_emit 3
for additional information.
.Pp
The only currently defined flag is
.Dv XOEF_RETAIN .
.Nm
can retain the parsed internal information related to the given
format string, allowing subsequent
.Xr xo_emit 3
calls, the retained
information is used, avoiding repetitive parsing of the format string.
To retain parsed format information, use the
.Dv XOEF_RETAIN
flag to the
.Fn xo_emit_f
function.
.Pp
The format string must be immutable across multiple calls to
.Xn xo_emit_f ,
since the library retains the string.
Typically this is done by using
static constant strings, such as string literals. If the string is not
immutable, the
.Dv XOEF_RETAIN
flag must not be used.
.Pp
The functions
.Fn xo_retain_clear
and
.Fn xo_retain_clear_all
release internal information on either a single format string or all
format strings, respectively.
Neither is required, but the library will
retain this information until it is cleared or the process exits.
.Pp
The retained information is kept as thread-specific data.
.Pp
Use
.Fn xo_retain_clear
and
.Fn xo_retain_clear_all
to clear the retained information, clearing the retained information
for either a specific format string or all format strings, respectively.
These functions are only needed when the calling application wants to
clear this information; they are not generally needed.
.Sh EXAMPLES
.Pp
.Bd -literal -offset indent
for (i = 0; i < 1000; i++) {
xo_open_instance("item");
xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\n",
name[i], count[i]);
}
.Ed
.Pp
In this example, the caller desires to clear the retained information.
.Bd -literal -offset indent
const char *fmt = "{:name} {:count/%d}\n";
for (i = 0; i < 1000; i++) {
xo_open_instance("item");
xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]);
}
xo_retain_clear(fmt);
.Ed
.Sh RETURN CODE
The return values for these functions is identical to those of their
traditional counterparts. See
.Xr xo_emit 3
for details.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr xo_open_container 3 ,
.Xr xo_open_list 3 ,
.Xr xo_format 5 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

375
0.9.0/libxo/xo_encoder.c Normal file
View File

@ -0,0 +1,375 @@
/*
* 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
*/
/**
* libxo includes a number of fixed encoding styles. But other
* external encoders are need to deal with new encoders. Rather
* than expose a swarm of libxo internals, we create a distinct
* API, with a simpler API than we use internally.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/param.h>
#include <dlfcn.h>
#include "xo_config.h"
#include "xo.h"
#include "xo_encoder.h"
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#if !defined(HAVE_DLFUNC)
#define dlfunc(_p, _n) dlsym(_p, _n)
#endif
#else /* HAVE_DLFCN_H */
#define dlopen(_n, _f) NULL /* Fail */
#define dlsym(_p, _n) NULL /* Fail */
#define dlfunc(_p, _n) NULL /* Fail */
#endif /* HAVE_DLFCN_H */
static void xo_encoder_setup (void); /* Forward decl */
/*
* Need a simple string collection
*/
typedef struct xo_string_node_s {
TAILQ_ENTRY(xo_string_node_s) xs_link; /* Next string */
char xs_data[0]; /* String data */
} xo_string_node_t;
typedef TAILQ_HEAD(xo_string_list_s, xo_string_node_s) xo_string_list_t;
static inline void
xo_string_list_init (xo_string_list_t *listp)
{
if (listp->tqh_last == NULL)
TAILQ_INIT(listp);
}
static inline xo_string_node_t *
xo_string_add (xo_string_list_t *listp, const char *str)
{
if (listp == NULL || str == NULL)
return NULL;
xo_string_list_init(listp);
size_t len = strlen(str);
xo_string_node_t *xsp;
xsp = xo_realloc(NULL, sizeof(*xsp) + len + 1);
if (xsp) {
memcpy(xsp->xs_data, str, len);
xsp->xs_data[len] = '\0';
TAILQ_INSERT_TAIL(listp, xsp, xs_link);
}
return xsp;
}
#define XO_STRING_LIST_FOREACH(_xsp, _listp) \
xo_string_list_init(_listp); \
TAILQ_FOREACH(_xsp, _listp, xs_link)
static inline void
xo_string_list_clean (xo_string_list_t *listp)
{
xo_string_node_t *xsp;
xo_string_list_init(listp);
for (;;) {
xsp = TAILQ_FIRST(listp);
if (xsp == NULL)
break;
TAILQ_REMOVE(listp, xsp, xs_link);
xo_free(xsp);
}
}
static xo_string_list_t xo_encoder_path;
void
xo_encoder_path_add (const char *path)
{
xo_encoder_setup();
if (path)
xo_string_add(&xo_encoder_path, path);
}
/* ---------------------------------------------------------------------- */
typedef struct xo_encoder_node_s {
TAILQ_ENTRY(xo_encoder_node_s) xe_link; /* Next session */
char *xe_name; /* Name for this encoder */
xo_encoder_func_t xe_handler; /* Callback function */
void *xe_dlhandle; /* dlopen handle */
} xo_encoder_node_t;
typedef TAILQ_HEAD(xo_encoder_list_s, xo_encoder_node_s) xo_encoder_list_t;
#define XO_ENCODER_LIST_FOREACH(_xep, _listp) \
xo_encoder_list_init(_listp); \
TAILQ_FOREACH(_xep, _listp, xe_link)
static xo_encoder_list_t xo_encoders;
static void
xo_encoder_list_init (xo_encoder_list_t *listp)
{
if (listp->tqh_last == NULL)
TAILQ_INIT(listp);
}
static xo_encoder_node_t *
xo_encoder_list_add (const char *name)
{
if (name == NULL)
return NULL;
xo_encoder_node_t *xep = xo_realloc(NULL, sizeof(*xep));
if (xep) {
ssize_t len = strlen(name) + 1;
xep->xe_name = xo_realloc(NULL, len);
if (xep->xe_name == NULL) {
xo_free(xep);
return NULL;
}
memcpy(xep->xe_name, name, len);
TAILQ_INSERT_TAIL(&xo_encoders, xep, xe_link);
}
return xep;
}
void
xo_encoders_clean (void)
{
xo_encoder_node_t *xep;
xo_encoder_setup();
for (;;) {
xep = TAILQ_FIRST(&xo_encoders);
if (xep == NULL)
break;
TAILQ_REMOVE(&xo_encoders, xep, xe_link);
if (xep->xe_dlhandle)
dlclose(xep->xe_dlhandle);
xo_free(xep);
}
xo_string_list_clean(&xo_encoder_path);
}
static void
xo_encoder_setup (void)
{
static int initted;
if (!initted) {
initted = 1;
xo_string_list_init(&xo_encoder_path);
xo_encoder_list_init(&xo_encoders);
xo_encoder_path_add(XO_ENCODERDIR);
}
}
static xo_encoder_node_t *
xo_encoder_find (const char *name)
{
xo_encoder_node_t *xep;
xo_encoder_list_init(&xo_encoders);
XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) {
if (strcmp(xep->xe_name, name) == 0)
return xep;
}
return NULL;
}
static xo_encoder_node_t *
xo_encoder_discover (const char *name)
{
void *dlp = NULL;
char buf[MAXPATHLEN];
xo_string_node_t *xsp;
xo_encoder_node_t *xep = NULL;
XO_STRING_LIST_FOREACH(xsp, &xo_encoder_path) {
static const char fmt[] = "%s/%s.enc";
char *dir = xsp->xs_data;
size_t len = snprintf(buf, sizeof(buf), fmt, dir, name);
if (len > sizeof(buf)) /* Should not occur */
continue;
dlp = dlopen((const char *) buf, RTLD_NOW);
if (dlp)
break;
}
if (dlp) {
/*
* If the library exists, find the initializer function and
* call it.
*/
xo_encoder_init_func_t func;
func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME);
if (func) {
xo_encoder_init_args_t xei;
bzero(&xei, sizeof(xei));
xei.xei_version = XO_ENCODER_VERSION;
ssize_t rc = func(&xei);
if (rc == 0 && xei.xei_handler) {
xep = xo_encoder_list_add(name);
if (xep) {
xep->xe_handler = xei.xei_handler;
xep->xe_dlhandle = dlp;
}
}
}
if (xep == NULL)
dlclose(dlp);
}
return xep;
}
void
xo_encoder_register (const char *name, xo_encoder_func_t func)
{
xo_encoder_setup();
xo_encoder_node_t *xep = xo_encoder_find(name);
if (xep) /* "We alla-ready got one" */
return;
xep = xo_encoder_list_add(name);
if (xep)
xep->xe_handler = func;
}
void
xo_encoder_unregister (const char *name)
{
xo_encoder_setup();
xo_encoder_node_t *xep = xo_encoder_find(name);
if (xep) {
TAILQ_REMOVE(&xo_encoders, xep, xe_link);
xo_free(xep);
}
}
int
xo_encoder_init (xo_handle_t *xop, const char *name)
{
xo_encoder_setup();
/* Can't have names containing '/' or ':' */
if (strchr(name, '/') != NULL || strchr(name, ':') != NULL)
return -1;
/*
* First we look on the list of known (registered) encoders.
* If we don't find it, we follow the set of paths to find
* the encoding library.
*/
xo_encoder_node_t *xep = xo_encoder_find(name);
if (xep == NULL) {
xep = xo_encoder_discover(name);
if (xep == NULL)
return -1;
}
xo_set_encoder(xop, xep->xe_handler);
return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL, 0);
}
/*
* A couple of function varieties here, to allow for multiple
* use cases. This variant is for when the main program knows
* its own encoder needs.
*/
xo_handle_t *
xo_encoder_create (const char *name, xo_xof_flags_t flags)
{
xo_handle_t *xop;
xop = xo_create(XO_STYLE_ENCODER, flags);
if (xop) {
if (xo_encoder_init(xop, name)) {
xo_destroy(xop);
xop = NULL;
}
}
return xop;
}
int
xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op,
const char *name, const char *value, xo_xof_flags_t flags)
{
void *private = xo_get_private(xop);
xo_encoder_func_t func = xo_get_encoder(xop);
if (func == NULL)
return -1;
return func(xop, op, name, value, private, flags);
}
const char *
xo_encoder_op_name (xo_encoder_op_t op)
{
static const char *names[] = {
/* 0 */ "unknown",
/* 1 */ "create",
/* 2 */ "open_container",
/* 3 */ "close_container",
/* 4 */ "open_list",
/* 5 */ "close_list",
/* 6 */ "open_leaf_list",
/* 7 */ "close_leaf_list",
/* 8 */ "open_instance",
/* 9 */ "close_instance",
/* 10 */ "string",
/* 11 */ "content",
/* 12 */ "finish",
/* 13 */ "flush",
/* 14 */ "destroy",
/* 15 */ "attr",
/* 16 */ "version",
};
if (op > sizeof(names) / sizeof(names[0]))
return "unknown";
return names[op];
}

117
0.9.0/libxo/xo_encoder.h Normal file
View File

@ -0,0 +1,117 @@
/*
* 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
*/
/*
* NOTE WELL: This file is needed to software that implements an
* external encoder for libxo that allows libxo data to be encoded in
* new and bizarre formats. General libxo code should _never_
* include this header file.
*/
#ifndef XO_ENCODER_H
#define XO_ENCODER_H
/*
* Expose libxo's memory allocation functions
*/
extern xo_realloc_func_t xo_realloc;
extern xo_free_func_t xo_free;
typedef unsigned xo_encoder_op_t;
/* Encoder operations; names are in xo_encoder.c:xo_encoder_op_name() */
#define XO_OP_UNKNOWN 0
#define XO_OP_CREATE 1 /* Called when the handle is init'd */
#define XO_OP_OPEN_CONTAINER 2
#define XO_OP_CLOSE_CONTAINER 3
#define XO_OP_OPEN_LIST 4
#define XO_OP_CLOSE_LIST 5
#define XO_OP_OPEN_LEAF_LIST 6
#define XO_OP_CLOSE_LEAF_LIST 7
#define XO_OP_OPEN_INSTANCE 8
#define XO_OP_CLOSE_INSTANCE 9
#define XO_OP_STRING 10 /* Quoted UTF-8 string */
#define XO_OP_CONTENT 11 /* Other content */
#define XO_OP_FINISH 12 /* Finish any pending output */
#define XO_OP_FLUSH 13 /* Flush any buffered output */
#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_ENCODER_HANDLER_ARGS \
xo_handle_t *xop __attribute__ ((__unused__)), \
xo_encoder_op_t op __attribute__ ((__unused__)), \
const char *name __attribute__ ((__unused__)), \
const char *value __attribute__ ((__unused__)), \
void *private __attribute__ ((__unused__)), \
xo_xof_flags_t flags __attribute__ ((__unused__))
typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS);
typedef struct xo_encoder_init_args_s {
unsigned xei_version; /* Current version */
xo_encoder_func_t xei_handler; /* Encoding handler */
} xo_encoder_init_args_t;
#define XO_ENCODER_VERSION 1 /* Current version */
#define XO_ENCODER_INIT_ARGS \
xo_encoder_init_args_t *arg __attribute__ ((__unused__))
typedef int (*xo_encoder_init_func_t)(XO_ENCODER_INIT_ARGS);
/*
* Each encoder library must define a function named xo_encoder_init
* that takes the arguments defined in XO_ENCODER_INIT_ARGS. It
* should return zero for success.
*/
#define XO_ENCODER_INIT_NAME_TOKEN xo_encoder_library_init
#define XO_STRINGIFY(_x) #_x
#define XO_STRINGIFY2(_x) XO_STRINGIFY(_x)
#define XO_ENCODER_INIT_NAME XO_STRINGIFY2(XO_ENCODER_INIT_NAME_TOKEN)
extern int XO_ENCODER_INIT_NAME_TOKEN (XO_ENCODER_INIT_ARGS);
void
xo_encoder_register (const char *name, xo_encoder_func_t func);
void
xo_encoder_unregister (const char *name);
void *
xo_get_private (xo_handle_t *xop);
void
xo_encoder_path_add (const char *path);
void
xo_set_private (xo_handle_t *xop, void *opaque);
xo_encoder_func_t
xo_get_encoder (xo_handle_t *xop);
void
xo_set_encoder (xo_handle_t *xop, xo_encoder_func_t encoder);
int
xo_encoder_init (xo_handle_t *xop, const char *name);
xo_handle_t *
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);
void
xo_encoders_clean (void);
const char *
xo_encoder_op_name (xo_encoder_op_t op);
#endif /* XO_ENCODER_H */

84
0.9.0/libxo/xo_err.3 Normal file
View File

@ -0,0 +1,84 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_err , xo_errc , xo_errx
.Nm xo_warn , xo_warnx , xo_warn_c , xo_warn_hc
.Nd emit errors and warnings in multiple output styles
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_warn "const char *fmt" "..."
.Ft void
.Fn xo_warnx "const char *fmt" "..."
.Ft void
.Fn xo_warn_c "int code" "const char *fmt" "..."
.Ft void
.Fn xo_warn_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
.Ft void
.Fn xo_err "int eval" "const char *fmt" "..."
.Ft void
.Fn xo_errc "int eval" "int code" "const char *fmt" "..."
.Ft void
.Fn xo_errx "int eval" "const char *fmt" "..."
.Sh DESCRIPTION
Many programs make use of the standard library functions
.Xr err 3
and
.Xr warn 3
to generate errors and warnings for the user.
.Nm libxo
wants to
pass that information via the current output style, and provides
compatible functions to allow this.
.Pp
The
.Fa fmt
argument is one compatible with
.Xr printf 3
rather than
.Xr xo_emit 3
to aid in simple conversion. This means
these functions make unstructured data.
To generate structured data,
use the
.Xr xo_emit_err 3
functions.
.Pp
These functions display the program name, a colon, a formatted message
based on the arguments, and then optionally a colon and an error
message associated with either
.Fa errno
or the
.Fa code
parameter.
.Bd -literal -offset indent
EXAMPLE:
if (open(filename, O_RDONLY) < 0)
xo_err(1, "cannot open file '%s'", filename);
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr xo_emit_err 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

51
0.9.0/libxo/xo_error.3 Normal file
View File

@ -0,0 +1,51 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_error
.Nd generate simple error messages in multiple output styles
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_error "const char *fmt" "..."
.Sh DESCRIPTION
Use the
.Fn xo_error
function to generate error messages to standard error.
The
.Fa fmt
argument is a string containing printf-style formatting
instructions that describe the remaining arguments.
.Pp
When converting an application to
.Nm libxo ,
one can replace
.Em "fprintf(stderr,...)"
calls with
.Fn xo_error
calls.
.Sh SEE ALSO
.Xr printf 3 ,
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

49
0.9.0/libxo/xo_finish.3 Normal file
View File

@ -0,0 +1,49 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_finish , xo_finish_h
.Nd finish formatting output
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_finish "void"
.Ft void
.Fn xo_finish_h "xo_handle_t *xop"
.Sh DESCRIPTION
When the program is ready to exit or close a handle, a call to
.Fn xo_finish
is required.
This flushes any buffered data, closes
open
.Nm libxo
constructs, and completes any pending operations.
.Pp
Calling this function is
.Em vital
to the proper operation of libxo,
especially for the non-TEXT output styles.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

45
0.9.0/libxo/xo_flush.3 Normal file
View File

@ -0,0 +1,45 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_flush , xo_flush_h
.Nd flush formatted output from libxo handle
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_flush "void"
.Ft void
.Fn xo_flush_h "xo_handle_t *handle"
.Sh DESCRIPTION
.Nm libxo
buffers data, both for performance and consistency, but also to
allow some advanced features to work properly.
At various times, the
caller may wish to flush any data buffered within the library.
The
.Fn xo_flush
function is used for this.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

977
0.9.0/libxo/xo_format.5 Normal file
View File

@ -0,0 +1,977 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_format
.Nd content of format descriptors for xo_emit
.Sh DESCRIPTION
.Pp
.Nm libxo
uses format strings to control the rendering of data into
various output styles, including
.Em text ,
.Em XML ,
.Em JSON ,
and
.Em HTML .
Each format string contains a set of zero or more
.Dq "field descriptions" ,
which describe independent data fields.
Each field description contains a set of
.Dq modifiers ,
a
.Dq "content string" ,
and zero, one, or two
.Dq "format descriptors" .
The modifiers tell
.Nm libxo
what the field is and how to treat it, while the format descriptors are
formatting instructions using
.Xr printf 3 Ns -style
format strings, telling
.Nm libxo
how to format the field.
The field description is placed inside
a set of braces, with a colon
.Ql ( \&: )
after the modifiers and a slash
.Ql ( \&/ )
before each format descriptors.
Text may be intermixed with
field descriptions within the format string.
.Pp
The field description is given as follows:
.Bd -literal -offset indent
\(aq{\(aq [ role | modifier ]* [\(aq,\(aq long\-names ]* \(aq:\(aq [ content ]
[ \(aq/\(aq field\-format [ \(aq/\(aq encoding\-format ]] \(aq}\(aq
.Ed
.Pp
The role describes the function of the field, while the modifiers
enable optional behaviors.
The contents, field\-format, and
encoding\-format are used in varying ways, based on the role.
These are described in the following sections.
.Pp
Braces can be escaped by using double braces, similar to "%%" in
.Xr printf 3 .
The format string "{{braces}}" would emit "{braces}".
.Pp
In the following example, three field descriptors appear.
The first
is a padding field containing three spaces of padding, the second is a
label ("In stock"), and the third is a value field ("in\-stock").
The in\-stock field has a "%u" format that will parse the next argument
passed to the
.Xr xo_emit 3 ,
function as an unsigned integer.
.Bd -literal -offset indent
xo_emit("{P: }{Lwc:In stock}{:in\-stock/%u}\\n", 65);
.Ed
.Pp
This single line of code can generate text ("In stock: 65\\n"), XML
("<in\-stock>65</in\-stock>"), JSON (\(aq"in\-stock": 65\(aq), or HTML (too
lengthy to be listed here).
.Pp
While roles and modifiers typically use single character for brevity,
there are alternative names for each which allow more verbose
formatting strings.
These names must be preceded by a comma, and may follow any
single\-character values:
.Bd -literal -offset indent
xo_emit("{L,white,colon:In stock}{,key:in\-stock/%u}\\n", 65);
.Ed
.Ss "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:
.Bl -column "M" "Name12341234"
.It Sy "M" "Name " "Description"
.It C "color " "Field is a color or effect"
.It D "decoration " "Field is non\-text (e.g. colon, comma)"
.It E "error " "Field is an error message"
.It L "label " "Field is text that prefixes a value"
.It N "note " "Field is text that follows a value"
.It P "padding " "Field is spaces needed for vertical alignment"
.It T "title " "Field is a title value for headings"
.It U "units " "Field is the units for the previous value field"
.It V "value " "Field is the name of field (the default)"
.It W "warning " "Field is a warning message"
.It \&[ "start\-anchor" "Begin a section of anchored variable\-width text"
.It \&] "stop\-anchor " "End a section of anchored variable\-width text"
.El
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{L:Free}{D::}{P: }{:free/%u} {U:Blocks}\\n",
free_blocks);
.Ed
.Pp
When a role is not provided, the "value" role is used as the default.
.Pp
Roles and modifiers can also use more verbose names, when preceded by
a comma:
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{,label:Free}{,decoration::}{,padding: }"
"{,value:free/%u} {,units:Blocks}\\n",
free_blocks);
.Ed
.Ss "The Color Role ({C:})"
Colors and effects control how text values are displayed; they are
used for display styles (TEXT and HTML).
.Bd -literal -offset indent
xo_emit("{C:bold}{:value}{C:no\-bold}\\n", value);
.Ed
.Pp
Colors and effects remain in effect until modified by other "C"\-role
fields.
.Bd -literal -offset indent
xo_emit("{C:bold}{C:inverse}both{C:no\-bold}only inverse\\n");
.Ed
.Pp
If the content is empty, the "reset" action is performed.
.Bd -literal -offset indent
xo_emit("{C:both,underline}{:value}{C:}\\n", value);
.Ed
.Pp
The content should be a comma\-separated list of zero or more colors or
display effects.
.Bd -literal -offset indent
xo_emit("{C:bold,underline,inverse}All three{C:no\-bold,no\-inverse}\\n");
.Ed
.Pp
The color content can be either static, when placed directly within
the field descriptor, or a printf\-style format descriptor can be used,
if preceded by a slash ("/"):
.Bd -literal -offset indent
xo_emit("{C:/%s%s}{:value}{C:}", need_bold ? "bold" : "",
need_underline ? "underline" : "", value);
.Ed
.Pp
Color names are prefixed with either "fg\-" or "bg\-" to change the
foreground and background colors, respectively.
.Bd -literal -offset indent
xo_emit("{C:/fg\-%s,bg\-%s}{Lwc:Cost}{:cost/%u}{C:reset}\\n",
fg_color, bg_color, cost);
.Ed
.Pp
The following table lists the supported effects:
.Bl -column "no\-underline"
.It Sy "Name " "Description"
.It "bg\-xxxxx " "Change background color"
.It "bold " "Start bold text effect"
.It "fg\-xxxxx " "Change foreground color"
.It "inverse " "Start inverse (aka reverse) text effect"
.It "no\-bold " "Stop bold text effect"
.It "no\-inverse " "Stop inverse (aka reverse) text effect"
.It "no\-underline " "Stop underline text effect"
.It "normal " "Reset effects (only)"
.It "reset " "Reset colors and effects (restore defaults)"
.It "underline " "Start underline text effect"
.El
.Pp
The following color names are supported:
.Bl -column "no\-underline"
.It Sy "Name"
.It black
.It blue
.It cyan
.It default
.It green
.It magenta
.It red
.It white
.It yellow
.El
.Ss "The Decoration Role ({D:})"
Decorations are typically punctuation marks such as colons,
semi\-colons, and commas used to decorate the text and make it simpler
for human readers.
By marking these distinctly, HTML usage scenarios
can use CSS to direct their display parameters.
.Bd -literal -offset indent
xo_emit("{D:((}{:name}{D:))}\\n", name);
.Ed
.Ss "The Gettext Role ({G:})"
.Nm libxo
supports internationalization (i18n) through its use of
.Xr gettext 3 .
Use the "{G:}" role to request that the remaining part of
the format string, following the "{G:}" field, be handled using
.Fn gettext .
Since
.Fn gettext
uses the string as the key into the message catalog,
.Nm libxo
uses a simplified version of the format string that removes
unimportant field formatting and modifiers, stopping minor formatting
changes from impacting the expensive translation process.
A developer
change such as changing "/%06d" to "/%08d" should not force hand
inspection of all .po files.
.Pp
The simplified version can be generated for a single message using the
"xopo \-s <text>" command, or an entire .pot can be translated using
the "xopo \-f <input> \-o <output>" command.
.Bd -literal -offset indent
xo_emit("{G:}Invalid token\\n");
.Ed
.Pp
The {G:} role allows a domain name to be set.
.Fn gettext
calls will
continue to use that domain name until the current format string
processing is complete, enabling a library function to emit strings
using it\(aqs own catalog.
The domain name can be either static as the
content of the field, or a format can be used to get the domain name
from the arguments.
.Bd -literal -offset indent
xo_emit("{G:libc}Service unavailable in restricted mode\\n");
.Ed
.Ss "The Label Role ({L:})"
Labels are text that appears before a value.
.Bd -literal -offset indent
xo_emit("{Lwc:Cost}{:cost/%u}\\n", cost);
.Ed
.Ss "The Note Role ({N:})"
Notes are text that appears after a value.
.Bd -literal -offset indent
xo_emit("{:cost/%u} {N:per year}\\n", cost);
.Ed
.Ss "The Padding Role ({P:})"
Padding represents whitespace used before and between fields.
The padding content can be either static, when placed directly within
the field descriptor, or a printf\-style format descriptor can be used,
if preceded by a slash ("/"):
.Bd -literal -offset indent
xo_emit("{P: }{Lwc:Cost}{:cost/%u}\\n", cost);
xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\\n", "", cost);
.Ed
.Ss "The Title Role ({T:})"
Titles are heading or column headers that are meant to be displayed to
the user.
The title can be either static, when placed directly within
the field descriptor, or a printf\-style format descriptor can be used,
if preceded by a slash ("/"):
.Bd -literal -offset indent
xo_emit("{T:Interface Statistics}\\n");
xo_emit("{T:/%20.20s}{T:/%6.6s}\\n", "Item Name", "Cost");
.Ed
.Ss "The Units Role ({U:})"
Units are the dimension by which values are measured, such as degrees,
miles, bytes, and decibels.
The units field carries this information
for the previous value field.
.Bd -literal -offset indent
xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\\n", miles);
.Ed
.Pp
Note that the sense of the \(aqw\(aq modifier is reversed for units;
a blank is added before the contents, rather than after it.
.Pp
When the
.Dv XOF_UNITS
flag is set, units are rendered in XML as the
.Dq units
attribute:
.Bd -literal -offset indent
<distance units="miles">50</distance>
.Ed
.Pp
Units can also be rendered in HTML as the "data\-units" attribute:
.Bd -literal -offset indent
<div class="data" data\-tag="distance" data\-units="miles"
data\-xpath="/top/data/distance">50</div>
.Ed
.Ss "The Value Role ({V:} and {:})"
The value role is used to represent the a data value that is
interesting for the non\-display output styles (XML and JSON).
Value
is the default role; if no other role designation is given, the field
is a value.
The field name must appear within the field descriptor,
followed by one or two format descriptors.
The first format
descriptor is used for display styles (TEXT and HTML), while the
second one is used for encoding styles (XML and JSON).
If no second
format is given, the encoding format defaults to the first format,
with any minimum width removed.
If no first format is given, both
format descriptors default to "%s".
.Bd -literal -offset indent
xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\\n",
length, width, height);
xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\\n,
author, poem, year);
.Ed
.Ss "The Anchor Roles ({[:} and {]:})"
The anchor roles allow a set of strings by be padded as a group,
but still be visible to
.Xr xo_emit 3
as distinct fields.
Either the start
or stop anchor can give a field width and it can be either directly in
the descriptor or passed as an argument.
Any fields between the start
and stop anchor are padded to meet the minimum width given.
.Pp
To give a width directly, encode it as the content of the anchor tag:
.Bd -literal -offset indent
xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\\n", min, max);
.Ed
.Pp
To pass a width as an argument, use "%d" as the format, which must
appear after the "/".
Note that only "%d" is supported for widths.
Using any other value could ruin your day.
.Bd -literal -offset indent
xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\\n", width, min, max);
.Ed
.Pp
If the width is negative, padding will be added on the right, suitable
for left justification.
Otherwise the padding will be added to the
left of the fields between the start and stop anchors, suitable for
right justification.
If the width is zero, nothing happens.
If the
number of columns of output between the start and stop anchors is less
than the absolute value of the given width, nothing happens.
.Pp
Widths over 8k are considered probable errors and not supported.
If
.Dv XOF_WARN
is set, a warning will be generated.
.Ss "Field Modifiers"
Field modifiers are flags which modify the way content emitted for
particular output styles:
.Bl -column M "Name123456789"
.It Sy M "Name " "Description"
.It a "argument " "The content appears as a ""const char *"" argument"
.It c "colon " "A colon ("":"") is appended after the label"
.It d "display " "Only emit field for display styles (text/HTML)"
.It e "encoding " "Only emit for encoding styles (XML/JSON)"
.It h "humanize (hn) " "Format large numbers in human\-readable style"
.It " " "hn\-space " "Humanize: Place space between numeric and unit"
.It " " "hn\-decimal " "Humanize: Add a decimal digit, if number < 10"
.It " " "hn\-1000 " "Humanize: Use 1000 as divisor instead of 1024"
.It k "key " "Field is a key, suitable for XPath predicates"
.It l "leaf\-list " "Field is a leaf\-list, a list of leaf values"
.It n "no\-quotes " "Do not quote the field when using JSON style"
.It q "quotes " "Quote the field when using JSON style"
.It t "trim " "Trim leading and trailing whitespace"
.It w "white space " "A blank ("" "") is appended after the label"
.El
.Pp
For example, the modifier string "Lwc" means the field has a label
role (text that describes the next field) and should be followed by a
colon (\(aqc\(aq) and a space (\(aqw\(aq).
The modifier string "Vkq" means the
field has a value role, that it is a key for the current instance, and
that the value should be quoted when encoded for JSON.
.Pp
Roles and modifiers can also use more verbose names, when preceded by
a comma.
For example, the modifier string "Lwc" (or "L,white,colon")
means the field has a label role (text that describes the next field)
and should be followed by a colon (\(aqc\(aq) and a space (\(aqw\(aq).
The modifier string "Vkq" (or ":key,quote") means the field has a value
role (the default role), that it is a key for the current instance,
and that the value should be quoted when encoded for JSON.
.Ss "The Argument Modifier ({a:})"
The argument modifier indicates that the content of the field
descriptor will be placed as a UTF\-8 string (const char *) argument
within the xo_emit parameters.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{La:} {a:}\\n", "Label text", "label", "value");
TEXT:
Label text value
JSON:
"label": "value"
XML:
<label>value</label>
.Ed
.Pp
The argument modifier allows field names for value fields to be passed
on the stack, avoiding the need to build a field descriptor using
.Xr snprintf 1 .
For many field roles, the argument modifier is not needed,
since those roles have specific mechanisms for arguments,
such as "{C:fg\-%s}".
.Ss "The Colon Modifier ({c:})"
The colon modifier appends a single colon to the data value:
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{Lc:Name}{:name}\\n", "phil");
TEXT:
Name:phil
.Ed
.Pp
The colon modifier is only used for the TEXT and HTML output
styles.
It is commonly combined with the space modifier (\(aq{w:}\(aq).
It is purely a convenience feature.
.Ss "The Display Modifier ({d:})"
The display modifier indicated the field should only be generated for
the display output styles, TEXT and HTML.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{Lcw:Name}{d:name} {:id/%d}\\n", "phil", 1);
TEXT:
Name: phil 1
XML:
<id>1</id>
.Ed
.Pp
The display modifier is the opposite of the encoding modifier, and
they are often used to give to distinct views of the underlying data.
.Ss "The Encoding Modifier ({e:})"
The encoding modifier indicated the field should only be generated for
the encoding output styles, such as JSON and XML.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{Lcw:Name}{:name} {e:id/%d}\\n", "phil", 1);
TEXT:
Name: phil
XML:
<name>phil</name><id>1</id>
.Ed
.Pp
The encoding modifier is the opposite of the display modifier, and
they are often used to give to distinct views of the underlying data.
.Ss "The Humanize Modifier ({h:})"
The humanize modifier is used to render large numbers as in a
human\-readable format.
While numbers like "44470272" are completely readable to computers and
savants, humans will generally find "44M" more meaningful.
.Pp
"hn" can be used as an alias for "humanize".
.Pp
The humanize modifier only affects display styles (TEXT and HMTL).
The "no\-humanize" option will block the function of the humanize modifier.
.Pp
There are a number of modifiers that affect details of humanization.
These are only available in as full names, not single characters.
The "hn\-space" modifier places a space between the number and any
multiplier symbol, such as "M" or "K" (ex: "44 K").
The "hn\-decimal" modifier will add a decimal point and a single tenths digit
when the number is less than 10 (ex: "4.4K").
The "hn\-1000" modifier will use 1000 as divisor instead of 1024, following the
JEDEC\-standard instead of the more natural binary powers\-of\-two
tradition.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{h:input/%u}, {h,hn\-space:output/%u}, "
"{h,hn\-decimal:errors/%u}, {h,hn\-1000:capacity/%u}, "
"{h,hn\-decimal:remaining/%u}\\n",
input, output, errors, capacity, remaining);
TEXT:
21, 57 K, 96M, 44M, 1.2G
.Ed
.Pp
In the HTML style, the original numeric value is rendered in the
"data\-number" attribute on the <div> element:
.Bd -literal -offset indent
<div class="data" data\-tag="errors"
data\-number="100663296">96M</div>
.Ed
.Ss "The Gettext Modifier ({g:})"
The gettext modifier is used to translate individual fields using the
gettext domain (typically set using the "{G:}" role) and current
language settings.
Once libxo renders the field value, it is passed
to
.Xr gettext 3 ,
where it is used as a key to find the native language
translation.
.Pp
In the following example, the strings "State" and "full" are passed
to
.Fn gettext
to find locale\-based translated strings.
.Bd -literal -offset indent
xo_emit("{Lgwc:State}{g:state}\\n", "full");
.Ed
.Ss "The Key Modifier ({k:})"
The key modifier is used to indicate that a particular field helps
uniquely identify an instance of list data.
.Bd -literal -offset indent
EXAMPLE:
xo_open_list("user");
for (i = 0; i < num_users; i++) {
xo_open_instance("user");
xo_emit("User {k:name} has {:count} tickets\\n",
user[i].u_name, user[i].u_tickets);
xo_close_instance("user");
}
xo_close_list("user");
.Ed
.Pp
Currently the key modifier is only used when generating XPath values
for the HTML output style when
.Dv XOF_XPATH
is set, but other uses are likely in the near future.
.Ss "The Leaf\-List Modifier ({l:})"
The leaf\-list modifier is used to distinguish lists where each
instance consists of only a single value. In XML, these are
rendered as single elements, where JSON renders them as arrays.
.Bd -literal -offset indent
EXAMPLE:
xo_open_list("user");
for (i = 0; i < num_users; i++) {
xo_emit("Member {l:name}\\n", user[i].u_name);
}
xo_close_list("user");
XML:
<user>phil</user>
<user>pallavi</user>
JSON:
"user": [ "phil", "pallavi" ]
.Ed
.Ss "The No\-Quotes Modifier ({n:})"
The no\-quotes modifier (and its twin, the \(aqquotes\(aq modifier) affect
the quoting of values in the JSON output style.
JSON uses quotes for
string values, but no quotes for numeric, boolean, and null data.
.Xr xo_emit 3
applies a simple heuristic to determine whether quotes are
needed, but often this needs to be controlled by the caller.
.Bd -literal -offset indent
EXAMPLE:
const char *bool = is_true ? "true" : "false";
xo_emit("{n:fancy/%s}", bool);
JSON:
"fancy": true
.Ed
.Ss "The Plural Modifier ({p:})"
The plural modifier selects the appropriate plural form of an
expression based on the most recent number emitted and the current
language settings.
The contents of the field should be the singular
and plural English values, separated by a comma:
.Bd -literal -offset indent
xo_emit("{:bytes} {Ngp:byte,bytes}\\n", bytes);
.Ed
.Pp
The plural modifier is meant to work with the gettext modifier ({g:})
but can work independently.
.Pp
When used without the gettext modifier or when the message does not
appear in the message catalog, the first token is chosen when the last
numeric value is equal to 1; otherwise the second value is used,
mimicking the simple pluralization rules of English.
.Pp
When used with the gettext modifier, the
.Xr ngettext 3
function is
called to handle the heavy lifting, using the message catalog to
convert the singular and plural forms into the native language.
.Ss "The Quotes Modifier ({q:})"
The quotes modifier (and its twin, the \(aqno-quotes\(aq modifier) affect
the quoting of values in the JSON output style.
JSON uses quotes for
string values, but no quotes for numeric, boolean, and null data.
.Xr xo_emit 3
applies a simple heuristic to determine whether quotes are
needed, but often this needs to be controlled by the caller.
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{q:time/%d}", 2014);
JSON:
"year": "2014"
.Ed
.Ss "The White Space Modifier ({w:})"
The white space modifier appends a single space to the data value:
.Bd -literal -offset indent
EXAMPLE:
xo_emit("{Lw:Name}{:name}\\n", "phil");
TEXT:
Name phil
.Ed
.Pp
The white space modifier is only used for the TEXT and HTML output
styles.
It is commonly combined with the colon modifier (\(aq{c:}\(aq).
It is purely a convenience feature.
.Pp
Note that the sense of the \(aqw\(aq modifier is reversed for the units role
({Uw:}); a blank is added before the contents, rather than after it.
.Ss "Field Formatting"
The field format is similar to the format string for
.Xr printf 3 .
Its use varies based on the role of the field, but generally is used to
format the field\(aqs contents.
.Pp
If the format string is not provided for a value field, it defaults
to "%s".
.Pp
Note a field definition can contain zero or more printf\-style
.Dq directives ,
which are sequences that start with a \(aq%\(aq and end with
one of following characters: "diouxXDOUeEfFgGaAcCsSp".
Each directive
is matched by one of more arguments to the
.Xr xo_emit 3
function.
.Pp
The format string has the form:
.Bd -literal -offset indent
\(aq%\(aq format\-modifier * format\-character
.Ed
.Pp
The format\-modifier can be:
.Bl -bullet
.It
a \(aq#\(aq character, indicating the output value should be prefixed with
"0x", typically to indicate a base 16 (hex) value.
.It
a minus sign (\(aq\-\(aq), indicating the output value should be padded on
the right instead of the left.
.It
a leading zero (\(aq0\(aq) indicating the output value should be padded on the
left with zeroes instead of spaces (\(aq \(aq).
.It
one or more digits (\(aq0\(aq \- \(aq9\(aq) indicating the minimum width of the
argument.
If the width in columns of the output value is less than
the minimum width, the value will be padded to reach the minimum.
.It
a period followed by one or more digits indicating the maximum
number of bytes which will be examined for a string argument, or the maximum
width for a non\-string argument.
When handling ASCII strings this
functions as the field width but for multi\-byte characters, a single
character may be composed of multiple bytes.
.Xr xo_emit 3
will never dereference memory beyond the given number of bytes.
.It
a second period followed by one or more digits indicating the maximum
width for a string argument.
This modifier cannot be given for non\-string arguments.
.It
one or more \(aqh\(aq characters, indicating shorter input data.
.It
one or more \(aql\(aq characters, indicating longer input data.
.It
a \(aqz\(aq character, indicating a \(aqsize_t\(aq argument.
.It
a \(aqt\(aq character, indicating a \(aqptrdiff_t\(aq argument.
.It
a \(aq \(aq character, indicating a space should be emitted before
positive numbers.
.It
a \(aq+\(aq character, indicating sign should emitted before any number.
.El
.Pp
Note that \(aqq\(aq, \(aqD\(aq, \(aqO\(aq, and \(aqU\(aq are considered deprecated and will be
removed eventually.
.Pp
The format character is described in the following table:
.Bl -column C "Argument Type12"
.It Sy "C" "Argument Type " "Format"
.It d "int " "base 10 (decimal)"
.It i "int " "base 10 (decimal)"
.It o "int " "base 8 (octal)"
.It u "unsigned " "base 10 (decimal)"
.It x "unsigned " "base 16 (hex)"
.It X "unsigned long " "base 16 (hex)"
.It D "long " "base 10 (decimal)"
.It O "unsigned long " "base 8 (octal)"
.It U "unsigned long " "base 10 (decimal)"
.It e "double " "[\-]d.ddde+\-dd"
.It E "double " "[\-]d.dddE+\-dd"
.It f "double " "[\-]ddd.ddd"
.It F "double " "[\-]ddd.ddd"
.It g "double " "as \(aqe\(aq or \(aqf\(aq"
.It G "double " "as \(aqE\(aq or \(aqF\(aq"
.It a "double " "[\-]0xh.hhhp[+\-]d"
.It A "double " "[\-]0Xh.hhhp[+\-]d"
.It c "unsigned char " "a character"
.It C "wint_t " "a character"
.It s "char * " "a UTF\-8 string"
.It S "wchar_t * " "a unicode/WCS string"
.It p "void * " "\(aq%#lx\(aq"
.El
.Pp
The \(aqh\(aq and \(aql\(aq modifiers affect the size and treatment of the
argument:
.Bl -column "Mod" "d, i " "o, u, x, X "
.It Sy "Mod" "d, i " "o, u, x, X"
.It "hh " "signed char " "unsigned char"
.It "h " "short " "unsigned short"
.It "l " "long " "unsigned long"
.It "ll " "long long " "unsigned long long"
.It "j " "intmax_t " "uintmax_t"
.It "t " "ptrdiff_t " "ptrdiff_t"
.It "z " "size_t " "size_t"
.It "q " "quad_t " "u_quad_t"
.El
.Ss "UTF\-8 and Locale Strings"
All strings for
.Nm libxo
must be UTF\-8.
.Nm libxo
will handle turning them
into locale\-based strings for display to the user.
.Pp
For strings, the \(aqh\(aq and \(aql\(aq modifiers affect the interpretation of
the bytes pointed to argument.
The default \(aq%s\(aq string is a \(aqchar *\(aq
pointer to a string encoded as UTF\-8.
Since UTF\-8 is compatible with
.Em ASCII
data, a normal 7\-bit
.Em ASCII
string can be used.
"%ls" expects a
"wchar_t *" pointer to a wide\-character string, encoded as 32\-bit
Unicode values.
"%hs" expects a "char *" pointer to a multi\-byte
string encoded with the current locale, as given by the
.Ev LC_CTYPE ,
.Ev LANG ,
or
.Ev LC_ALL
environment variables.
The first of this list of
variables is used and if none of the variables are set, the locale defaults to
.Em UTF\-8 .
.Pp
.Nm libxo
will
convert these arguments as needed to either UTF\-8 (for XML, JSON, and
HTML styles) or locale\-based strings for display in text style.
.Bd -literal -offset indent
xo_emit("All strings are utf\-8 content {:tag/%ls}",
L"except for wide strings");
.Ed
.Pp
"%S" is equivalent to "%ls".
.Pp
For example, a function is passed a locale\-base name, a hat size,
and a time value.
The hat size is formatted in a UTF\-8 (ASCII)
string, and the time value is formatted into a wchar_t string.
.Bd -literal -offset indent
void print_order (const char *name, int size,
struct tm *timep) {
char buf[32];
const char *size_val = "unknown";
if (size > 0)
snprintf(buf, sizeof(buf), "%d", size);
size_val = buf;
}
wchar_t when[32];
wcsftime(when, sizeof(when), L"%d%b%y", timep);
xo_emit("The hat for {:name/%hs} is {:size/%s}.\\n",
name, size_val);
xo_emit("It was ordered on {:order\-time/%ls}.\\n",
when);
}
.Ed
.Pp
It is important to note that
.Xr xo_emit 3
will perform the conversion
required to make appropriate output.
Text style output uses the
current locale (as described above), while XML, JSON, and HTML use
UTF\-8.
.Pp
UTF\-8 and locale\-encoded strings can use multiple bytes to encode one
column of data.
The traditional "precision" (aka "max\-width") value
for "%s" printf formatting becomes overloaded since it specifies both
the number of bytes that can be safely referenced and the maximum
number of columns to emit.
.Xr xo_emit 3
uses the precision as the former,
and adds a third value for specifying the maximum number of columns.
.Pp
In this example, the name field is printed with a minimum of 3 columns
and a maximum of 6.
Up to ten bytes are in used in filling those columns.
.Bd -literal -offset indent
xo_emit("{:name/%3.10.6s}", name);
.Ed
.Ss "Characters Outside of Field Definitions"
Characters in the format string that are not part of a field definition are
copied to the output for the TEXT style, and are ignored for the JSON
and XML styles.
For HTML, these characters are placed in a <div> with class "text".
.Bd -literal -offset indent
EXAMPLE:
xo_emit("The hat is {:size/%s}.\\n", size_val);
TEXT:
The hat is extra small.
XML:
<size>extra small</size>
JSON:
"size": "extra small"
HTML:
<div class="text">The hat is </div>
<div class="data" data\-tag="size">extra small</div>
<div class="text">.</div>
.Ed
.Ss "\(aq%n\(aq is Not Supported"
.Nm libxo
does not support the \(aq%n\(aq directive.
It is a bad idea and we
just do not do it.
.Ss "The Encoding Format (eformat)"
The "eformat" string is the format string used when encoding the field
for JSON and XML.
If not provided, it defaults to the primary format
with any minimum width removed.
If the primary is not given, both default to "%s".
.Sh EXAMPLE
In this example, the value for the number of items in stock is emitted:
.Bd -literal -offset indent
xo_emit("{P: }{Lwc:In stock}{:in\-stock/%u}\\n",
instock);
.Ed
.Pp
This call will generate the following output:
.Bd -literal -offset indent
TEXT:
In stock: 144
XML:
<in\-stock>144</in\-stock>
JSON:
"in\-stock": 144,
HTML:
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data\-tag="in\-stock">144</div>
</div>
.Ed
.Pp
Clearly HTML wins the verbosity award, and this output does
not include
.Dv XOF_XPATH
or
.Dv XOF_INFO
data, which would expand the penultimate line to:
.Bd -literal -offset indent
<div class="data" data\-tag="in\-stock"
data\-xpath="/top/data/item/in\-stock"
data\-type="number"
data\-help="Number of items in stock">144</div>
.Ed
.Sh WHAT MAKES A GOOD FIELD NAME?
To make useful, consistent field names, follow these guidelines:
.Ss "Use lower case, even for TLAs"
Lower case is more civilized.
Even TLAs should be lower case
to avoid scenarios where the differences between "XPath" and
"Xpath" drive your users crazy.
Using "xpath" is simpler and better.
.Ss "Use hyphens, not underscores"
Use of hyphens is traditional in XML, and the
.Dv XOF_UNDERSCORES
flag can be used to generate underscores in JSON, if desired.
But the raw field name should use hyphens.
.Ss "Use full words"
Do not abbreviate especially when the abbreviation is not obvious or
not widely used.
Use "data\-size", not "dsz" or "dsize".
Use
"interface" instead of "ifname", "if\-name", "iface", "if", or "intf".
.Ss "Use <verb>\-<units>"
Using the form <verb>\-<units> or <verb>\-<classifier>\-<units> helps in
making consistent, useful names, avoiding the situation where one app
uses "sent\-packet" and another "packets\-sent" and another
"packets\-we\-have\-sent".
The <units> can be dropped when it is
obvious, as can obvious words in the classification.
Use "receive\-after\-window\-packets" instead of
"received\-packets\-of\-data\-after\-window".
.Ss "Reuse existing field names"
Nothing is worse than writing expressions like:
.Bd -literal -offset indent
if ($src1/process[pid == $pid]/name ==
$src2/proc\-table/proc/p[process\-id == $pid]/proc\-name) {
...
}
.Ed
.Pp
Find someone else who is expressing similar data and follow their
fields and hierarchy.
Remember the quote is not
.Dq "Consistency is the hobgoblin of little minds"
but
.Dq "A foolish consistency is the hobgoblin of little minds" .
.Ss "Think about your users"
Have empathy for your users, choosing clear and useful fields that
contain clear and useful data.
You may need to augment the display content with
.Xr xo_attr 3
calls or "{e:}" fields to make the data useful.
.Ss "Do not use an arbitrary number postfix"
What does "errors2" mean?
No one will know.
"errors\-after\-restart" would be a better choice.
Think of your users, and think of the future.
If you make "errors2", the next guy will happily make
"errors3" and before you know it, someone will be asking what is the
difference between errors37 and errors63.
.Ss "Be consistent, uniform, unsurprising, and predictable"
Think of your field vocabulary as an API.
You want it useful,
expressive, meaningful, direct, and obvious.
You want the client
application\(aqs programmer to move between without the need to
understand a variety of opinions on how fields are named.
They should
see the system as a single cohesive whole, not a sack of cats.
.Pp
Field names constitute the means by which client programmers interact
with our system.
By choosing wise names now, you are making their lives better.
.Pp
After using
.Xr xolint 1
to find errors in your field descriptors, use
.Dq "xolint \-V"
to spell check your field names and to detect different
names for the same data.
.Dq dropped\-short
and
.Dq dropped\-too\-short
are both reasonable names, but using them both will lead users to ask the
difference between the two fields.
If there is no difference,
use only one of the field names.
If there is a difference, change the
names to make that difference more obvious.
.Sh SEE ALSO
.Xr libxo 3 ,
.Xr xolint 1 ,
.Xr xo_emit 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

169
0.9.0/libxo/xo_humanize.h Normal file
View File

@ -0,0 +1,169 @@
/* $NetBSD: humanize_number.c,v 1.8 2004/07/27 01:56:24 enami Exp $ */
/*
* Copyright (c) 1997, 1998, 1999, 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center, by Luke Mewburn and by Tomas Svensson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <locale.h>
#include <stdint.h>
#include <limits.h>
#include <unistd.h>
#include <stdbool.h>
/* humanize_number(3) */
#define HN_DECIMAL 0x01
#define HN_NOSPACE 0x02
#define HN_B 0x04
#define HN_DIVISOR_1000 0x08
#define HN_GETSCALE 0x10
#define HN_AUTOSCALE 0x20
static int
xo_humanize_number (char *buf, size_t len, int64_t bytes,
const char *suffix, int scale, int flags)
{
const char *prefixes, *sep;
int b, i, r, maxscale, s1, s2, sign;
int64_t divisor, max;
// We multiply bytes by 100 to deal with rounding, so we need something
// big enough to hold LLONG_MAX * 100. On 64-bit we can use 128-bit wide
// integers with __int128_t, but on 32-bit we have to use long double.
#ifdef __LP64__
__int128_t scalable = (__int128_t)bytes;
#else
long double scalable = (long double)bytes;
#endif
size_t baselen;
assert(buf != NULL);
assert(suffix != NULL);
assert(scale >= 0);
if (flags & HN_DIVISOR_1000) {
/* SI for decimal multiplies */
divisor = 1000;
if (flags & HN_B)
prefixes = "B\0k\0M\0G\0T\0P\0E";
else
prefixes = "\0\0k\0M\0G\0T\0P\0E";
} else {
/*
* binary multiplies
* XXX IEC 60027-2 recommends Ki, Mi, Gi...
*/
divisor = 1024;
if (flags & HN_B)
prefixes = "B\0K\0M\0G\0T\0P\0E";
else
prefixes = "\0\0K\0M\0G\0T\0P\0E";
}
#define SCALE2PREFIX(scale) (&prefixes[(scale) << 1])
maxscale = 7;
if (scale >= maxscale &&
(scale & (HN_AUTOSCALE | HN_GETSCALE)) == 0)
return (-1);
if (buf == NULL || suffix == NULL)
return (-1);
if (len > 0)
buf[0] = '\0';
if (bytes < 0) {
sign = -1;
scalable *= -100;
baselen = 3; /* sign, digit, prefix */
} else {
sign = 1;
scalable *= 100;
baselen = 2; /* digit, prefix */
}
if (flags & HN_NOSPACE)
sep = "";
else {
sep = " ";
baselen++;
}
baselen += strlen(suffix);
/* Check if enough room for `x y' + suffix + `\0' */
if (len < baselen + 1)
return (-1);
if (scale & (HN_AUTOSCALE | HN_GETSCALE)) {
/* See if there is additional columns can be used. */
for (max = 100, i = len - baselen; i-- > 0;)
max *= 10;
for (i = 0; scalable >= max && i < maxscale; i++)
scalable /= divisor;
if (scale & HN_GETSCALE)
return (i);
} else
for (i = 0; i < scale && i < maxscale; i++)
scalable /= divisor;
/* If a value <= 9.9 after rounding and ... */
if (scalable < 995 && i > 0 && flags & HN_DECIMAL) {
/* baselen + \0 + .N */
if (len < baselen + 1 + 2)
return (-1);
b = ((int)scalable + 5) / 10;
s1 = b / 10;
s2 = b % 10;
r = snprintf(buf, len, "%s%d%s%d%s%s%s",
((sign == -1) ? "-" : ""),
s1, localeconv()->decimal_point, s2,
sep, SCALE2PREFIX(i), suffix);
} else
r = snprintf(buf, len, "%s%lld%s%s%s",
/* LONGLONG */
((sign == -1) ? "-" : ""),
(long long)((scalable + 50) / 100),
sep, SCALE2PREFIX(i), suffix);
return (r);
}

78
0.9.0/libxo/xo_message.3 Normal file
View File

@ -0,0 +1,78 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_message , xo_message_c , xo_message_hc , xo_message_hcv
.Nd emit messages in multiple output styles
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_message "const char *fmt" "..."
.Ft void
.Fn xo_message_e "const char *fmt" "..."
.Ft void
.Fn xo_message_c "int code" "const char *fmt" "..."
.Ft void
.Fn xo_message_hc "xo_handle_t *xop" "int code, const char *fmt" "..."
.Ft void
.Fn xo_message_hcv "xo_handle_t *xop" "int code" "const char *fmt" "va_list vap"
.Sh DESCRIPTION
.Nm xo_message
generates text message which lack any sort of structure.
These functions should not be used under normal conditions, since
they completely defeat the value of using libxo. They are provided
for scenarios when the output's content is genuinely unknown and
unusable.
It is used in converting programs where err/warn where not used,
and error messages went to
.Nm stdout ,
not
.Nm stderr .
Use of
.Nm xo_message
allows backwards compatibility with that output, but does not put
the error in a useful form.
.Pp
The
.Nm xo_message
function generates output strings using the printf-style format string
and arguments provided.
If the format string does not end in a newline,
.Nm xo_message_e
will appear a colon, a space, and the error associated with the current
.Nm errno
value.
.Nm xo_message_c behaves similarly for the value passed in the
.Fa code
parameter.
.Nm xo_message_hc
accepts a
.Fa handle
as opened by
.Xr xo_create 3
and
.Nm xo_message_hcv accepts a va_list parameter of arguments.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,53 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_no_setlocale
.Nd prevent implicit call to setlocale
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_no_setlocale "void"
.Sh DESCRIPTION
.Nm libxo
automatically initializes the locale based on the setting of the
environment variables
.Ev LC_CTYPE ,
.Ev LANG ,
and
.Ev LC_ALL .
The first of this
list of variables is used and if none of the variables are set, the locale
defaults to
.Em UTF-8 .
The caller may wish to avoid this behavior, and
can do so by calling the
.Fn xo_no_setlocale
function.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr xo_open_container 3 ,
.Xr xo_open_list 3 ,
.Xr xo_format 5 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,198 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_open_container , xo_open_container_h , xo_open_container_hd , xo_open_container_d
.Nm xo_close_container , xo_close_container_h , xo_close_container_hd , xo_close_container_d
.Nd open (and close) container constructs
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_open_container "const char *name"
.Ft int
.Fn xo_open_container_h "xo_handle_t *handle" "const char *name"
.Ft int
.Fn xo_open_container_hd "xo_handle_t *handle" "const char *name"
.Ft int
.Fn xo_open_container_d "const char *name"
.Ft int
.Fn xo_close_container "const char *name"
.Ft int
.Fn xo_close_container_h "xo_handle_t *handle" "const char *name"
.Ft int
.Fn xo_close_container_hd "xo_handle_t *handle"
.Ft int
.Fn xo_close_container_d "void"
.Sh DESCRIPTION
.Nm libxo
represents two types of hierarchy:
.Dq containers
and
.Dq lists .
A container appears once under a given parent where a list contains
instances that can appear multiple times.
A container is used to hold
related fields and to give the data organization and scope.
The container has no value, but serves to
contain other nodes.
.Pp
To open a container, call
.Fn xo_open_container
or
.Fn xo_open_container_h .
The former uses the default handle and
the latter accepts a specific handle.
.Pp
To close a level, use the
.Fn xo_close_container
or
.Fn xo_close_container_h
functions.
.Pp
Each open call should have a matching close call.
If the
.Dv XOF_WARN
flag is set and the name given does not match the name of
the currently open
container, a warning will be generated.
.Bd -literal -offset indent -compact
Example:
xo_open_container("top");
xo_open_container("system");
xo_emit("{:host-name/%s%s%s", hostname,
domainname ? "." : "", domainname ?: "");
xo_close_container("system");
xo_close_container("top");
Sample Output:
Text:
my-host.example.org
XML:
<top>
<system>
<host-name>my-host.example.org</host-name>
</system>
</top>
JSON:
"top" : {
"system" : {
"host-name": "my-host.example.org"
}
}
HTML:
<div class="data"
data-tag="host-name">my-host.example.org</div>
.Ed
.Sh EMITTING HIERARCHY
To create a container, use the
.Fn xo_open_container
and
.Fn xo_close_container
set of functions.
The
.Fa handle
parameter contains a handle such as returned by
.Xr xo_create 3
or
.Dv NULL
to use the default handle.
The
.Fa name
parameter gives the name of the container, encoded in
.Em UTF-8 .
Since
.Em ASCII
is a proper subset of
.Em UTF-8 ,
traditional C strings can be used directly.
.Pp
The close functions with the
.Dq _d
suffix are used in
.Dq "Do The Right Thing"
mode, where the name of the open containers, lists, and
instances are maintained internally by
.Nm libxo
to allow the caller to
avoid keeping track of the open container name.
.Pp
Use the
.Dv XOF_WARN
flag to generate a warning if the name given on the
close does not match the current open container.
.Pp
For TEXT and HTML output, containers are not rendered into output
text, though for HTML they are used when the
.Dv XOF_XPATH
flag is set.
.Pp
.Bd -literal -offset indent -compact
EXAMPLE:
xo_open_container("system");
xo_emit("The host name is {:host-name}\n", hn);
xo_close_container("system");
XML:
<system><host-name>foo</host-name></system>
.Ed
.Sh DTRT MODE
Some users may find tracking the names of open containers, lists, and
instances inconvenient.
.Nm libxo
offers a
.Dq "Do The Right Thing"
mode, where
.Nm libxo
will track the names of open containers, lists, and instances so
the close function can be called without a name.
To enable
.Em DTRT
mode,
turn on the
.Dv XOF_DTRT
flag prior to making any other
.Nm libxo
output.
.Bd -literal -offset indent -compact
xo_set_flags(NULL, XOF_DTRT);
.Ed
Each open and close function has a version with the suffix
.Dq _d ,
which will close the open container, list, or instance:
.Bd -literal -offset indent -compact
xo_open_container("top");
...
xo_close_container_d();
.Ed
Note that the
.Dv XOF_WARN
flag will also cause
.Nm libxo
to track open
containers, lists, and instances.
A warning is generated when the name given to the close function
and the name recorded do not match.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

168
0.9.0/libxo/xo_open_list.3 Normal file
View File

@ -0,0 +1,168 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_open_list , xo_open_list_h , xo_open_list_hd , xo_open_list_d
.Nm xo_open_instance , xo_open_instance_h , xo_open_instance_hd , xo_open_instance_d
.Nm xo_close_instance , xo_close_instance_h , xo_close_instance_hd , xo_close_instance_d
.Nm xo_close_list , xo_close_list_h , xo_close_list_hd , xo_close_list_d
.Nd open and close lists and instances
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_open_list_h "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_open_list "const char *name"
.Ft int
.Fn xo_open_list_hd "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_open_list_d "const char *name"
.Ft int
.Fn xo_open_instance_h "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_open_instance "const char *name"
.Ft int
.Fn xo_open_instance_hd "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_open_instance_d "const char *name"
.Ft int
.Fn xo_close_instance_h "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_close_instance "const char *name"
.Ft int
.Fn xo_close_instance_hd "xo_handle_t *xop"
.Ft int
.Fn xo_close_instance_d "void"
.Ft int
.Fn xo_close_list_h "xo_handle_t *xop" "const char *name"
.Ft int
.Fn xo_close_list "const char *name"
.Ft int
.Fn xo_close_list_hd "xo_handle_t *xop"
.Ft int
.Fn xo_close_list_d "void"
.Sh DESCRIPTION
Lists are sequences of instances of homogeneous data objects.
Two
distinct levels of calls are needed to represent them in our output
styles.
Calls must be made to open and close a list, and for each
instance of data in that list, calls must be make to open and close
that instance.
.Pp
The name given to all calls must be identical, and it is strongly
suggested that the name be singular, not plural, as a matter of
style and usage expectations.
.Pp
A list is a set of one or more instances that appear under the same
parent.
The instances contain details about a specific object.
One can think of instances as objects or records.
A call is needed to
open and close the list, while a distinct call is needed to open and
close each instance of the list:
.Bd -literal -offset indent -compact
xo_open_list("item");
for (ip = list; ip->i_title; ip++) {
xo_open_instance("item");
xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title);
xo_close_instance("item");
}
xo_close_list("item");
.Ed
Getting the list and instance calls correct is critical to the proper
generation of XML and JSON data.
.Pp
.Bd -literal -offset indent -compact
EXAMPLE:
xo_open_list("user");
for (i = 0; i < num_users; i++) {
xo_open_instance("user");
xo_emit("{k:name}:{:uid/%u}:{:gid/%u}:{:home}\n",
pw[i].pw_name, pw[i].pw_uid,
pw[i].pw_gid, pw[i].pw_dir);
xo_close_instance("user");
}
xo_close_list("user");
TEXT:
phil:1001:1001:/home/phil
pallavi:1002:1002:/home/pallavi
XML:
<user>
<name>phil</name>
<uid>1001</uid>
<gid>1001</gid>
<home>/home/phil</home>
</user>
<user>
<name>pallavi</name>
<uid>1002</uid>
<gid>1002</gid>
<home>/home/pallavi</home>
</user>
JSON:
user: [
{
"name": "phil",
"uid": 1001,
"gid": 1001,
"home": "/home/phil",
},
{
"name": "pallavi",
"uid": 1002,
"gid": 1002,
"home": "/home/pallavi",
}
]
.Ed
.Pp
.Sh LEAF LISTS
In contrast to a list of instances, a "leaf list" is list of simple
values.
To emit a leaf list, call the
.Fn xo_emit
function using the ""l"" modifier:
.Bd -literal -offset indent -compact
for (ip = list; ip->i_title; ip++) {
xo_emit("{Lwc:Item}{l:item}\n", ip->i_title);
}
.Ed
.Pp
The name of the field must match the name of the leaf list.
.Pp
In JSON, leaf lists are rendered as arrays of values. In XML, they
are rendered as multiple leaf elements.
.Bd -literal -offset indent -compact
JSON:
"item": "hammer", "nail"
XML:
<item>hammer</item>
<item>nail</item>
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,115 @@
.\" #
.\" # 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
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, January 2015
.\"
.Dd January 22, 2015
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_open_marker , xo_open_marker_h , xo_close_marker , xo_close_marker_h
.Nd prevent and allow closing of open constructs
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_open_marker "const char *name"
.Ft int
.Fn xo_open_marker_h "xo_handle_t *handle" "const char *name"
.Ft int
.Fn xo_close_marker "const char *name"
.Ft int
.Fn xo_close_marker_h "xo_handle_t *handle" "const char *name"
.Sh DESCRIPTION
.Nm libxo
represents hierarchy using two constructs:
.Dq containers
and
.Dq lists .
A marker can be used to affect how open constructs are closed, either
by preventing their (implicit or explicit) closure or by forcing their
closure.
While a marker is open, no other open constructs can be closed.
When a marker is closed, all constructs open since the marker was opened
will be closed.
A marker is used to "freeze" any open constructs.
Calls to
.Fn xo_close_*
functions that would normally close them will be ignored, effectively
blocking their closure.
However when
.Fn xo_close_marker
is called, any containers, lists, or leaf-lists open since the
matching
.Fn xo_open_marker
call will be close and the marker discarded.
Markers use names which are not user-visible, allowing the caller to
choose appropriate internal names.
The marker has no value and is not emitted in any form.
.Pp
To open a marker, call
.Fn xo_open_marker
or
.Fn xo_open_marker_h .
The former uses the default handle and
the latter accepts a specific handle.
.Pp
To close a marker, use the
.Fn xo_close_marker
or
.Fn xo_close_marker_h
functions.
.Pp
Each open call must have a matching close call.
.Pp
In this example, the
.Fn xo_close_container
call on line [1] will be ignored, since the open marker "outer"
will prevent close of any open constructs that precede it.
The
.Fn xo_close_marker
call on line [2] will close the "system" container, since it was
opened after the "outer" marker.
.Bd -literal -offset indent -compact
Example:
xo_open_container("top");
xo_open_marker("outer");
xo_open_container("system");
xo_emit("{:host-name/%s%s%s", hostname,
domainname ? "." : "", domainname ?: "");
xo_close_container("top"); /* [1] */
xo_close_marker("outer"); /* [2] */
xo_close_container("top");
.Ed
.Pp
In this example, the code whiffles through a list of fish, calling a
function to emit details about each fish. The marker "fish-guts" is
used to ensure that any constructs opened by the function are closed
properly.
.Bd -literal -offset indent
for (i = 0; fish[i]; i++) {
xo_open_instance("fish");
xo_open_marker("fish-guts");
dump_fish_details(i);
xo_close_marker("fish-guts");
}
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

156
0.9.0/libxo/xo_options.7 Normal file
View File

@ -0,0 +1,156 @@
.\" #
.\" # Copyright (c) 2014-2017, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd May 11, 2017
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_options
.Nd common options for libxo\-based commands
.Sh DESCRIPTION
.Pp
.Nm libxo
allows the rendering of data into
various output styles, including
.Em text ,
.Em XML ,
.Em JSON ,
and
.Em HTML .
.Nm libxo
uses command line options to trigger rendering behavior.
Options are recognised in three forms:
.Bl -bullet
.It
\-\-libxo <options>
.It
\-\-libxo=<options>
.It
\-\-libxo:<brief\-options>
.El
.Pp
The first two forms accept a comma\-separated set of words, detailed
below, while the third form accepts a set of letters, also below.
The triggered functionality is identical.
.Bl -column "Token2341234"
.It Sy "Option " "Action"
.It "color " "Enable colors/effects for display styles (TEXT, HTML)"
.It "flush " "Flush after each emit call"
.It "flush\-line " "Flush each line of output"
.It "html " "Emit HTML output"
.It "indent=xx " "Set the indentation level"
.It "info " "Add info attributes (HTML)"
.It "json " "Emit JSON output"
.It "keys " "Emit the key attribute for keys (XML)"
.It "log\-gettext" "Log (via stderr) each gettext(3) string lookup"
.It "log\-syslog " "Log (via stderr) each syslog message (via xo_syslog)"
.It "no\-humanize" "Ignore the {h:} modifier (TEXT, HTML)"
.It "no\-locale " "Do not initialize the locale setting"
.It "no\-retain " "Prevent retaining formatting information"
.It "pretty " "Emit pretty\-printed output"
.It "retain " "Force retaining formatting information"
.It "text " "Emit TEXT output"
.It "underscores" "Replace XML\-friendly \"\-\"s with JSON friendly \"_\"s"
.It "units " "Add the 'units' (XML) or 'data\-units (HTML) attribute"
.It "warn " "Emit warnings when libxo detects bad calls"
.It "warn\-xml " "Emit warnings in XML"
.It "xml " "Emit XML output"
.It "xpath " "Add XPath expressions (HTML)"
.El
.Pp
The brief options are a set of single\-letter aliases for the longer
terms, used as a single string:
.Bl -column "Value" "Equivalent Token"
.It Sy "Value" "Equivalent Token"
.It "c
.It "f " "flush"
.It "F " "flush\-line"
.It "H " "html"
.It "I " "info"
.It "i<num>" "indent=<num>"
.It "J " "json"
.It "k " "keys"
.It "n " "no\-humanize"
.It "P " "pretty"
.It "T " "text"
.It "U " "units"
.It "u " "underscore
.It "W " "warn"
.It "X " "xml"
.It "x " "xpath"
.El
.Pp
Most of these option are simple and direct, but some require
additional details:
.Pp
.Fa "flush\-line"
performs line buffering, even when the output is not directed to
a TTY device.
.Pp
.Fa info
generates additional data for HTML, encoded in attributes using
names that state with "data\-".
.Pp
.Fa keys
adds a "key" attribute for XML output to indicate that a leaf is
an identifier for the list member.
.Pp
.Fa no\-humanize
avoids "humanizing" numeric output (see
.Xr humanize_number 3
for details).
.Pp
.Fa no\-locale
instructs
.Nm libxo
to avoid translating output to the current locale.
.Pp
.Fa no\-retain
disables the ability of
.Nm libxo
to internally retain "compiled" information about formatting strings.
.Pp
.Fa underscores
can be used with
.Em JSON
output to change
.Em XML \-friendly
names with dashes into
.Em JSON \-friendly
name with underscores.
.Pp
.Fa warn
allows
.Nm libxo
to emit warnings on stderr when application code make incorrect calls.
.Fa warn\-xml causes those warnings to be placed in
.Em XML
inside the output.
.Sh EXAMPLES
The following are three example invocations of
.Xr ps 1 :
.Bd -literal
ps \-\-libxo json,pretty,warn \-ux
ps \-\-libxo=xml \-lg
ps \-\-libxo:Hxc 1
.Ed
.Sh SEE ALSO
.Xr libxo 3 ,
.Xr xo_format 5
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

162
0.9.0/libxo/xo_parse_args.3 Normal file
View File

@ -0,0 +1,162 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_parse_args , xo_set_program
.Nd detect, parse, and remove arguments for libxo
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_parse_args "int argc" "char **argv"
.Ft int
.Fn xo_set_program "const char *name"
.Sh DESCRIPTION
The
.Fn xo_parse_args
function is used to process command-line arguments.
.Nm libxo
specific
options are processed and removed
from the argument list so the calling application does not
need to process them.
If successful, a new value for argc is returned.
On failure, a message it emitted and -1 is returned.
.Bd -literal -offset indent
argc = xo_parse_args(argc, argv);
if (argc < 0)
exit(EXIT_FAILURE);
.Ed
.Pp
Following the call to
.Fn xo_parse_args ,
the application can process the remaining arguments in a normal manner.
.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 )
.If 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
.If 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
The
.Fn xo_set_program
function sets name of the program as reported by
functions like
.Fn xo_failure ,
.Fn xo_warn ,
.Fn xo_err ,
etc.
The program name is initialized by
.Fn xo_parse_args ,
but subsequent calls to
.Fn xo_set_program
can override this value.
.Pp
Note that the value is not copied, so the memory passed to
.Fn xo_set_program
(and
.Fn xo_parse_args )
must be maintained by the caller.
.Pp
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,64 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_allocator
.Nd set allocation functions for libxo
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Sy typedef void *(*xo_realloc_func_t)(void *, size_t);
.Pp
.Sy typedef void (*xo_free_func_t)(void *);
.Ft void
.Fn xo_set_allocator "xo_realloc_func_t realloc_func" "xo_free_func_t free_func"
.Sh DESCRIPTION
The
.Fn xo_set_allocator
function allows
.Nm libxo
to be used in environments
where the standard
.Xr realloc 3
and
.Xr free 3
functions are not available.
.Pp
.Fa realloc_func
should expect the same arguments as
.Xr realloc 3
and return
a pointer to memory following the same convention.
.Fa free_func
will receive the same argument as
.Xr free 3
and should release it, as appropriate for the environment.
.Pp
By default, the standard
.Xr realloc 3
and
.Xr free 3
functions are used.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

149
0.9.0/libxo/xo_set_flags.3 Normal file
View File

@ -0,0 +1,149 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_flags , xo_clear_flags
.Nd set operational flags for a libxo handle
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_set_flags "xo_handle_t *handle" "unsigned flags"
.Ft void
.Fn xo_clear_flags "xo_handle_t *handle" "xo_xof_flags_t flags"
.Sh DESCRIPTION
Use the
.Fn xo_set_flags
function to set the flags for a
.Nm libxo
handle.
To use the default handle, pass a
.Dv NULL
handle.
.Pp
The set of valid flags include:
.Bl -tag -width "XOF_UNDERSCORES"
.It Sy "Flag Description"
.It Dv XOF_CLOSE_FP
Close file pointer on
.Xr xo_destroy 3 .
This flag will trigger the call of the
.Fn close_func
(provided via
.Xr xo_set_writer 3 )
when the handle is destroyed.
.It Dv XOF_COLOR
Enable color and effects in output regardless of output device.
.It Dv XOF_COLOR_ALLOWED
Allow color and effects if the output device is a terminal.
.It Dv XOF_INFO
Display info data attributes (HTML)
.It Dv XOF_KEYS
Emit the key attribute (XML)
.It Dv XOF_LOG_GETTEXT
Log (via stderr) each
.Xr gettext 3
string lookup
.It Dv XOF_LOG_SYSLOG
Log (via stderr) each syslog message (via
.Xr xo_syslog 3 )
.It Dv XOF_NO_ENV
Do not use the
.Ev LIBXO_OPTIONS
environment variable.
.It Dv XOF_PRETTY
Make 'pretty printed' output, with the
addition of indentation and newlines to enhance the readability of
XML, JSON, and HTML output.
Text output is not affected.
.It Dv XOF_UNDERSCORES
Replaces hyphens with underscores
.It Dv XOF_UNITS
Display units (XML and HMTL)
.It Dv XOF_WARN
Generate warnings for broken calls, triggering diagnostic
output (on standard error) when the library notices errors during
operations, or with arguments to functions.
Without warnings enabled, such conditions are ignored.
Warnings allow developers to debug their interaction with
.Nm libxo .
The function
.Fn xo_failure
can be used as a breakpoint for a debugger,
regardless of whether warnings are enabled.
.It Dv XOF_WARN_XML
Generate warnings in XML on stdout
.It Dv XOF_XPATH
Emit XPath expressions (HTML)
.It Dv XOF_COLUMNS
Force
.Xr xo_emit 3
to return columns used
.It Dv XOF_FLUSH
Flush output after each
.Xr xo_emit 3
call
.El
.Pp
If the style is
.Dv XO_STYLE_HTML ,
the following additional flags can be
used:
.Bl -tag -width "XOF_UNDERSCORES"
.It Sy "Flag Description"
.It Dv XOF_XPATH
Emit "data-xpath" attributes
.It Dv XOF_INFO
Emit additional informational fields for HTML
output.
See
.Xr xo_set_info 3
for details.
.El
.Pp
The
.Dv XOF_XPATH
flag enables the emission of XPath expressions detailing
the hierarchy of XML elements used to encode the data field, if the
XPATH style of output were requested.
.Pp
If the style is
.Dv XO_STYLE_XML ,
the following additional flags can be
used:
.Bl -tag -width "XOF_UNDERSCORES"
.It Sy "Flag Description"
.It XOF_KEYS
Add 'key' attribute to the XML encoding for
field definitions that use the 'k' modifier.
The key attribute has
the value "key".
.El
.Pp
The
.Fn xo_clear_flags
function turns off the given flags in a specific
handle.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

112
0.9.0/libxo/xo_set_info.3 Normal file
View File

@ -0,0 +1,112 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_info
.Nd set the field information data for libxo
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_set_info "xo_handle_t *handle" "xo_info_t *info" "int count"
.Sh DESCRIPTION
HTML data can include additional information in attributes that
begin with "data-".
To enable this, three things must occur:
.Pp
First the application must build an array of
.Dv xo_info_t
structures,
one per tag.
The array must be sorted by name, since
.Nm libxo
uses a
binary search to find the entry that matches names from format
instructions.
.Pp
The
.Dv xo_info_t
structure is defined in
.In libxo/xo.h :
.Bd -literal -offset indent
typedef struct xo_info_s {
const char *xi_name; /* Name of the element */
const char *xi_type; /* Type of field */
const char *xi_help; /* Description of field */
} xo_info_t;
.Ed
.Pp
Second, the application must inform
.Nm libxo
about this information using the
.Fn xo_set_info
call.
Like other
.Nm libxo
calls, passing
.Dv NULL
for the handle tells
.Nm libxo
to use the default handle.
.Pp
If the
.Fa count
is -1,
.Nm libxo
will count the elements of
.Fa info ,
but there
must be an empty element at the end.
More typically, the number is
known to the application:
.Bd -literal -offset indent
xo_info_t info[] = {
{ "in-stock", "number", "Number of items in stock" },
{ "name", "string", "Name of the item" },
{ "on-order", "number", "Number of items on order" },
{ "sku", "string", "Stock Keeping Unit" },
{ "sold", "number", "Number of items sold" },
};
int info_count = (sizeof(info) / sizeof(info[0]));
...
xo_set_info(NULL, info, info_count);
.Ed
.Pp
Third, the emission of info must be triggered with the
.Dv XOF_INFO
flag
using either the
.Fn xo_set_flags
function or the
.Dq --libxo=info
command line argument.
.Pp
The type and help values, if present, are emitted as the "data-type"
and "data-help" attributes:
.Bd -literal -offset indent
<div class="data" data-tag="sku" data-type="string"
data-help="Stock Keeping Unit">GRO-000-533</div>
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,41 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_options
.Nd change options used by a libxo handle
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft int
.Fn xo_set_options "xo_handle_t *xop" "const char *input"
.Sh DESCRIPTION
The
.Fn xo_set_options
function accepts a comma-separated list of styles
and flags and enables them for a specific handle.
The options are identical to those listed in
.Xr xo_parse_args 3 .
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,63 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_style , xo_set_style_name
.Nd set the output style for a libxo handle
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_set_style "xo_handle_t *handle" "unsigned style"
.Ft int
.Fn xo_set_style_name "xo_handle_t *handle" "const char *style"
.Sh DESCRIPTION
Use the
.Fn xo_set_style
function to set the output style for a handle.
To use the default handle, pass a
.Dv NULL
handle.
The set of output styles used by
.Nm libxo
is:
.Bl -column "XO_STYLE_TEXT12"
.It Sy "Flag Description"
.It "XO_STYLE_TEXT Traditional text output"
.It "XO_STYLE_XML XML encoded data"
.It "XO_STYLE_JSON JSON encoded data"
.It "XO_STYLE_HTML HTML encoded data"
.El
.Pp
The
.Fn xo_set_style_name
function can be used to set the style based on a name
encoded as a string.
The name can be any of the styles: "text", "xml", "json", or "html".
.Bd -literal -offset indent
EXAMPLE:
xo_set_style_name(NULL, "html");
.Ed
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,46 @@
.\" #
.\" # 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
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2015
.\"
.Dd July 20, 2015
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_syslog_enterprise_id
.Nd Set the enterprise identifier for syslog content
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_set_syslog_enterprise_id "unsigned short eid"
.Ft void
.Sh DESCRIPTION
The
.Fn xo_set_syslog_enterprise_id
function records an enterprise identifier used for subsequent
.Xr xo_syslog 3
calls.
Enterprise IDs are
defined by IANA, the Internet Assigned Numbers Authority:
.Bd -literal -offset indent
https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
.Ed
.Sh SEE ALSO
.Xr xo_syslog 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,44 @@
.\" #
.\" # 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
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_version , xo_set_version_h
.Nd record content-version information in encoded output
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_set_version "const char *version"
.Ft void
.Fn xo_set_version_h "xo_handle_t *xop" "const char *version"
.Sh DESCRIPTION
The
.Nm xo_set_version
function records a version number to be emitted as
part of the data for encoding styles (XML and JSON).
This version number is suitable for tracking changes in the content,
allowing a user of the data to discern which version of the data model
is in use.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

View File

@ -0,0 +1,66 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_set_writer
.Nd set custom writer functions for a libxo handle
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Sy typedef int (*xo_write_func_t)(void *, const char *);
.Pp
.Sy typedef void (*xo_close_func_t)(void *);
.Pp
.Sy typedef int (*xo_flush_func_t)(void *);
.Fn xo_set_writer "xo_handle_t *handle" "void *opaque"
"xo_write_func_t write_func"
"xo_close_func_t close_func"
"xo_flush_func_t flush_func"
.Sh DESCRIPTION
The
.Fn xo_set_writer
function allows custom
.Dq write
functions
which can tailor how
.Nm libxo
writes data.
An
.Fa opaque
argument is
recorded and passed back to the
.Fa write_func
function, allowing the function
to acquire context information.
The
.Fa close_func
function can
release this opaque data and any other resources as needed.
The
.Fa flush_func
function should
flush any pending data associated with the opaque pointer.
.Sh SEE ALSO
.Xr xo_emit 3 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

89
0.9.0/libxo/xo_syslog.3 Normal file
View File

@ -0,0 +1,89 @@
.\" #
.\" # 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
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2015
.\"
.Dd July 20, 2015
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_syslog , xo_vsyslog , xo_open_log , xo_close_log , xo_set_logmask
.Nd create SYSLOG (RFC5424) log records using libxo formatting
.Sh LIBRARY
.Lb libxo
.Sh SYNOPSIS
.In libxo/xo.h
.Ft void
.Fn xo_syslog "int pri" "const char *name" "const char *fmt" "..."
.Ft void
.Fn xo_vsyslog "int pri" "const char *name" "const char *fmt" "va_list vap"
.Ft void
.Fn xo_close_log "void"
.Ft void
.Fn xo_open_log "const char *ident" "int logstat" "int logfac"
.Ft int
.Fn xo_set_logmask "int pmask"
.Sh DESCRIPTION
The
.Fn xo_syslog
function creates log entries following the standard defined in
RFC5424.
These messages are sent to the log
.Xr syslogd 8
daemon, where they can be filtered, forwarded, and archived.
.Nm libxo
format strings are used to create both the message text and the
.Nm SD-PARAMS
content, containing name/value pairs that can be parsed by suitable
automation software.
.Pp
Refer to
.Xr xo_format 5
for basic information about formatting strings.
.Nm xo_syslog
encodes all value fields at SD-PARAMS within the syslog message.
An exception is made for fields with the "{d:}" modifier; such fields
appear in the message text only, with fields with the "{e:}" modifier
appear as SD-PARAMS, but not in the message text.
.Pp
.Fn xo_vsyslog
accepts a
.Fa va_list
for additional flexibility.
.Pp
.Fn xo_open_log ,
.Fn xo_close_log , and
.Fn xo_set_logmask
are all analogous to their libs counterparts,
.Xr openlog 3 ,
.Xr closelog 3 , and
.Xr setlogmask 3 .
The extra underscores in the names are unfortunate, but keep
consistency in
.Nm libxo
function names.
.Sh EXAMPLES
.Bd -literal -offset indent
xo_syslog(LOG_LOCAL4 | LOG_NOTICE, "ID47",
"{e:iut/%u}An {:event-source} {:event-id/%u} log entry",
iut, source, id);
.Ed
.Sh SEE ALSO
.Xr xo_syslog 3 ,
.Xr xo_set_syslog_enterprise_id 3 ,
.Xr xo_format 5 ,
.Xr libxo 3
.Sh HISTORY
The
.Nm libxo
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.Nm libxo
was written by
.An Phil Shafer Aq Mt phil@freebsd.org .

711
0.9.0/libxo/xo_syslog.c Normal file
View File

@ -0,0 +1,711 @@
/*
* 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, June 2015
*/
/*
* Portions of this file are:
* Copyright (c) 1983, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#include <unistd.h>
#include <stdarg.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include "xo_config.h"
#include "xo.h"
#include "xo_encoder.h" /* For xo_realloc */
#include "xo_buf.h"
/*
* SYSLOG (RFC 5424) requires an enterprise identifier. This turns
* out to be a fickle little issue. For a single-vendor box, the
* system should have a single EID that all software can use. When
* VendorX turns FreeBSD into a product, all software (kernel and
* utilities) should report VendorX's EID. But when software is
* installed on top of an external operating system, the application
* should report it's own EID, distinct from the base OS.
*
* To make this happen, the kernel should support a sysctl to assign a
* custom enterprise-id ("kern.syslog.enterprise_id"). libxo then
* allows an application to set a custom EID to override that system
* wide value, if needed.
*
* We try to set the stock IANA assigned Enterprise ID value for the
* vendors we know about (FreeBSD, macosx), but fallback to the
* "example" EID defined by IANA. See:
* https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
*/
#define XO_SYSLOG_ENTERPRISE_ID "kern.syslog.enterprise_id"
#if defined(__FreeBSD__)
#define XO_DEFAULT_EID 2238
#elif defined(__macosx__)
#define XO_DEFAULT_EID 63
#else
#define XO_DEFAULT_EID 32473 /* Fallback to the "example" number */
#endif
#ifndef HOST_NAME_MAX
#ifdef _SC_HOST_NAME_MAX
#define HOST_NAME_MAX _SC_HOST_NAME_MAX
#else
#define HOST_NAME_MAX 255
#endif /* _SC_HOST_NAME_MAX */
#endif /* HOST_NAME_MAX */
#ifndef UNUSED
#define UNUSED __attribute__ ((__unused__))
#endif /* UNUSED */
static int xo_logfile = -1; /* fd for log */
static int xo_status; /* connection xo_status */
static int xo_opened; /* have done openlog() */
static int xo_logstat = 0; /* xo_status bits, set by openlog() */
static const char *xo_logtag = NULL; /* string to tag the entry with */
static int xo_logfacility = LOG_USER; /* default facility code */
static int xo_logmask = 0xff; /* mask of priorities to be logged */
static pthread_mutex_t xo_syslog_mutex UNUSED = PTHREAD_MUTEX_INITIALIZER;
static int xo_unit_test; /* Fake data for unit test */
#define REAL_VOID(_x) \
do { int really_ignored = _x; if (really_ignored) { }} while (0)
#if !defined(HAVE_DECL___ISTHREADED) || !HAVE_DECL___ISTHREADED
#define __isthreaded 1
#endif
#define THREAD_LOCK() \
do { \
if (__isthreaded) pthread_mutex_lock(&xo_syslog_mutex); \
} while(0)
#define THREAD_UNLOCK() \
do { \
if (__isthreaded) pthread_mutex_unlock(&xo_syslog_mutex); \
} while(0)
static void xo_disconnect_log(void); /* disconnect from syslogd */
static void xo_connect_log(void); /* (re)connect to syslogd */
static void xo_open_log_unlocked(const char *, int, int);
enum {
NOCONN = 0,
CONNDEF,
CONNPRIV,
};
static xo_syslog_open_t xo_syslog_open;
static xo_syslog_send_t xo_syslog_send;
static xo_syslog_close_t xo_syslog_close;
static char xo_syslog_enterprise_id[12];
/*
* Record an enterprise ID, which functions as a namespace for syslog
* messages. The value is pre-formatted into a string. This allows
* applications to customize their syslog message set, when needed.
*/
void
xo_set_syslog_enterprise_id (unsigned short eid)
{
snprintf(xo_syslog_enterprise_id, sizeof(xo_syslog_enterprise_id),
"%u", eid);
}
/*
* Handle the work of transmitting the syslog message
*/
static void
xo_send_syslog (char *full_msg, char *v0_hdr,
char *text_only)
{
if (xo_syslog_send) {
xo_syslog_send(full_msg, v0_hdr, text_only);
return;
}
int fd;
int full_len = strlen(full_msg);
/* Output to stderr if requested, then we've been passed a v0 header */
if (v0_hdr) {
struct iovec iov[3];
struct iovec *v = iov;
char newline[] = "\n";
v->iov_base = v0_hdr;
v->iov_len = strlen(v0_hdr);
v += 1;
v->iov_base = text_only;
v->iov_len = strlen(text_only);
v += 1;
v->iov_base = newline;
v->iov_len = 1;
v += 1;
REAL_VOID(writev(STDERR_FILENO, iov, 3));
}
/* Get connected, output the message to the local logger. */
if (!xo_opened)
xo_open_log_unlocked(xo_logtag, xo_logstat | LOG_NDELAY, 0);
xo_connect_log();
/*
* If the send() fails, there are two likely scenarios:
* 1) syslogd was restarted
* 2) /var/run/log is out of socket buffer space, which
* in most cases means local DoS.
* If the error does not indicate a full buffer, we address
* case #1 by attempting to reconnect to /var/run/log[priv]
* and resending the message once.
*
* If we are working with a privileged socket, the retry
* attempts end there, because we don't want to freeze a
* critical application like su(1) or sshd(8).
*
* Otherwise, we address case #2 by repeatedly retrying the
* send() to give syslogd a chance to empty its socket buffer.
*/
if (send(xo_logfile, full_msg, full_len, 0) < 0) {
if (errno != ENOBUFS) {
/*
* Scenario 1: syslogd was restarted
* reconnect and resend once
*/
xo_disconnect_log();
xo_connect_log();
if (send(xo_logfile, full_msg, full_len, 0) >= 0) {
return;
}
/*
* if the resend failed, fall through to
* possible scenario 2
*/
}
while (errno == ENOBUFS) {
/*
* Scenario 2: out of socket buffer space
* possible DoS, fail fast on a privileged
* socket
*/
if (xo_status == CONNPRIV)
break;
usleep(1);
if (send(xo_logfile, full_msg, full_len, 0) >= 0) {
return;
}
}
} else {
return;
}
/*
* Output the message to the console; try not to block
* as a blocking console should not stop other processes.
* Make sure the error reported is the one from the syslogd failure.
*/
int flags = O_WRONLY | O_NONBLOCK;
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif /* O_CLOEXEC */
if (xo_logstat & LOG_CONS
&& (fd = open(_PATH_CONSOLE, flags, 0)) >= 0) {
struct iovec iov[2];
struct iovec *v = iov;
char crnl[] = "\r\n";
char *p;
p = strchr(full_msg, '>') + 1;
v->iov_base = p;
v->iov_len = full_len - (p - full_msg);
++v;
v->iov_base = crnl;
v->iov_len = 2;
REAL_VOID(writev(fd, iov, 2));
(void) close(fd);
}
}
/* Should be called with mutex acquired */
static void
xo_disconnect_log (void)
{
if (xo_syslog_close) {
xo_syslog_close();
return;
}
/*
* If the user closed the FD and opened another in the same slot,
* that's their problem. They should close it before calling on
* system services.
*/
if (xo_logfile != -1) {
close(xo_logfile);
xo_logfile = -1;
}
xo_status = NOCONN; /* retry connect */
}
/* Should be called with mutex acquired */
static void
xo_connect_log (void)
{
if (xo_syslog_open) {
xo_syslog_open();
return;
}
struct sockaddr_un saddr; /* AF_UNIX address of local logger */
if (xo_logfile == -1) {
int flags = SOCK_DGRAM;
#ifdef SOCK_CLOEXEC
flags |= SOCK_CLOEXEC;
#endif /* SOCK_CLOEXEC */
if ((xo_logfile = socket(AF_UNIX, flags, 0)) == -1)
return;
}
if (xo_logfile != -1 && xo_status == NOCONN) {
#ifdef HAVE_SUN_LEN
saddr.sun_len = sizeof(saddr);
#endif /* HAVE_SUN_LEN */
saddr.sun_family = AF_UNIX;
/*
* First try privileged socket. If no success,
* then try default socket.
*/
#ifdef _PATH_LOG_PRIV
(void) strncpy(saddr.sun_path, _PATH_LOG_PRIV,
sizeof saddr.sun_path);
if (connect(xo_logfile, (struct sockaddr *) &saddr,
sizeof(saddr)) != -1)
xo_status = CONNPRIV;
#endif /* _PATH_LOG_PRIV */
#ifdef _PATH_LOG
if (xo_status == NOCONN) {
(void) strncpy(saddr.sun_path, _PATH_LOG,
sizeof saddr.sun_path);
if (connect(xo_logfile, (struct sockaddr *)&saddr,
sizeof(saddr)) != -1)
xo_status = CONNDEF;
}
#endif /* _PATH_LOG */
#ifdef _PATH_OLDLOG
if (xo_status == NOCONN) {
/*
* Try the old "/dev/log" path, for backward
* compatibility.
*/
(void) strncpy(saddr.sun_path, _PATH_OLDLOG,
sizeof saddr.sun_path);
if (connect(xo_logfile, (struct sockaddr *)&saddr,
sizeof(saddr)) != -1)
xo_status = CONNDEF;
}
#endif /* _PATH_OLDLOG */
if (xo_status == NOCONN) {
(void) close(xo_logfile);
xo_logfile = -1;
}
}
}
static void
xo_open_log_unlocked (const char *ident, int logstat, int logfac)
{
if (ident != NULL)
xo_logtag = ident;
xo_logstat = logstat;
if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0)
xo_logfacility = logfac;
if (xo_logstat & LOG_NDELAY) /* open immediately */
xo_connect_log();
xo_opened = 1; /* ident and facility has been set */
}
void
xo_open_log (const char *ident, int logstat, int logfac)
{
THREAD_LOCK();
xo_open_log_unlocked(ident, logstat, logfac);
THREAD_UNLOCK();
}
void
xo_close_log (void)
{
THREAD_LOCK();
if (xo_logfile != -1) {
(void) close(xo_logfile);
xo_logfile = -1;
}
xo_logtag = NULL;
xo_status = NOCONN;
THREAD_UNLOCK();
}
/* xo_set_logmask -- set the log mask level */
int
xo_set_logmask (int pmask)
{
int omask;
THREAD_LOCK();
omask = xo_logmask;
if (pmask != 0)
xo_logmask = pmask;
THREAD_UNLOCK();
return (omask);
}
void
xo_set_syslog_handler (xo_syslog_open_t open_func,
xo_syslog_send_t send_func,
xo_syslog_close_t close_func)
{
xo_syslog_open = open_func;
xo_syslog_send = send_func;
xo_syslog_close = close_func;
}
static ssize_t
xo_snprintf (char *out, ssize_t outsize, const char *fmt, ...)
{
ssize_t status;
ssize_t retval = 0;
va_list ap;
if (out && outsize) {
va_start(ap, fmt);
status = vsnprintf(out, outsize, fmt, ap);
if (status < 0) { /* this should never happen, */
*out = 0; /* handle it in the safest way possible if it does */
retval = 0;
} else {
retval = status;
retval = retval > outsize ? outsize : retval;
}
va_end(ap);
}
return retval;
}
static xo_ssize_t
xo_syslog_handle_write (void *opaque, const char *data)
{
xo_buffer_t *xbp = opaque;
int len = strlen(data);
int left = xo_buf_left(xbp);
if (len > left - 1)
len = left - 1;
memcpy(xbp->xb_curp, data, len);
xbp->xb_curp += len;
*xbp->xb_curp = '\0';
return len;
}
static void
xo_syslog_handle_close (void *opaque UNUSED)
{
}
static int
xo_syslog_handle_flush (void *opaque UNUSED)
{
return 0;
}
void
xo_set_unit_test_mode (int value)
{
xo_unit_test = value;
}
void
xo_vsyslog (int pri, const char *name, const char *fmt, va_list vap)
{
int saved_errno = errno;
char tbuf[2048];
char *tp = NULL, *ep = NULL;
unsigned start_of_msg = 0;
char *v0_hdr = NULL;
xo_buffer_t xb;
static pid_t my_pid;
unsigned log_offset;
if (my_pid == 0)
my_pid = xo_unit_test ? 222 : getpid();
/* Check for invalid bits */
if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) {
xo_syslog(LOG_ERR | LOG_CONS | LOG_PERROR | LOG_PID,
"syslog-unknown-priority",
"syslog: unknown facility/priority: %#x", pri);
pri &= LOG_PRIMASK|LOG_FACMASK;
}
THREAD_LOCK();
/* Check priority against setlogmask values. */
if (!(LOG_MASK(LOG_PRI(pri)) & xo_logmask)) {
THREAD_UNLOCK();
return;
}
/* Set default facility if none specified. */
if ((pri & LOG_FACMASK) == 0)
pri |= xo_logfacility;
/* Create the primary stdio hook */
xb.xb_bufp = tbuf;
xb.xb_curp = tbuf;
xb.xb_size = sizeof(tbuf);
xo_handle_t *xop = xo_create(XO_STYLE_SDPARAMS, 0);
if (xop == NULL) {
THREAD_UNLOCK();
return;
}
#ifdef HAVE_GETPROGNAME
if (xo_logtag == NULL)
xo_logtag = getprogname();
#endif /* HAVE_GETPROGNAME */
xo_set_writer(xop, &xb, xo_syslog_handle_write, xo_syslog_handle_close,
xo_syslog_handle_flush);
/* Build the message; start by getting the time */
struct tm tm;
struct timeval tv;
/* Unit test hack: fake a fixed time */
if (xo_unit_test) {
tv.tv_sec = 1435085229;
tv.tv_usec = 123456;
} else
gettimeofday(&tv, NULL);
(void) localtime_r(&tv.tv_sec, &tm);
if (xo_logstat & LOG_PERROR) {
/*
* For backwards compatibility, we need to make the old-style
* message. This message can be emitted to the console/tty.
*/
v0_hdr = alloca(2048);
tp = v0_hdr;
ep = v0_hdr + 2048;
if (xo_logtag != NULL)
tp += xo_snprintf(tp, ep - tp, "%s", xo_logtag);
if (xo_logstat & LOG_PID)
tp += xo_snprintf(tp, ep - tp, "[%d]", my_pid);
if (xo_logtag)
tp += xo_snprintf(tp, ep - tp, ": ");
}
log_offset = xb.xb_curp - xb.xb_bufp;
/* Add PRI, PRIVAL, and VERSION */
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "<%d>1 ", pri);
/* Add TIMESTAMP with milliseconds and TZOFFSET */
xb.xb_curp += strftime(xb.xb_curp, xo_buf_left(&xb), "%FT%T", &tm);
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb),
".%03.3u", tv.tv_usec / 1000);
xb.xb_curp += strftime(xb.xb_curp, xo_buf_left(&xb), "%z ", &tm);
/*
* Add HOSTNAME; we rely on gethostname and don't fluff with
* ip addresses. Might need to revisit.....
*/
char hostname[HOST_NAME_MAX];
hostname[0] = '\0';
if (xo_unit_test)
strcpy(hostname, "worker-host");
else
(void) gethostname(hostname, sizeof(hostname));
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
hostname[0] ? hostname : "-");
/* Add APP-NAME */
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s ",
xo_logtag ?: "-");
/* Add PROCID */
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%d ", my_pid);
/*
* Add MSGID. The user should provide us with a name, which we
* prefix with the current enterprise ID, as learned from the kernel.
* If the kernel won't tell us, we use the stock/builtin number.
*/
char *buf UNUSED = NULL;
const char *eid = xo_syslog_enterprise_id;
const char *at_sign = "@";
if (name == NULL) {
name = "-";
eid = at_sign = "";
} else if (*name == '@') {
/* Our convention is to prefix IANA-defined names with an "@" */
name += 1;
eid = at_sign = "";
} else if (eid[0] == '\0') {
#ifdef HAVE_SYSCTLBYNAME
/*
* See if the kernel knows the sysctl for the enterprise ID
*/
size_t size = 0;
if (sysctlbyname(XO_SYSLOG_ENTERPRISE_ID, NULL, &size, NULL, 0) == 0
&& size > 0) {
buf = alloca(size);
if (sysctlbyname(XO_SYSLOG_ENTERPRISE_ID, buf, &size, NULL, 0) == 0
&& size > 0)
eid = buf;
}
#endif /* HAVE_SYSCTLBYNAME */
if (eid[0] == '\0') {
/* Fallback to our base default */
xo_set_syslog_enterprise_id(XO_DEFAULT_EID);
eid = xo_syslog_enterprise_id;
}
}
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "%s [%s%s%s ",
name, name, at_sign, eid);
/*
* Now for the real content. We make two distinct passes thru the
* xo_emit engine, first for the SD-PARAMS and then for the text
* message.
*/
va_list ap;
va_copy(ap, vap);
errno = saved_errno; /* Restore saved error value */
xo_emit_hv(xop, fmt, ap);
xo_flush_h(xop);
va_end(ap);
/* Trim trailing space */
if (xb.xb_curp[-1] == ' ')
xb.xb_curp -= 1;
/* Close the structured data (SD-ELEMENT) */
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb), "] ");
/*
* Since our MSG is known to be UTF-8, we MUST prefix it with
* that most-annoying-of-all-UTF-8 features, the BOM (0xEF.BB.BF).
*/
xb.xb_curp += xo_snprintf(xb.xb_curp, xo_buf_left(&xb),
"%c%c%c", 0xEF, 0xBB, 0xBF);
/* Save the start of the message */
if (xo_logstat & LOG_PERROR)
start_of_msg = xb.xb_curp - xb.xb_bufp;
xo_set_style(xop, XO_STYLE_TEXT);
xo_set_flags(xop, XOF_UTF8);
errno = saved_errno; /* Restore saved error value */
xo_emit_hv(xop, fmt, ap);
xo_flush_h(xop);
/* Remove a trailing newline */
if (xb.xb_curp[-1] == '\n')
*--xb.xb_curp = '\0';
if (xo_get_flags(xop) & XOF_LOG_SYSLOG)
fprintf(stderr, "xo: syslog: %s\n", xb.xb_bufp + log_offset);
xo_send_syslog(xb.xb_bufp, v0_hdr, xb.xb_bufp + start_of_msg);
xo_destroy(xop);
THREAD_UNLOCK();
}
/*
* syslog - print message on log file; output is intended for syslogd(8).
*/
void
xo_syslog (int pri, const char *name, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
xo_vsyslog(pri, name, fmt, ap);
va_end(ap);
}

313
0.9.0/libxo/xo_wcwidth.h Normal file
View File

@ -0,0 +1,313 @@
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <wchar.h>
struct interval {
wchar_t first;
wchar_t last;
};
/* auxiliary function for binary search in interval table */
static int
xo_bisearch (wchar_t ucs, const struct interval *table, int max)
{
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that wchar_t characters are encoded
* in ISO 10646.
*/
static int
xo_wcwidth (wchar_t ucs)
{
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
{ 0xE0100, 0xE01EF }
};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (xo_bisearch(ucs, combining,
sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
#if UNUSED_CODE
static int xo_wcswidth(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int mk_wcwidth_cjk(wchar_t ucs)
{
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
};
/* binary search in table of non-spacing characters */
if (xo_bisearch(ucs, ambiguous,
sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return mk_wcwidth(ucs);
}
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
{
int w, width = 0;
for (;*pwcs && n-- > 0; pwcs++)
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
return -1;
else
width += w;
return width;
}
#endif /* UNUSED_CODE */

View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libxo
Version: @LIBXO_VERSION@
Description: The XML Output Library
Libs: -L@XO_LIBDIR@ @XO_LIBS@
Cflags: -I@XO_INCLUDEDIR@

View File

@ -0,0 +1,20 @@
#
# Homebrew formula file for libxo
# https://github.com/mxcl/homebrew
#
require 'formula'
class Libxo < Formula
homepage 'https://github.com/Juniper/@PACKAGE_NAME@'
url 'https://github.com/Juniper/@PACKAGE_NAME@/releases/download/@PACKAGE_VERSION@/@PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz'
sha1 '__SHA1__'
depends_on 'libtool' => :build
def install
system "./configure", "--disable-dependency-tracking", "--disable-silent-rules",
"--prefix=#{prefix}"
system "make", "install"
end
end

View File

@ -0,0 +1,44 @@
Name: @PACKAGE_NAME@
Version: @PACKAGE_VERSION@
Release: 1%{?dist}
Summary: The libxo library
Prefix: /usr
Vendor: Juniper Networks, Inc.
Packager: Phil Shafer <phil@juniper.net>
License: BSD
Group: Development/Libraries
URL: https://github.com/Juniper/libxo
Source0: https://github.com/Juniper/@PACKAGE_NAME@/releases/@PACKAGE_VERSION@/@PACKAGE_NAME@-@PACKAGE_VERSION@.tar.gz
%description
Welcome to libxo, a library that generates text, XML, JSON, and HTML
from a single source code path.
%prep
%setup -q
%build
%configure
make %{?_smp_mflags}
%install
rm -rf $RPM_BUILD_ROOT
%make_install
%clean
rm -rf $RPM_BUILD_ROOT
%post -p /sbin/ldconfig
%files
%{_bindir}/*
%{_includedir}/libxo/*
%{_libdir}/*
%{_datadir}/doc/libxo/*
%docdir %{_datadir}/doc/libxo/*
%{_mandir}/*/*
%docdir %{_mandir}/*/*

32
0.9.0/tests/Makefile.am Normal file
View File

@ -0,0 +1,32 @@
#
# Copyright 2014, 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 = core xo
if HAVE_GETTEXT
SUBDIRS += gettext
endif
test tests:
@(cur=`pwd` ; for dir in $(SUBDIRS) ; do \
cd $$dir ; \
$(MAKE) tests ; \
cd $$cur ; \
done)
accept:
@(cur=`pwd` ; for dir in $(SUBDIRS) ; do \
cd $$dir ; \
$(MAKE) accept ; \
cd $$cur ; \
done)
valgrind:
@echo '## Running the regression tests under Valgrind'
@echo '## Go get a cup of coffee it is gonna take a while ...'
${MAKE} VALGRIND='valgrind -q' tests

View File

@ -0,0 +1,129 @@
#
# $Id$
#
# Copyright 2014, 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.
AM_CFLAGS = -I${top_srcdir} -I${top_srcdir}/libxo
# Ick: maintained by hand!
TEST_CASES = \
test_01.c \
test_02.c \
test_03.c \
test_04.c \
test_05.c \
test_06.c \
test_07.c \
test_08.c \
test_09.c \
test_10.c \
test_11.c \
test_12.c
test_01_test_SOURCES = test_01.c
test_02_test_SOURCES = test_02.c
test_03_test_SOURCES = test_03.c
test_04_test_SOURCES = test_04.c
test_05_test_SOURCES = test_05.c
test_06_test_SOURCES = test_06.c
test_07_test_SOURCES = test_07.c
test_08_test_SOURCES = test_08.c
test_09_test_SOURCES = test_09.c
test_10_test_SOURCES = test_10.c
test_11_test_SOURCES = test_11.c
test_12_test_SOURCES = test_12.c
# TEST_CASES := $(shell cd ${srcdir} ; echo *.c )
noinst_PROGRAMS = ${TEST_CASES:.c=.test}
LDADD = \
${top_builddir}/libxo/libxo.la
if HAVE_HUMANIZE_NUMBER
LDADD += -lutil
endif
EXTRA_DIST = \
${TEST_CASES} \
${addprefix saved/, ${TEST_CASES:.c=.T.err}} \
${addprefix saved/, ${TEST_CASES:.c=.T.out}} \
${addprefix saved/, ${TEST_CASES:.c=.XP.err}} \
${addprefix saved/, ${TEST_CASES:.c=.XP.out}} \
${addprefix saved/, ${TEST_CASES:.c=.JP.err}} \
${addprefix saved/, ${TEST_CASES:.c=.JP.out}} \
${addprefix saved/, ${TEST_CASES:.c=.HP.err}} \
${addprefix saved/, ${TEST_CASES:.c=.HP.out}} \
${addprefix saved/, ${TEST_CASES:.c=.X.err}} \
${addprefix saved/, ${TEST_CASES:.c=.X.out}} \
${addprefix saved/, ${TEST_CASES:.c=.J.err}} \
${addprefix saved/, ${TEST_CASES:.c=.J.out}} \
${addprefix saved/, ${TEST_CASES:.c=.H.err}} \
${addprefix saved/, ${TEST_CASES:.c=.H.out}} \
${addprefix saved/, ${TEST_CASES:.c=.HIPx.err}} \
${addprefix saved/, ${TEST_CASES:.c=.HIPx.out}} \
${addprefix saved/, ${TEST_CASES:.c=.E.err}} \
${addprefix saved/, ${TEST_CASES:.c=.E.out}}
S2O = | ${SED} '1,/@@/d'
all:
valgrind:
@echo '## Running the regression tests under Valgrind'
${MAKE} CHECKER='valgrind -q' tests
#TEST_TRACE = set -x ;
TEST_JIG = \
${CHECKER} ./$$base.test --libxo$$xoopts ${TEST_OPTS} \
> out/$$base.$$fmt.out 2> out/$$base.$$fmt.err ; \
${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_FORMATS = T XP JP HP X J H HIPx
test tests: ${bin_PROGRAMS}
@${MKDIR} -p out
-@ ${TEST_TRACE} (for test in ${TEST_CASES} ; do \
base=`${BASENAME} $$test .c` ; \
(for fmt in ${TEST_FORMATS}; do \
echo "... $$test ... $$fmt ..."; \
xoopts=:W$$fmt ; \
${TEST_JIG}; \
true; \
done) ; \
(for fmt in E; do \
echo "... $$test ... $$fmt ..."; \
xoopts==warn,encoder=test ; \
${TEST_JIG}; \
true; \
done) \
done)
one:
-@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
accept:
-@(for test in ${TEST_CASES} ; do \
base=`${BASENAME} $$test .c` ; \
(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)
.c.test:
$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -o $@ $<
CLEANFILES = ${TEST_CASES:.c=.test}
CLEANDIRS = out
clean-local:
rm -rf ${CLEANDIRS}

View File

View File

@ -0,0 +1,153 @@
op create: [] [] [0]
op open_container: [top] [] [0x810]
op string: [type] [ethernet] [0]
op content: [type] [bridge] [0]
op content: [type] [18u] [0]
op content: [type] [24] [0]
op content: [address] [0x0] [0]
op content: [port] [1] [0]
op content: [address] [0x0] [0]
op content: [port] [1] [0]
op content: [address] [0x0] [0]
op content: [port] [1] [0]
op content: [used-percent] [12] [0]
op content: [kve_start] [0xdeadbeef] [0x8]
op content: [kve_end] [0xcabb1e] [0x8]
op string: [host] [my-box] [0x200000]
op string: [domain] [example.com] [0x200000]
op string: [host] [my-box] [0x200008]
op string: [domain] [example.com] [0x200000]
op string: [label] [value] [0x200000]
op string: [max-chaos] [very] [0x1000]
op content: [min-chaos] [42] [0]
op string: [some-chaos] [[42]] [0]
op string: [host] [my-box] [0]
op string: [domain] [example.com] [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: [in-stock] [54] [0]
op content: [on-order] [10] [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 content: [in-stock] [4] [0]
op content: [on-order] [2] [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 content: [in-stock] [2] [0]
op content: [on-order] [1] [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: [in-stock] [144] [0]
op content: [on-order] [42] [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 content: [in-stock] [14] [0]
op content: [on-order] [2] [0]
op close_instance: [item] [] [0]
op close_list: [item] [] [0]
op close_container: [data] [] [0]
op open_container: [data2] [] [0x810]
op open_list: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [GRO-000-415] [0x98]
op string: [name] [gum] [0x80]
op content: [sold] [1412.0] [0x20]
op content: [in-stock] [54] [0]
op content: [on-order] [10] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [HRD-000-212] [0x98]
op string: [name] [rope] [0x80]
op content: [sold] [85.0] [0x20]
op content: [in-stock] [4] [0]
op content: [on-order] [2] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [HRD-000-517] [0x98]
op string: [name] [ladder] [0x80]
op content: [sold] [0] [0x20]
op content: [in-stock] [2] [0]
op content: [on-order] [1] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [HRD-000-632] [0x98]
op string: [name] [bolt] [0x80]
op content: [sold] [4123.0] [0x20]
op content: [in-stock] [144] [0]
op content: [on-order] [42] [0]
op close_instance: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [GRO-000-2331] [0x98]
op string: [name] [water] [0x80]
op content: [sold] [17.0] [0x20]
op content: [in-stock] [14] [0]
op content: [on-order] [2] [0]
op close_instance: [item] [] [0]
op close_list: [item] [] [0]
op close_container: [data2] [] [0]
op open_container: [data3] [] [0x810]
op open_list: [item] [] [0]
op open_instance: [item] [] [0x810]
op string: [sku] [GRO-000-533] [0x98]
op string: [name] [fish] [0x80]
op content: [sold] [1321.0] [0x20]
op content: [in-stock] [45] [0]
op content: [on-order] [1] [0]
op close_instance: [item] [] [0]
op close_list: [item] [] [0]
op close_container: [data3] [] [0]
op open_container: [data4] [] [0x810]
op open_list: [item] [] [0]
op attr: [test4] [value4] [0]
op string: [item] [gum] [0x2000]
op attr: [test4] [value4] [0]
op string: [item] [rope] [0x2000]
op attr: [test4] [value4] [0]
op string: [item] [ladder] [0x2000]
op attr: [test4] [value4] [0]
op string: [item] [bolt] [0x2000]
op attr: [test4] [value4] [0]
op string: [item] [water] [0x2000]
op close_list: [item] [] [0]
op close_container: [data4] [] [0]
op content: [cost] [425] [0]
op content: [cost] [455] [0]
op string: [mode] [mode] [0x8]
op string: [mode_octal] [octal] [0x8]
op string: [links] [links] [0x1000]
op string: [user] [user] [0x1000]
op string: [group] [group] [0x1000]
op string: [pre] [that] [0x8]
op content: [links] [3] [0x1000]
op string: [post] [this] [0x1000]
op string: [mode] [/some/file] [0x1000]
op content: [mode_octal] [640] [0x8]
op content: [links] [1] [0x1000]
op string: [user] [user] [0x1000]
op string: [group] [group] [0x1000]
op close_container: [top] [] [0]
op finish: [] [] [0]
op flush: [] [] [0]

View File

File diff suppressed because one or more lines are too long

View File

View File

@ -0,0 +1,382 @@
<div class="line">
<div class="text">static </div>
<div class="data" data-tag="type" data-xpath="/top/type">ethernet</div>
<div class="text"> </div>
<div class="data" data-tag="type" data-xpath="/top/type">bridge</div>
<div class="text"> </div>
<div class="data" data-tag="type" data-xpath="/top/type"> 18u</div>
<div class="text"> </div>
<div class="data" data-tag="type" data-xpath="/top/type"> 24</div>
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address" data-xpath="/top/address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port" data-xpath="/top/port">1</div>
</div>
<div class="line">
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address" data-xpath="/top/address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port" data-xpath="/top/port">1</div>
</div>
<div class="line">
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address" data-xpath="/top/address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port" data-xpath="/top/port">1</div>
</div>
<div class="line">
<div class="text">df </div>
<div class="data" data-tag="used-percent" data-xpath="/top/used-percent"> 12</div>
<div class="units">%</div>
</div>
<div class="line">
<div class="text">testing argument modifier </div>
<div class="data" data-tag="host" data-xpath="/top/host">my-box</div>
<div class="text">.</div>
<div class="data" data-tag="domain" data-xpath="/top/domain">example.com</div>
<div class="text">...</div>
</div>
<div class="line">
<div class="text">testing argument modifier with encoding to </div>
<div class="text">.</div>
<div class="data" data-tag="domain" data-xpath="/top/domain">example.com</div>
<div class="text">...</div>
</div>
<div class="line">
<div class="label">Label text</div>
<div class="text"> </div>
<div class="data" data-tag="label" data-xpath="/top/label">value</div>
</div>
<div class="line">
<div class="data" data-tag="max-chaos" data-xpath="/top/max-chaos"> very </div>
<div class="data" data-tag="min-chaos" data-xpath="/top/min-chaos">42</div>
<div class="data" data-tag="some-chaos" data-xpath="/top/some-chaos">42
</div>
<div class="text">Connecting to </div>
<div class="data" data-tag="host" data-xpath="/top/host">my-box</div>
<div class="text">.</div>
<div class="data" data-tag="domain" data-xpath="/top/domain">example.com</div>
<div class="text">...</div>
</div>
<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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="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="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data2/item/name" data-type="string" data-help="Name of the item" data-key="key">gum</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data2/item[sku = 'GRO-000-415'][name = 'gum']/sold" data-type="number" data-help="Number of items sold">1412.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data2/item[sku = 'GRO-000-415'][name = 'gum']/in-stock" data-type="number" data-help="Number of items in stock">54</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data2/item[sku = 'GRO-000-415'][name = 'gum']/on-order" data-type="number" data-help="Number of items on order">10</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data2/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-415</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data2/item/name" data-type="string" data-help="Name of the item" data-key="key">rope</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data2/item[sku = 'HRD-000-212'][name = 'rope']/sold" data-type="number" data-help="Number of items sold">85.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data2/item[sku = 'HRD-000-212'][name = 'rope']/in-stock" data-type="number" data-help="Number of items in stock">4</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data2/item[sku = 'HRD-000-212'][name = 'rope']/on-order" data-type="number" data-help="Number of items on order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data2/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-212</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data2/item/name" data-type="string" data-help="Name of the item" data-key="key">ladder</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data2/item[sku = 'HRD-000-517'][name = 'ladder']/sold" data-type="number" data-help="Number of items sold">0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data2/item[sku = 'HRD-000-517'][name = 'ladder']/in-stock" data-type="number" data-help="Number of items in stock">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data2/item[sku = 'HRD-000-517'][name = 'ladder']/on-order" data-type="number" data-help="Number of items on order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data2/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-517</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data2/item/name" data-type="string" data-help="Name of the item" data-key="key">bolt</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data2/item[sku = 'HRD-000-632'][name = 'bolt']/sold" data-type="number" data-help="Number of items sold">4123.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data2/item[sku = 'HRD-000-632'][name = 'bolt']/in-stock" data-type="number" data-help="Number of items in stock">144</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data2/item[sku = 'HRD-000-632'][name = 'bolt']/on-order" data-type="number" data-help="Number of items on order">42</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data2/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">HRD-000-632</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data2/item/name" data-type="string" data-help="Name of the item" data-key="key">water</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data2/item[sku = 'GRO-000-2331'][name = 'water']/sold" data-type="number" data-help="Number of items sold">17.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data2/item[sku = 'GRO-000-2331'][name = 'water']/in-stock" data-type="number" data-help="Number of items in stock">14</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data2/item[sku = 'GRO-000-2331'][name = 'water']/on-order" data-type="number" data-help="Number of items on order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data2/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-2331</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-xpath="/top/data3/item/name" data-type="string" data-help="Name of the item" data-key="key">fish</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold" data-xpath="/top/data3/item[sku = 'GRO-000-533'][name = 'fish']/sold" data-type="number" data-help="Number of items sold">1321.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock" data-xpath="/top/data3/item[sku = 'GRO-000-533'][name = 'fish']/in-stock" data-type="number" data-help="Number of items in stock">45</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order" data-xpath="/top/data3/item[sku = 'GRO-000-533'][name = 'fish']/on-order" data-type="number" data-help="Number of items on order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-xpath="/top/data3/item/sku" data-type="string" data-help="Stock Keeping Unit" data-key="key">GRO-000-533</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/item">gum</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/item">rope</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/item">ladder</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/item">bolt</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item" data-xpath="/top/data4/item">water</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="padding"> </div>
<div class="text">X</div>
<div class="label">Cost</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="cost" data-xpath="/top/cost">425</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="padding"> </div>
<div class="text">X</div>
<div class="label">Cost</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="cost" data-xpath="/top/cost">455</div>
</div>
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="links" data-xpath="/top/links">links</div>
<div class="text"> </div>
<div class="data" data-tag="user" data-xpath="/top/user">user</div>
<div class="text"> </div>
<div class="data" data-tag="group" data-xpath="/top/group">group</div>
<div class="text"> </div>
</div>
<div class="line">
<div class="data" data-tag="links" data-xpath="/top/links">3 </div>
<div class="data" data-tag="post" data-xpath="/top/post">this </div>
</div>
<div class="line">
<div class="data" data-tag="mode" data-xpath="/top/mode">/some/file</div>
<div class="text"> </div>
<div class="data" data-tag="links" data-xpath="/top/links"> 1</div>
<div class="text"> </div>
<div class="data" data-tag="user" data-xpath="/top/user">user </div>
<div class="text"> </div>
<div class="data" data-tag="group" data-xpath="/top/group">group </div>
<div class="text"> </div>
</div>

View File

View File

@ -0,0 +1,382 @@
<div class="line">
<div class="text">static </div>
<div class="data" data-tag="type">ethernet</div>
<div class="text"> </div>
<div class="data" data-tag="type">bridge</div>
<div class="text"> </div>
<div class="data" data-tag="type"> 18u</div>
<div class="text"> </div>
<div class="data" data-tag="type"> 24</div>
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port">1</div>
</div>
<div class="line">
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port">1</div>
</div>
<div class="line">
<div class="text">anchor </div>
<div class="padding"> </div>
<div class="data" data-tag="address">0x0</div>
<div class="text">..</div>
<div class="data" data-tag="port">1</div>
</div>
<div class="line">
<div class="text">df </div>
<div class="data" data-tag="used-percent"> 12</div>
<div class="units">%</div>
</div>
<div class="line">
<div class="text">testing argument modifier </div>
<div class="data" data-tag="host">my-box</div>
<div class="text">.</div>
<div class="data" data-tag="domain">example.com</div>
<div class="text">...</div>
</div>
<div class="line">
<div class="text">testing argument modifier with encoding to </div>
<div class="text">.</div>
<div class="data" data-tag="domain">example.com</div>
<div class="text">...</div>
</div>
<div class="line">
<div class="label">Label text</div>
<div class="text"> </div>
<div class="data" data-tag="label">value</div>
</div>
<div class="line">
<div class="data" data-tag="max-chaos"> very </div>
<div class="data" data-tag="min-chaos">42</div>
<div class="data" data-tag="some-chaos">42
</div>
<div class="text">Connecting to </div>
<div class="data" data-tag="host">my-box</div>
<div class="text">.</div>
<div class="data" data-tag="domain">example.com</div>
<div class="text">...</div>
</div>
<div class="line">
<div class="title">Item </div>
<div class="title"> Total Sold</div>
<div class="title"> In Stock</div>
<div class="title"> On Order</div>
<div class="title"> SKU</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-key="key">gum </div>
<div class="data" data-tag="sold"> 1412</div>
<div class="data" data-tag="in-stock"> 54</div>
<div class="data" data-tag="on-order"> 10</div>
<div class="data" data-tag="sku" data-key="key"> GRO-000-415</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-key="key">rope </div>
<div class="data" data-tag="sold"> 85</div>
<div class="data" data-tag="in-stock"> 4</div>
<div class="data" data-tag="on-order"> 2</div>
<div class="data" data-tag="sku" data-key="key"> HRD-000-212</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-key="key">ladder </div>
<div class="data" data-tag="sold"> 0</div>
<div class="data" data-tag="in-stock"> 2</div>
<div class="data" data-tag="on-order"> 1</div>
<div class="data" data-tag="sku" data-key="key"> HRD-000-517</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-key="key">bolt </div>
<div class="data" data-tag="sold"> 4123</div>
<div class="data" data-tag="in-stock"> 144</div>
<div class="data" data-tag="on-order"> 42</div>
<div class="data" data-tag="sku" data-key="key"> HRD-000-632</div>
</div>
<div class="line">
<div class="data" data-tag="name" data-key="key">water </div>
<div class="data" data-tag="sold"> 17</div>
<div class="data" data-tag="in-stock"> 14</div>
<div class="data" data-tag="on-order"> 2</div>
<div class="data" data-tag="sku" data-key="key"> GRO-000-2331</div>
</div>
<div class="line">
</div>
<div class="line">
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">gum</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">1412.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">54</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">10</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">GRO-000-415</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">rope</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">85.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">4</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">HRD-000-212</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">ladder</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">HRD-000-517</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">bolt</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">4123.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">144</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">42</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">HRD-000-632</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">water</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">17.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">14</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">2</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">GRO-000-2331</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="text"> '</div>
<div class="data" data-tag="name" data-key="key">fish</div>
<div class="text">':</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">Total sold</div>
<div class="text">: </div>
<div class="data" data-tag="sold">1321.0</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">In stock</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="in-stock">45</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">On order</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="on-order">1</div>
</div>
<div class="line">
<div class="padding"> </div>
<div class="label">SKU</div>
<div class="text">: </div>
<div class="data" data-tag="sku" data-key="key">GRO-000-533</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item">gum</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item">rope</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item">ladder</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item">bolt</div>
</div>
<div class="line">
<div class="label">Item</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="item">water</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
<div class="text">X</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="padding"> </div>
<div class="text">X</div>
<div class="label">Cost</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="cost">425</div>
</div>
<div class="line">
<div class="text">X</div>
<div class="padding"> </div>
<div class="text">X</div>
<div class="label">Cost</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="cost">455</div>
</div>
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="links">links</div>
<div class="text"> </div>
<div class="data" data-tag="user">user</div>
<div class="text"> </div>
<div class="data" data-tag="group">group</div>
<div class="text"> </div>
</div>
<div class="line">
<div class="data" data-tag="links">3 </div>
<div class="data" data-tag="post">this </div>
</div>
<div class="line">
<div class="data" data-tag="mode">/some/file</div>
<div class="text"> </div>
<div class="data" data-tag="links"> 1</div>
<div class="text"> </div>
<div class="data" data-tag="user">user </div>
<div class="text"> </div>
<div class="data" data-tag="group">group </div>
<div class="text"> </div>
</div>

View File

View File

@ -0,0 +1,2 @@
{"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"}
}

View File

View File

@ -0,0 +1,140 @@
{
"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"
}
}

View File

View File

@ -0,0 +1,58 @@
static ethernet bridge 18u 24anchor 0x0..1
anchor 0x0..1
anchor 0x0..1
df 12%
testing argument modifier my-box.example.com...
testing argument modifier with encoding to .example.com...
Label text value
very 4242
Connecting to my-box.example.com...
Item Total Sold In Stock On Order SKU
gum 1412 54 10 GRO-000-415
rope 85 4 2 HRD-000-212
ladder 0 2 1 HRD-000-517
bolt 4123 144 42 HRD-000-632
water 17 14 2 GRO-000-2331
Item 'gum':
Total sold: 1412.0
In stock: 54
On order: 10
SKU: GRO-000-415
Item 'rope':
Total sold: 85.0
In stock: 4
On order: 2
SKU: HRD-000-212
Item 'ladder':
Total sold: 0
In stock: 2
On order: 1
SKU: HRD-000-517
Item 'bolt':
Total sold: 4123.0
In stock: 144
On order: 42
SKU: HRD-000-632
Item 'water':
Total sold: 17.0
In stock: 14
On order: 2
SKU: GRO-000-2331
Item 'fish':
Total sold: 1321.0
In stock: 45
On order: 1
SKU: GRO-000-533
Item: gum
Item: rope
Item: ladder
Item: bolt
Item: water
XXXXXXXX
X XCost: 425
X XCost: 455
links user group
3 this
/some/file 1 user group

View File

View File

@ -0,0 +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>

View File

View File

@ -0,0 +1,130 @@
<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>

View File

Some files were not shown because too many files have changed in this diff Show More