Tag libxo 0.9.0
This commit is contained in:
parent
d58b3d7d3d
commit
f701945270
46
0.9.0/.gitignore
vendored
Normal file
46
0.9.0/.gitignore
vendored
Normal 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
18
0.9.0/.svnignore
Normal 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
12
0.9.0/.travis.yml
Normal 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
23
0.9.0/Copyright
Normal 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
15
0.9.0/INSTALL.md
Normal 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
23
0.9.0/LICENSE
Normal 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
143
0.9.0/Makefile.am
Normal 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
64
0.9.0/README.md
Normal 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
498
0.9.0/configure.ac
Normal 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
75
0.9.0/doc/Makefile.am
Normal 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
657
0.9.0/doc/_static/basic.css_t
vendored
Normal 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
14
0.9.0/doc/_templates/localtoc.html
vendored
Normal 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
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
178
0.9.0/doc/conf.py
Normal 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
694
0.9.0/doc/example.rst
Normal 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
209
0.9.0/doc/faq.rst
Normal 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
|
370
0.9.0/doc/field-formatting.rst
Normal file
370
0.9.0/doc/field-formatting.rst
Normal 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>
|
353
0.9.0/doc/field-modifiers.rst
Normal file
353
0.9.0/doc/field-modifiers.rst
Normal 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
310
0.9.0/doc/field-roles.rst
Normal 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.
|
47
0.9.0/doc/format-strings.rst
Normal file
47
0.9.0/doc/format-strings.rst
Normal 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
165
0.9.0/doc/formatting.rst
Normal 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
185
0.9.0/doc/getting.rst
Normal 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
394
0.9.0/doc/howto.rst
Normal 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
53
0.9.0/doc/index.rst
Normal 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
90
0.9.0/doc/intro.rst
Normal 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
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
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
164
0.9.0/doc/options.rst
Normal 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
125
0.9.0/doc/xo.rst
Normal 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
30
0.9.0/doc/xohtml.rst
Normal 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
40
0.9.0/doc/xolint.rst
Normal 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
45
0.9.0/doc/xopo.rst
Normal 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.
|
9
0.9.0/encoder/Makefile.am
Normal file
9
0.9.0/encoder/Makefile.am
Normal 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
|
51
0.9.0/encoder/cbor/Makefile.am
Normal file
51
0.9.0/encoder/cbor/Makefile.am
Normal 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}
|
365
0.9.0/encoder/cbor/enc_cbor.c
Normal file
365
0.9.0/encoder/cbor/enc_cbor.c
Normal 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;
|
||||
}
|
51
0.9.0/encoder/test/Makefile.am
Normal file
51
0.9.0/encoder/test/Makefile.am
Normal 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}
|
30
0.9.0/encoder/test/enc_test.c
Normal file
30
0.9.0/encoder/test/enc_test.c
Normal 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
119
0.9.0/libxo-config.in
Normal 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
94
0.9.0/libxo/Makefile.am
Normal 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
29
0.9.0/libxo/add.man.in
Normal 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
76
0.9.0/libxo/gen-wide.sh
Executable 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
323
0.9.0/libxo/libxo.3
Normal 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
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
683
0.9.0/libxo/xo.h
Normal 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
70
0.9.0/libxo/xo_attr.3
Normal 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
158
0.9.0/libxo/xo_buf.h
Normal 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
77
0.9.0/libxo/xo_create.3
Normal 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
114
0.9.0/libxo/xo_emit.3
Normal 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
82
0.9.0/libxo/xo_emit_err.3
Normal 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
121
0.9.0/libxo/xo_emit_f.3
Normal 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
375
0.9.0/libxo/xo_encoder.c
Normal 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
117
0.9.0/libxo/xo_encoder.h
Normal 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
84
0.9.0/libxo/xo_err.3
Normal 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
51
0.9.0/libxo/xo_error.3
Normal 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
49
0.9.0/libxo/xo_finish.3
Normal 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
45
0.9.0/libxo/xo_flush.3
Normal 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
977
0.9.0/libxo/xo_format.5
Normal 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
169
0.9.0/libxo/xo_humanize.h
Normal 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
78
0.9.0/libxo/xo_message.3
Normal 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 .
|
||||
|
53
0.9.0/libxo/xo_no_setlocale.3
Normal file
53
0.9.0/libxo/xo_no_setlocale.3
Normal 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 .
|
||||
|
198
0.9.0/libxo/xo_open_container.3
Normal file
198
0.9.0/libxo/xo_open_container.3
Normal 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
168
0.9.0/libxo/xo_open_list.3
Normal 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 .
|
||||
|
115
0.9.0/libxo/xo_open_marker.3
Normal file
115
0.9.0/libxo/xo_open_marker.3
Normal 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
156
0.9.0/libxo/xo_options.7
Normal 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
162
0.9.0/libxo/xo_parse_args.3
Normal 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 .
|
||||
|
64
0.9.0/libxo/xo_set_allocator.3
Normal file
64
0.9.0/libxo/xo_set_allocator.3
Normal 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
149
0.9.0/libxo/xo_set_flags.3
Normal 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
112
0.9.0/libxo/xo_set_info.3
Normal 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 .
|
||||
|
41
0.9.0/libxo/xo_set_options.3
Normal file
41
0.9.0/libxo/xo_set_options.3
Normal 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 .
|
||||
|
63
0.9.0/libxo/xo_set_style.3
Normal file
63
0.9.0/libxo/xo_set_style.3
Normal 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 .
|
||||
|
46
0.9.0/libxo/xo_set_syslog_enterprise_id.3
Normal file
46
0.9.0/libxo/xo_set_syslog_enterprise_id.3
Normal 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 .
|
||||
|
44
0.9.0/libxo/xo_set_version.3
Normal file
44
0.9.0/libxo/xo_set_version.3
Normal 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 .
|
||||
|
66
0.9.0/libxo/xo_set_writer.3
Normal file
66
0.9.0/libxo/xo_set_writer.3
Normal 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
89
0.9.0/libxo/xo_syslog.3
Normal 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
711
0.9.0/libxo/xo_syslog.c
Normal 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
313
0.9.0/libxo/xo_wcwidth.h
Normal 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 */
|
11
0.9.0/packaging/libxo.pc.in
Normal file
11
0.9.0/packaging/libxo.pc.in
Normal 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@
|
20
0.9.0/packaging/libxo.rb.base.in
Normal file
20
0.9.0/packaging/libxo.rb.base.in
Normal 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
|
44
0.9.0/packaging/libxo.spec.in
Normal file
44
0.9.0/packaging/libxo.spec.in
Normal 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
32
0.9.0/tests/Makefile.am
Normal 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
|
129
0.9.0/tests/core/Makefile.am
Normal file
129
0.9.0/tests/core/Makefile.am
Normal 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}
|
0
0.9.0/tests/core/saved/test_01.E.err
Normal file
0
0.9.0/tests/core/saved/test_01.E.err
Normal file
153
0.9.0/tests/core/saved/test_01.E.out
Normal file
153
0.9.0/tests/core/saved/test_01.E.out
Normal 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]
|
0
0.9.0/tests/core/saved/test_01.H.err
Normal file
0
0.9.0/tests/core/saved/test_01.H.err
Normal file
2
0.9.0/tests/core/saved/test_01.H.out
Normal file
2
0.9.0/tests/core/saved/test_01.H.out
Normal file
File diff suppressed because one or more lines are too long
0
0.9.0/tests/core/saved/test_01.HIPx.err
Normal file
0
0.9.0/tests/core/saved/test_01.HIPx.err
Normal file
382
0.9.0/tests/core/saved/test_01.HIPx.out
Normal file
382
0.9.0/tests/core/saved/test_01.HIPx.out
Normal 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>
|
0
0.9.0/tests/core/saved/test_01.HP.err
Normal file
0
0.9.0/tests/core/saved/test_01.HP.err
Normal file
382
0.9.0/tests/core/saved/test_01.HP.out
Normal file
382
0.9.0/tests/core/saved/test_01.HP.out
Normal 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>
|
0
0.9.0/tests/core/saved/test_01.J.err
Normal file
0
0.9.0/tests/core/saved/test_01.J.err
Normal file
2
0.9.0/tests/core/saved/test_01.J.out
Normal file
2
0.9.0/tests/core/saved/test_01.J.out
Normal 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"}
|
||||
}
|
0
0.9.0/tests/core/saved/test_01.JP.err
Normal file
0
0.9.0/tests/core/saved/test_01.JP.err
Normal file
140
0.9.0/tests/core/saved/test_01.JP.out
Normal file
140
0.9.0/tests/core/saved/test_01.JP.out
Normal 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"
|
||||
}
|
||||
}
|
0
0.9.0/tests/core/saved/test_01.T.err
Normal file
0
0.9.0/tests/core/saved/test_01.T.err
Normal file
58
0.9.0/tests/core/saved/test_01.T.out
Normal file
58
0.9.0/tests/core/saved/test_01.T.out
Normal 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
|
0
0.9.0/tests/core/saved/test_01.X.err
Normal file
0
0.9.0/tests/core/saved/test_01.X.err
Normal file
1
0.9.0/tests/core/saved/test_01.X.out
Normal file
1
0.9.0/tests/core/saved/test_01.X.out
Normal 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>
|
0
0.9.0/tests/core/saved/test_01.XP.err
Normal file
0
0.9.0/tests/core/saved/test_01.XP.err
Normal file
130
0.9.0/tests/core/saved/test_01.XP.out
Normal file
130
0.9.0/tests/core/saved/test_01.XP.out
Normal 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>
|
0
0.9.0/tests/core/saved/test_01.err
Normal file
0
0.9.0/tests/core/saved/test_01.err
Normal file
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user