Moving libxo to properly tracked, 3rd-Party imported handling.

Reviewed by: phil, sjg
This commit is contained in:
David E. O'Brien 2016-03-16 23:06:34 +00:00
commit 6c5bdc21e1
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/Juniper/libxo/dist/; revision=296962
345 changed files with 54139 additions and 0 deletions

12
.travis.yml Normal file
View File

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

23
Copyright Normal file
View File

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

15
INSTALL.md Normal file
View File

@ -0,0 +1,15 @@
<!---
# $Id$
#
# Copyright 2015, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
#-->
## Instructions for building libxo
Instructions for building libxo are now available in the
[wiki](http://juniper.github.io/libxo/libxo-manual.html#getting-libxo).

23
LICENSE Normal file
View File

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

102
Makefile.am Normal file
View File

@ -0,0 +1,102 @@
#
# $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
upload: dist upload-docs
@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
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 ..." \
&& 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:
${ANALYZE_CMD} -o ${ANALYZE_DIR} ${MAKE}

64
README.md Normal file
View File

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

29
bin/Makefile.am Normal file
View File

@ -0,0 +1,29 @@
#
# Copyright 2013, 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
EXTRA_DIST = gt setup.sh
GT_INSTALL_DIR = ${prefix}/bin
GT_INSTALL_FILES = gt
install-data-hook:
@echo "Installing gt ... "
@-mkdir -p ${GT_INSTALL_DIR}
@for file in ${GT_INSTALL_FILES} ; do \
if [ -f $$file ]; then \
rfile=$$file ; \
else \
rfile=${srcdir}/$$file ; \
fi ; \
mdir=${GT_INSTALL_DIR}/ ; \
mkdir -p $$mdir ; \
cp $$rfile $$mdir/ ; \
done
@${CHMOD} a+x ${GT_INSTALL_DIR}/gt

29
bin/Zaliases Normal file
View File

@ -0,0 +1,29 @@
set top_src=`pwd`
alias Zautoreconf "(cd $top_src ; autoreconf)"
set opts=' \
--with-libslax-prefix=/Users/phil/work/root \
--enable-debug \
--enable-warnings \
--enable-printflike \
--with-gettext=/opt/local \
--prefix ${HOME}/work/root \
'
set opts=`echo $opts`
setenv CONFIGURE_OPTS "$opts"
setenv ADB_PATH $top_src/build/libxo/.libs
alias Zconfigure "(cd $top_src/build; ../configure $opts)"
alias Zbuild "(cd $top_src/build; make \!* )"
alias mi "(cd $top_src/build; make && make install); ."
mkdir -p build
cd build
alias xx 'cc -I.. -W -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Werror -Waggregate-return -Wcast-align -Wcast-qual -Wchar-subscripts -Wcomment -Wformat -Wimplicit -Wmissing-declarations -Wnested-externs -Wparentheses -Wreturn-type -Wshadow -Wswitch -Wtrigraphs -Wuninitialized -Wunused -Wwrite-strings -fno-inline-functions-called-once -g -O2 -o xtest -DUNIT_TEST libxo.c'
alias mm "make CFLAGS='-O0 -g'"
alias mmi 'mm && mi'

33
bin/setup.sh Executable file
View File

@ -0,0 +1,33 @@
#
# Copyright 2013, 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 [ ! -f configure ]; then
vers=`autoreconf --version | head -1`
echo "Using" $vers
mkdir -p m4
autoreconf --install
if [ ! -f configure ]; then
echo "Failed to create configure script"
exit 1
fi
fi
echo "Creating build directory ..."
mkdir build
echo "Setup is complete. To build libslax:"
echo " 1) Type 'cd build ; ../configure' to configure libslax"
echo " 2) Type 'make' to build libslax"
echo " 3) Type 'make install' to install libslax"
exit 0

0
build/.create Normal file
View File

452
configure.ac Normal file
View File

@ -0,0 +1,452 @@
#
# $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.4.5], [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
AM_PROG_AR
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])
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
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_BINDIR=${GETTEXT_PREFIX}/bin
AC_SUBST(GETTEXT_BINDIR)
GETTEXT_LIBDIR=${GETTEXT_PREFIX}/lib
AC_SUBST(GETTEXT_LIBDIR)
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 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_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}
AC_SUBST(XO_SRCDIR)
AC_SUBST(XO_LIBDIR)
AC_SUBST(XO_BINDIR)
AC_SUBST(XO_INCLUDEDIR)
AC_SUBST(XO_LIBEXT)
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}
])

70
doc/Makefile.am Normal file
View File

@ -0,0 +1,70 @@
#
# $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}.txt \
${INPUT}.fxml \
${INPUT}.html
else
doc docs:
@${ECHO} "The 'oxtradoc' tool is not installed; see libslax.org"
endif

3757
doc/libxo.txt Normal file

File diff suppressed because it is too large Load Diff

9
encoder/Makefile.am Normal file
View File

@ -0,0 +1,9 @@
#
# Copyright 2015, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
SUBDIRS = cbor test

51
encoder/cbor/Makefile.am Normal file
View File

@ -0,0 +1,51 @@
#
# $Id$
#
# Copyright 2015, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
if LIBXO_WARNINGS_HIGH
LIBXO_WARNINGS = HIGH
endif
if HAVE_GCC
GCC_WARNINGS = yes
endif
include ${top_srcdir}/warnings.mk
enc_cborincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir}/libxo \
-I${top_builddir}/libxo \
${WARNINGS}
LIBNAME = libenc_cbor
pkglib_LTLIBRARIES = libenc_cbor.la
LIBS = \
-L${top_builddir}/libxo -lxo
LDADD = ${top_builddir}/libxo/libxo.la
libenc_cbor_la_SOURCES = \
enc_cbor.c
pkglibdir = ${XO_ENCODERDIR}
UGLY_NAME = cbor.enc
install-exec-hook:
@DLNAME=`sh -c '. ./libenc_cbor.la ; echo $$dlname'` ; \
if [ x"$$DLNAME" = x ]; \
then DLNAME=${LIBNAME}.${XO_LIBEXT}; fi ; \
if [ "$(build_os)" = "cygwin" ]; \
then DLNAME="../bin/$$DLNAME"; fi ; \
echo Install link $$DLNAME "->" ${UGLY_NAME} "..." ; \
mkdir -p ${DESTDIR}${XO_ENCODERDIR} ; \
cd ${DESTDIR}${XO_ENCODERDIR} \
&& chmod +w . \
&& rm -f ${UGLY_NAME} \
&& ${LN_S} $$DLNAME ${UGLY_NAME}

365
encoder/cbor/enc_cbor.c Normal file
View File

@ -0,0 +1,365 @@
/*
* Copyright (c) 2015, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
* using the SOFTWARE, you agree to be bound by the terms of that
* LICENSE.
* Phil Shafer, August 2015
*/
/*
* CBOR (RFC 7049) mades a suitable test case for libxo's external
* encoder API. It's simple, streaming, well documented, and an
* IETF standard.
*
* This encoder uses the "pretty" flag for diagnostics, which isn't
* really kosher, but it's example code.
*/
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include "xo.h"
#include "xo_encoder.h"
#include "xo_buf.h"
/*
* memdump(): dump memory contents in hex/ascii
0 1 2 3 4 5 6 7
0123456789012345678901234567890123456789012345678901234567890123456789012345
XX XX XX XX XX XX XX XX - XX XX XX XX XX XX XX XX abcdefghijklmnop
*/
static void
cbor_memdump (FILE *fp, const char *title, const char *data,
size_t len, const char *tag, int indent)
{
enum { MAX_PER_LINE = 16 };
char buf[ 80 ];
char text[ 80 ];
char *bp, *tp;
size_t i;
#if 0
static const int ends[ MAX_PER_LINE ] = { 2, 5, 8, 11, 15, 18, 21, 24,
29, 32, 35, 38, 42, 45, 48, 51 };
#endif
if (fp == NULL)
fp = stdout;
if (tag == NULL)
tag = "";
fprintf(fp, "%*s[%s] @ %p (%lx/%lu)\n", indent + 1, tag,
title, data, (unsigned long) len, (unsigned long) len);
while (len > 0) {
bp = buf;
tp = text;
for (i = 0; i < MAX_PER_LINE && i < len; i++) {
if (i && (i % 4) == 0) *bp++ = ' ';
if (i == 8) {
*bp++ = '-';
*bp++ = ' ';
}
sprintf(bp, "%02x ", (unsigned char) *data);
bp += strlen(bp);
*tp++ = (isprint((int) *data) && *data >= ' ') ? *data : '.';
data += 1;
}
*tp = 0;
*bp = 0;
fprintf(fp, "%*s%-54s%s\n", indent + 1, tag, buf, text);
len -= i;
}
}
/*
* CBOR breaks the first byte into two pieces, the major type in the
* top 3 bits and the minor value in the low 5 bits. The value can be
* a small value (0 .. 23), an 8-bit value (24), a 16-bit value (25),
* a 32-bit value (26), or a 64-bit value (27). A value of 31
* represents an unknown length, which we'll use extensively for
* streaming our content.
*/
#define CBOR_MAJOR_MASK 0xE0
#define CBOR_MINOR_MASK 0x1F
#define CBOR_MAJOR_SHIFT 5
#define CBOR_MAJOR(_x) ((_x) & CBOR_MAJOR_MASK)
#define CBOR_MAJOR_VAL(_x) ((_x) << CBOR_MAJOR_SHIFT)
#define CBOR_MINOR_VAL(_x) ((_x) & CBOR_MINOR_MASK)
/* Major type codes */
#define CBOR_UNSIGNED CBOR_MAJOR_VAL(0) /* 0x00 */
#define CBOR_NEGATIVE CBOR_MAJOR_VAL(1) /* 0x20 */
#define CBOR_BYTES CBOR_MAJOR_VAL(2) /* 0x40 */
#define CBOR_STRING CBOR_MAJOR_VAL(3) /* 0x60 */
#define CBOR_ARRAY CBOR_MAJOR_VAL(4) /* 0x80 */
#define CBOR_MAP CBOR_MAJOR_VAL(5) /* 0xa0 */
#define CBOR_SEMANTIC CBOR_MAJOR_VAL(6) /* 0xc0 */
#define CBOR_SPECIAL CBOR_MAJOR_VAL(7) /* 0xe0 */
#define CBOR_ULIMIT 24 /* Largest unsigned value */
#define CBOR_NLIMIT 23 /* Largest negative value */
#define CBOR_BREAK 0xFF
#define CBOR_INDEF 0x1F
#define CBOR_FALSE 0xF4
#define CBOR_TRUE 0xF5
#define CBOR_NULL 0xF6
#define CBOR_UNDEF 0xF7
#define CBOR_LEN8 0x18 /* 24 - 8-bit value */
#define CBOR_LEN16 0x19 /* 25 - 16-bit value */
#define CBOR_LEN32 0x1a /* 26 - 32-bit value */
#define CBOR_LEN64 0x1b /* 27 - 64-bit value */
#define CBOR_LEN128 0x1c /* 28 - 128-bit value */
typedef struct cbor_private_s {
xo_buffer_t c_data; /* Our data buffer */
unsigned c_indent; /* Indent level */
unsigned c_open_leaf_list; /* Open leaf list construct? */
} cbor_private_t;
static void
cbor_encode_uint (xo_buffer_t *xbp, uint64_t minor, unsigned limit)
{
char *bp = xbp->xb_curp;
int i, m;
if (minor > (1UL<<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
encoder/test/Makefile.am Normal file
View File

@ -0,0 +1,51 @@
#
# $Id$
#
# Copyright 2015, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
if LIBXO_WARNINGS_HIGH
LIBXO_WARNINGS = HIGH
endif
if HAVE_GCC
GCC_WARNINGS = yes
endif
include ${top_srcdir}/warnings.mk
enc_testincdir = ${includedir}/libxo
AM_CFLAGS = \
-I${top_srcdir}/libxo \
-I${top_builddir}/libxo \
${WARNINGS}
LIBNAME = libenc_test
pkglib_LTLIBRARIES = libenc_test.la
LIBS = \
-L${top_builddir}/libxo -lxo
LDADD = ${top_builddir}/libxo/libxo.la
libenc_test_la_SOURCES = \
enc_test.c
pkglibdir = ${XO_ENCODERDIR}
UGLY_NAME = test.enc
install-exec-hook:
@DLNAME=`sh -c '. ./libenc_test.la ; echo $$dlname'` ; \
if [ x"$$DLNAME" = x ]; \
then DLNAME=${LIBNAME}.${XO_LIBEXT}; fi ; \
if [ "$(build_os)" = "cygwin" ]; \
then DLNAME="../bin/$$DLNAME"; fi ; \
echo Install link $$DLNAME "->" ${UGLY_NAME} "..." ; \
mkdir -p ${DESTDIR}${XO_ENCODERDIR} ; \
cd ${DESTDIR}${XO_ENCODERDIR} \
&& chmod +w . \
&& rm -f ${UGLY_NAME} \
&& ${LN_S} $$DLNAME ${UGLY_NAME}

30
encoder/test/enc_test.c Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright (c) 2015, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
* using the SOFTWARE, you agree to be bound by the terms of that
* LICENSE.
* Phil Shafer, August 2015
*/
#include "xo.h"
#include "xo_encoder.h"
static int
test_handler (XO_ENCODER_HANDLER_ARGS)
{
printf("op %s: [%s] [%s]\n", xo_encoder_op_name(op),
name ?: "", value ?: "");
return 0;
}
int
xo_encoder_library_init (XO_ENCODER_INIT_ARGS)
{
arg->xei_version = XO_ENCODER_VERSION;
arg->xei_handler = test_handler;
return 0;
}

527
install-sh Executable file
View File

@ -0,0 +1,527 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2011-11-20.07; # UTC
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# 'make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit=${DOITPROG-}
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
chgrpprog=${CHGRPPROG-chgrp}
chmodprog=${CHMODPROG-chmod}
chownprog=${CHOWNPROG-chown}
cmpprog=${CMPPROG-cmp}
cpprog=${CPPROG-cp}
mkdirprog=${MKDIRPROG-mkdir}
mvprog=${MVPROG-mv}
rmprog=${RMPROG-rm}
stripprog=${STRIPPROG-strip}
posix_glob='?'
initialize_posix_glob='
test "$posix_glob" != "?" || {
if (set -f) 2>/dev/null; then
posix_glob=
else
posix_glob=:
fi
}
'
posix_mkdir=
# Desired mode of installed file.
mode=0755
chgrpcmd=
chmodcmd=$chmodprog
chowncmd=
mvcmd=$mvprog
rmcmd="$rmprog -f"
stripcmd=
src=
dst=
dir_arg=
dst_arg=
copy_on_change=false
no_target_directory=
usage="\
Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
--help display this help and exit.
--version display version info and exit.
-c (ignored)
-C install only if different (preserve the last data modification time)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) ;;
-C) copy_on_change=true;;
-d) dir_arg=true;;
-g) chgrpcmd="$chgrpprog $2"
shift;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
shift;;
-o) chowncmd="$chownprog $2"
shift;;
-s) stripcmd=$stripprog;;
-t) dst_arg=$2
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
shift;;
-T) no_target_directory=true;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
shift
done
if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dst_arg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dst_arg"
shift # fnord
fi
shift # arg
dst_arg=$arg
# Protect names problematic for 'test' and other utilities.
case $dst_arg in
-* | [=\(\)!]) dst_arg=./$dst_arg;;
esac
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call 'install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
do_exit='(exit $ret); exit $ret'
trap "ret=129; $do_exit" 1
trap "ret=130; $do_exit" 2
trap "ret=141; $do_exit" 13
trap "ret=143; $do_exit" 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names problematic for 'test' and other utilities.
case $src in
-* | [=\(\)!]) src=./$src;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dst_arg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dst_arg
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dst_arg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix='/';;
[-=\(\)!]*) prefix='./';;
*) prefix='';;
esac
eval "$initialize_posix_glob"
oIFS=$IFS
IFS=/
$posix_glob set -f
set fnord $dstdir
shift
$posix_glob set +f
IFS=$oIFS
prefixes=
for d
do
test X"$d" = X && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
{ test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
{ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# If -C, don't bother to copy if it wouldn't change the file.
if $copy_on_change &&
old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
eval "$initialize_posix_glob" &&
$posix_glob set -f &&
set X $old && old=:$2:$4:$5:$6 &&
set X $new && new=:$2:$4:$5:$6 &&
$posix_glob set +f &&
test "$old" = "$new" &&
$cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
then
rm -f "$dsttmp"
else
# Rename the file to the real destination.
$doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
{
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
test ! -f "$dst" ||
$doit $rmcmd -f "$dst" 2>/dev/null ||
{ $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
{ $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
} ||
{ echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
fi || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-time-zone: "UTC"
# time-stamp-end: "; # UTC"
# End:

119
libxo-config.in Normal file
View File

@ -0,0 +1,119 @@
#! /bin/sh
#
# $Id$
#
# Copyright 2011-2014, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
prefix=@prefix@
exec_prefix=@exec_prefix@
includedir=@includedir@
libdir=@libdir@
usage()
{
cat <<EOF
Usage: libxo-config [OPTION]
Known values for OPTION are:
--prefix=DIR change libxo prefix [default $prefix]
--exec-prefix=DIR change libxo exec prefix [default $exec_prefix]
--libs print library linking information
--bindir print the bin directory
--cflags print pre-processor and compiler flags
--share print share directory
--help display this help and exit
--version output version information
EOF
exit $1
}
if test $# -eq 0; then
usage 1
fi
cflags=false
libs=false
while test $# -gt 0; do
case "$1" in
-*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
*) optarg= ;;
esac
case "$1" in
--prefix=*)
prefix=$optarg
includedir=$prefix/include
libdir=$prefix/lib
;;
--prefix)
echo $prefix
;;
--exec-prefix=*)
exec_prefix=$optarg
libdir=$exec_prefix/lib
;;
--exec-prefix)
echo $exec_prefix
;;
--version)
echo @VERSION@
exit 0
;;
--help)
usage 0
;;
--cflags)
echo -I@LIBXO_INCLUDEDIR@ @LIBXO_CFLAGS@
;;
--share)
echo @LIBXO_SHAREDIR@
;;
--bindir)
echo @LIBXO_BINDIR@
;;
--libdir)
echo @LIBXO_LIBDIR@
;;
--libs)
if [ "`uname`" = "Linux" ]
then
if [ "@LIBXO_LIBDIR@" = "-L/usr/lib" -o "@LIBXO_LIBDIR@" = "-L/usr/lib64" ]
then
echo @LIBXO_LIBS@
else
echo -L@LIBXO_LIBDIR@ @LIBXO_LIBS@
fi
else
echo -L@LIBXO_LIBDIR@ @LIBXO_LIBS@ @WIN32_EXTRA_LIBADD@
fi
;;
*)
usage
exit 1
;;
esac
shift
done
exit 0

89
libxo/Makefile.am Normal file
View File

@ -0,0 +1,89 @@
#
# 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
man_MANS = ${man3_files} ${man5_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

29
libxo/add.man Normal file
View File

@ -0,0 +1,29 @@
.Sh ADDITIONAL DOCUMENTATION
.Fx
uses
.Nm libxo
version 0.4.3.
Complete documentation can be found on github:
.Bd -literal -offset indent
http://juniper.github.io/libxo/0.4.3/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

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

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

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

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

313
libxo/libxo.3 Normal file
View File

@ -0,0 +1,313 @@
.\" #
.\" # 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

7659
libxo/libxo.c Normal file

File diff suppressed because it is too large Load Diff

596
libxo/xo.h Normal file
View File

@ -0,0 +1,596 @@
/*
* 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 <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) && !defined(__linux__)
#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 */
/*
* 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 */
typedef int (*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 int (*xo_formatter_t)(xo_handle_t *, char *, int,
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);
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);
int
xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap);
int
xo_emit_h (xo_handle_t *xop, const char *fmt, ...);
int
xo_emit (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;
}
int
xo_open_container_h (xo_handle_t *xop, const char *name);
int
xo_open_container (const char *name);
int
xo_open_container_hd (xo_handle_t *xop, const char *name);
int
xo_open_container_d (const char *name);
int
xo_close_container_h (xo_handle_t *xop, const char *name);
int
xo_close_container (const char *name);
int
xo_close_container_hd (xo_handle_t *xop);
int
xo_close_container_d (void);
int
xo_open_list_h (xo_handle_t *xop, const char *name);
int
xo_open_list (const char *name);
int
xo_open_list_hd (xo_handle_t *xop, const char *name);
int
xo_open_list_d (const char *name);
int
xo_close_list_h (xo_handle_t *xop, const char *name);
int
xo_close_list (const char *name);
int
xo_close_list_hd (xo_handle_t *xop);
int
xo_close_list_d (void);
int
xo_open_instance_h (xo_handle_t *xop, const char *name);
int
xo_open_instance (const char *name);
int
xo_open_instance_hd (xo_handle_t *xop, const char *name);
int
xo_open_instance_d (const char *name);
int
xo_close_instance_h (xo_handle_t *xop, const char *name);
int
xo_close_instance (const char *name);
int
xo_close_instance_hd (xo_handle_t *xop);
int
xo_close_instance_d (void);
int
xo_open_marker_h (xo_handle_t *xop, const char *name);
int
xo_open_marker (const char *name);
int
xo_close_marker_h (xo_handle_t *xop, const char *name);
int
xo_close_marker (const char *name);
int
xo_attr_h (xo_handle_t *xop, const char *name, const char *fmt, ...);
int
xo_attr_hv (xo_handle_t *xop, const char *name, const char *fmt, va_list vap);
int
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, ...);
int
xo_flush_h (xo_handle_t *xop);
int
xo_flush (void);
int
xo_finish_h (xo_handle_t *xop);
int
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);
#endif /* INCLUDE_XO_H */

60
libxo/xo_attr.3 Normal file
View File

@ -0,0 +1,60 @@
.\" #
.\" # 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

158
libxo/xo_buf.h Normal file
View File

@ -0,0 +1,158 @@
/*
* Copyright (c) 2015, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
* using the SOFTWARE, you agree to be bound by the terms of that
* LICENSE.
* Phil Shafer, August 2015
*/
/*
* This file is an _internal_ part of the libxo plumbing, not suitable
* for external use. It is not considered part of the libxo API and
* will not be a stable part of that API. Mine, not your's, dude...
* The real hope is that something like this will become a standard part
* of libc and I can kill this off.
*/
#ifndef XO_BUF_H
#define XO_BUF_H
#define XO_BUFSIZ (8*1024) /* Initial buffer size */
/*
* 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 */
unsigned 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, int len)
{
if (xbp->xb_curp + len >= xbp->xb_bufp + xbp->xb_size) {
int 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, int len)
{
if (!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)
{
int 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 */

247
libxo/xo_config.h Normal file
View File

@ -0,0 +1,247 @@
/* libxo/xo_config.h. Generated from xo_config.h.in by configure. */
/* libxo/xo_config.h.in. Generated from configure.ac by autoheader. */
/* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
systems. This function is required for `alloca.c' support on those systems.
*/
/* #undef CRAY_STACKSEG_END */
/* Define to 1 if using `alloca.c'. */
/* #undef C_ALLOCA */
/* Define to 1 if you have `alloca', as a function or macro. */
#define HAVE_ALLOCA 1
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
*/
/* #undef HAVE_ALLOCA_H */
/* Define to 1 if you have the `asprintf' function. */
#define HAVE_ASPRINTF 1
/* Define to 1 if you have the `bzero' function. */
#define HAVE_BZERO 1
/* Define to 1 if you have the `ctime' function. */
#define HAVE_CTIME 1
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define to 1 if you have the declaration of `__isthreaded', and to 0 if you
don't. */
#define HAVE_DECL___ISTHREADED 1
/* Define to 1 if you have the <dlfcn.h> header file. */
#define HAVE_DLFCN_H 1
/* Define to 1 if you have the `dlfunc' function. */
#define HAVE_DLFUNC 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the `fdopen' function. */
#define HAVE_FDOPEN 1
/* Define to 1 if you have the `flock' function. */
#define HAVE_FLOCK 1
/* Define to 1 if you have the `getpass' function. */
#define HAVE_GETPASS 1
/* Define to 1 if you have the `getprogname' function. */
#define HAVE_GETPROGNAME 1
/* Define to 1 if you have the `getrusage' function. */
#define HAVE_GETRUSAGE 1
/* gettext(3) */
/* #undef HAVE_GETTEXT */
/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1
/* humanize_number(3) */
#define HAVE_HUMANIZE_NUMBER 1
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `crypto' library (-lcrypto). */
#define HAVE_LIBCRYPTO 1
/* Define to 1 if you have the `m' library (-lm). */
#define HAVE_LIBM 1
/* Define to 1 if you have the <libutil.h> header file. */
#define HAVE_LIBUTIL_H 1
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Support printflike */
/* #undef HAVE_PRINTFLIKE */
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
and to 0 otherwise. */
#define HAVE_REALLOC 1
/* Define to 1 if you have the `srand' function. */
#define HAVE_SRAND 1
/* Define to 1 if you have the `sranddev' function. */
#define HAVE_SRANDDEV 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio_ext.h> header file. */
/* #undef HAVE_STDIO_EXT_H */
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <stdtime/tzfile.h> header file. */
/* #undef HAVE_STDTIME_TZFILE_H */
/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the `strcspn' function. */
#define HAVE_STRCSPN 1
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strlcpy' function. */
#define HAVE_STRLCPY 1
/* Define to 1 if you have the `strspn' function. */
#define HAVE_STRSPN 1
/* Have struct sockaddr_un.sun_len */
#define HAVE_SUN_LEN 1
/* Define to 1 if you have the `sysctlbyname' function. */
#define HAVE_SYSCTLBYNAME 1
/* Define to 1 if you have the <sys/param.h> header file. */
#define HAVE_SYS_PARAM_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/sysctl.h> header file. */
#define HAVE_SYS_SYSCTL_H 1
/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <threads.h> header file. */
#define HAVE_THREADS_H 1
/* thread-local setting */
#define HAVE_THREAD_LOCAL THREAD_LOCAL_before
/* Define to 1 if you have the <tzfile.h> header file. */
/* #undef HAVE_TZFILE_H */
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if you have the `__flbf' function. */
/* #undef HAVE___FLBF */
/* Enable debugging */
/* #undef LIBXO_DEBUG */
/* Enable text-only rendering */
/* #undef LIBXO_TEXT_ONLY */
/* Version number as dotted value */
#define LIBXO_VERSION "0.4.3"
/* Version number extra information */
#define LIBXO_VERSION_EXTRA ""
/* Version number as a number */
#define LIBXO_VERSION_NUMBER 4003
/* Version number as string */
#define LIBXO_VERSION_STRING "4003"
/* Enable local wcwidth implementation */
#define LIBXO_WCWIDTH 1
/* Define to the sub-directory where libtool stores uninstalled libraries. */
#define LT_OBJDIR ".libs/"
/* Name of package */
#define PACKAGE "libxo"
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "phil@juniper.net"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libxo"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libxo 0.4.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libxo"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "0.4.3"
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at runtime.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
/* #undef STACK_DIRECTION */
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Version number of package */
#define VERSION "0.4.3"
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
/* #undef inline */
#endif
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to rpl_realloc if the replacement function should be used. */
/* #undef realloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

67
libxo/xo_create.3 Normal file
View File

@ -0,0 +1,67 @@
.\" #
.\" # 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

104
libxo/xo_emit.3 Normal file
View File

@ -0,0 +1,104 @@
.\" #
.\" # 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

72
libxo/xo_emit_err.3 Normal file
View File

@ -0,0 +1,72 @@
.\" #
.\" # 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

375
libxo/xo_encoder.c Normal file
View File

@ -0,0 +1,375 @@
/*
* Copyright (c) 2015, Juniper Networks, Inc.
* All rights reserved.
* This SOFTWARE is licensed under the LICENSE provided in the
* ../Copyright file. By downloading, installing, copying, or otherwise
* using the SOFTWARE, you agree to be bound by the terms of that
* LICENSE.
* Phil Shafer, August 2015
*/
/**
* libxo includes a number of fixed encoding styles. But other
* external encoders are need to deal with new encoders. Rather
* than expose a swarm of libxo internals, we create a distinct
* API, with a simpler API than we use internally.
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/queue.h>
#include <sys/param.h>
#include <dlfcn.h>
#include "xo_config.h"
#include "xo.h"
#include "xo_encoder.h"
#ifdef HAVE_DLFCN_H
#include <dlfcn.h>
#if !defined(HAVE_DLFUNC)
#define dlfunc(_p, _n) dlsym(_p, _n)
#endif
#else /* HAVE_DLFCN_H */
#define dlopen(_n, _f) NULL /* Fail */
#define dlsym(_p, _n) NULL /* Fail */
#define dlfunc(_p, _n) NULL /* Fail */
#endif /* HAVE_DLFCN_H */
static void xo_encoder_setup (void); /* Forward decl */
/*
* Need a simple string collection
*/
typedef struct xo_string_node_s {
TAILQ_ENTRY(xo_string_node_s) xs_link; /* Next string */
char xs_data[0]; /* String data */
} xo_string_node_t;
typedef TAILQ_HEAD(xo_string_list_s, xo_string_node_s) xo_string_list_t;
static inline void
xo_string_list_init (xo_string_list_t *listp)
{
if (listp->tqh_last == NULL)
TAILQ_INIT(listp);
}
static inline xo_string_node_t *
xo_string_add (xo_string_list_t *listp, const char *str)
{
if (listp == NULL || str == NULL)
return NULL;
xo_string_list_init(listp);
size_t len = strlen(str);
xo_string_node_t *xsp;
xsp = xo_realloc(NULL, sizeof(*xsp) + len + 1);
if (xsp) {
memcpy(xsp->xs_data, str, len);
xsp->xs_data[len] = '\0';
TAILQ_INSERT_TAIL(listp, xsp, xs_link);
}
return xsp;
}
#define XO_STRING_LIST_FOREACH(_xsp, _listp) \
xo_string_list_init(_listp); \
TAILQ_FOREACH(_xsp, _listp, xs_link)
static inline void
xo_string_list_clean (xo_string_list_t *listp)
{
xo_string_node_t *xsp;
xo_string_list_init(listp);
for (;;) {
xsp = TAILQ_FIRST(listp);
if (xsp == NULL)
break;
TAILQ_REMOVE(listp, xsp, xs_link);
xo_free(xsp);
}
}
static xo_string_list_t xo_encoder_path;
void
xo_encoder_path_add (const char *path)
{
xo_encoder_setup();
if (path)
xo_string_add(&xo_encoder_path, path);
}
/* ---------------------------------------------------------------------- */
typedef struct xo_encoder_node_s {
TAILQ_ENTRY(xo_encoder_node_s) xe_link; /* Next session */
char *xe_name; /* Name for this encoder */
xo_encoder_func_t xe_handler; /* Callback function */
void *xe_dlhandle; /* dlopen handle */
} xo_encoder_node_t;
typedef TAILQ_HEAD(xo_encoder_list_s, xo_encoder_node_s) xo_encoder_list_t;
#define XO_ENCODER_LIST_FOREACH(_xep, _listp) \
xo_encoder_list_init(_listp); \
TAILQ_FOREACH(_xep, _listp, xe_link)
static xo_encoder_list_t xo_encoders;
static void
xo_encoder_list_init (xo_encoder_list_t *listp)
{
if (listp->tqh_last == NULL)
TAILQ_INIT(listp);
}
static xo_encoder_node_t *
xo_encoder_list_add (const char *name)
{
if (name == NULL)
return NULL;
xo_encoder_node_t *xep = xo_realloc(NULL, sizeof(*xep));
if (xep) {
int 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;
int 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);
}
/*
* A couple of function varieties here, to allow for multiple
* use cases. This varient 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)
{
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);
}
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];
}

116
libxo/xo_encoder.h Normal file
View File

@ -0,0 +1,116 @@
/*
* 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__))
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);
void
xo_encoders_clean (void);
const char *
xo_encoder_op_name (xo_encoder_op_t op);
#endif /* XO_ENCODER_H */

74
libxo/xo_err.3 Normal file
View File

@ -0,0 +1,74 @@
.\" #
.\" # 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

41
libxo/xo_error.3 Normal file
View File

@ -0,0 +1,41 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.Dd December 4, 2014
.Dt LIBXO 3
.Os
.Sh NAME
.Nm xo_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

39
libxo/xo_finish.3 Normal file
View File

@ -0,0 +1,39 @@
.\" #
.\" # 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

35
libxo/xo_flush.3 Normal file
View File

@ -0,0 +1,35 @@
.\" #
.\" # 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

943
libxo/xo_format.5 Normal file
View File

@ -0,0 +1,943 @@
.\" #
.\" # 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 November 6, 2015
.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
'{' [ role | modifier ]* [',' long-names ]* ':' [ content ]
[ '/' field-format [ '/' encoding-format ]] '}'
.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 ('"in-stock": 65'), 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 preceeded 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
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'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.
.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 'w' 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 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 ('c') and a space ('w').
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 preceeded 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.
.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 ('{w:}').
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 'quotes' 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
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 'no-quotes' 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 ('{c:}').
It is purely a convenience feature.
.Pp
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.
.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's 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 '%' 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
'%' format-modifier * format-character
.Ed
.Pp
The format- modifier can be:
.Bl -bullet
.It
a '#' character, indicating the output value should be prefixed with
"0x", typically to indicate a base 16 (hex) value.
.It
a minus sign ('-'), indicating the output value should be padded on
the right instead of the left.
.It
a leading zero ('0') indicating the output value should be padded on the
left with zeroes instead of spaces (' ').
.It
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.
.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 'h' characters, indicating shorter input data.
.It
one or more 'l' characters, indicating longer input data.
.It
a 'z' character, indicating a 'size_t' argument.
.It
a 't' character, indicating a 'ptrdiff_t' argument.
.It
a ' ' character, indicating a space should be emitted before
positive numbers.
.It
a '+' character, indicating sign should emitted before any number.
.El
.Pp
Note that 'q', 'D', 'O', and 'U' 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 'e' or 'f'"
.It G "double " "as 'E' or 'F'"
.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 * " "'%#lx'"
.El
.Pp
The 'h' and 'l' 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 '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
.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 "'%n' is Not Supported"
.Nm libxo
does not support the '%n' 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'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.
.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

169
libxo/xo_humanize.h Normal file
View File

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

68
libxo/xo_message.3 Normal file
View File

@ -0,0 +1,68 @@
.\" #
.\" # 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

43
libxo/xo_no_setlocale.3 Normal file
View File

@ -0,0 +1,43 @@
.\" #
.\" # 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

188
libxo/xo_open_container.3 Normal file
View File

@ -0,0 +1,188 @@
.\" #
.\" # 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

158
libxo/xo_open_list.3 Normal file
View File

@ -0,0 +1,158 @@
.\" #
.\" # 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_instnace_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

105
libxo/xo_open_marker.3 Normal file
View File

@ -0,0 +1,105 @@
.\" #
.\" # 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

148
libxo/xo_parse_args.3 Normal file
View File

@ -0,0 +1,148 @@
.\" #
.\" # 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-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 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

54
libxo/xo_set_allocator.3 Normal file
View File

@ -0,0 +1,54 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.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

139
libxo/xo_set_flags.3 Normal file
View File

@ -0,0 +1,139 @@
.\" #
.\" # 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

102
libxo/xo_set_info.3 Normal file
View File

@ -0,0 +1,102 @@
.\" #
.\" # 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

31
libxo/xo_set_options.3 Normal file
View File

@ -0,0 +1,31 @@
.\" #
.\" # 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

53
libxo/xo_set_style.3 Normal file
View File

@ -0,0 +1,53 @@
.\" #
.\" # Copyright (c) 2014, Juniper Networks, Inc.
.\" # All rights reserved.
.\" # This SOFTWARE is licensed under the LICENSE provided in the
.\" # ../Copyright file. By downloading, installing, copying, or
.\" # using the SOFTWARE, you agree to be bound by the terms of that
.\" # LICENSE.
.\" # Phil Shafer, July 2014
.\"
.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

View File

@ -0,0 +1,36 @@
.\" #
.\" # 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

34
libxo/xo_set_version.3 Normal file
View File

@ -0,0 +1,34 @@
.\" #
.\" # 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

56
libxo/xo_set_writer.3 Normal file
View File

@ -0,0 +1,56 @@
.\" #
.\" # 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

79
libxo/xo_syslog.3 Normal file
View File

@ -0,0 +1,79 @@
.\" #
.\" # 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

706
libxo/xo_syslog.c Normal file
View File

@ -0,0 +1,706 @@
/*
* 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.
* 4. 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 <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 /* Bail; use "example" number */
#endif
#ifdef _SC_HOST_NAME_MAX
#define HOST_NAME_MAX _SC_HOST_NAME_MAX
#else
#define HOST_NAME_MAX 255
#endif /* _SC_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. */
if (xo_logstat & LOG_PERROR) {
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 size_t
xo_snprintf (char *out, size_t outsize, const char *fmt, ...)
{
int status;
size_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 int
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
libxo/xo_wcwidth.h Normal file
View File

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

8369
m4/libtool.m4 vendored Normal file

File diff suppressed because it is too large Load Diff

437
m4/ltoptions.m4 vendored Normal file
View File

@ -0,0 +1,437 @@
# Helper functions for option handling. -*- Autoconf -*-
#
# Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
# Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 8 ltoptions.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
# ------------------------------------------
m4_define([_LT_MANGLE_OPTION],
[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
# ---------------------------------------
# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
# matching handler defined, dispatch to it. Other OPTION-NAMEs are
# saved as a flag.
m4_define([_LT_SET_OPTION],
[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
_LT_MANGLE_DEFUN([$1], [$2]),
[m4_warning([Unknown $1 option '$2'])])[]dnl
])
# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
# ------------------------------------------------------------
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
m4_define([_LT_IF_OPTION],
[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
# -------------------------------------------------------
# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
# are set.
m4_define([_LT_UNLESS_OPTIONS],
[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
[m4_define([$0_found])])])[]dnl
m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
])[]dnl
])
# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
# ----------------------------------------
# OPTION-LIST is a space-separated list of Libtool options associated
# with MACRO-NAME. If any OPTION has a matching handler declared with
# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
# the unknown option and exit.
m4_defun([_LT_SET_OPTIONS],
[# Set options
m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
[_LT_SET_OPTION([$1], _LT_Option)])
m4_if([$1],[LT_INIT],[
dnl
dnl Simply set some default values (i.e off) if boolean options were not
dnl specified:
_LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
])
_LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
])
dnl
dnl If no reference was made to various pairs of opposing options, then
dnl we run the default mode handler for the pair. For example, if neither
dnl 'shared' nor 'disable-shared' was passed, we enable building of shared
dnl archives by default:
_LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
_LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
_LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
_LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
[_LT_ENABLE_FAST_INSTALL])
_LT_UNLESS_OPTIONS([LT_INIT], [aix-soname=aix aix-soname=both aix-soname=svr4],
[_LT_WITH_AIX_SONAME([aix])])
])
])# _LT_SET_OPTIONS
## --------------------------------- ##
## Macros to handle LT_INIT options. ##
## --------------------------------- ##
# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
# -----------------------------------------
m4_define([_LT_MANGLE_DEFUN],
[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
# -----------------------------------------------
m4_define([LT_OPTION_DEFINE],
[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
])# LT_OPTION_DEFINE
# dlopen
# ------
LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
])
AU_DEFUN([AC_LIBTOOL_DLOPEN],
[_LT_SET_OPTION([LT_INIT], [dlopen])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'dlopen' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
# win32-dll
# ---------
# Declare package support for building win32 dll's.
LT_OPTION_DEFINE([LT_INIT], [win32-dll],
[enable_win32_dll=yes
case $host in
*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
AC_CHECK_TOOL(AS, as, false)
AC_CHECK_TOOL(DLLTOOL, dlltool, false)
AC_CHECK_TOOL(OBJDUMP, objdump, false)
;;
esac
test -z "$AS" && AS=as
_LT_DECL([], [AS], [1], [Assembler program])dnl
test -z "$DLLTOOL" && DLLTOOL=dlltool
_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
test -z "$OBJDUMP" && OBJDUMP=objdump
_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
])# win32-dll
AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
[AC_REQUIRE([AC_CANONICAL_HOST])dnl
_LT_SET_OPTION([LT_INIT], [win32-dll])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'win32-dll' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
# _LT_ENABLE_SHARED([DEFAULT])
# ----------------------------
# implement the --enable-shared flag, and supports the 'shared' and
# 'disable-shared' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_SHARED],
[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([shared],
[AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
[build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_shared=yes ;;
no) enable_shared=no ;;
*)
enable_shared=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_shared=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
_LT_DECL([build_libtool_libs], [enable_shared], [0],
[Whether or not to build shared libraries])
])# _LT_ENABLE_SHARED
LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
# Old names:
AC_DEFUN([AC_ENABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
])
AC_DEFUN([AC_DISABLE_SHARED],
[_LT_SET_OPTION([LT_INIT], [disable-shared])
])
AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_SHARED], [])
dnl AC_DEFUN([AM_DISABLE_SHARED], [])
# _LT_ENABLE_STATIC([DEFAULT])
# ----------------------------
# implement the --enable-static flag, and support the 'static' and
# 'disable-static' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_STATIC],
[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([static],
[AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
[build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_static=yes ;;
no) enable_static=no ;;
*)
enable_static=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_static=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_static=]_LT_ENABLE_STATIC_DEFAULT)
_LT_DECL([build_old_libs], [enable_static], [0],
[Whether or not to build static libraries])
])# _LT_ENABLE_STATIC
LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
# Old names:
AC_DEFUN([AC_ENABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
])
AC_DEFUN([AC_DISABLE_STATIC],
[_LT_SET_OPTION([LT_INIT], [disable-static])
])
AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AM_ENABLE_STATIC], [])
dnl AC_DEFUN([AM_DISABLE_STATIC], [])
# _LT_ENABLE_FAST_INSTALL([DEFAULT])
# ----------------------------------
# implement the --enable-fast-install flag, and support the 'fast-install'
# and 'disable-fast-install' LT_INIT options.
# DEFAULT is either 'yes' or 'no'. If omitted, it defaults to 'yes'.
m4_define([_LT_ENABLE_FAST_INSTALL],
[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
AC_ARG_ENABLE([fast-install],
[AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
[optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
[p=${PACKAGE-default}
case $enableval in
yes) enable_fast_install=yes ;;
no) enable_fast_install=no ;;
*)
enable_fast_install=no
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for pkg in $enableval; do
IFS=$lt_save_ifs
if test "X$pkg" = "X$p"; then
enable_fast_install=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
_LT_DECL([fast_install], [enable_fast_install], [0],
[Whether or not to optimize for fast installation])dnl
])# _LT_ENABLE_FAST_INSTALL
LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
# Old names:
AU_DEFUN([AC_ENABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'fast-install' option into LT_INIT's first parameter.])
])
AU_DEFUN([AC_DISABLE_FAST_INSTALL],
[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you put
the 'disable-fast-install' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
# _LT_WITH_AIX_SONAME([DEFAULT])
# ----------------------------------
# implement the --with-aix-soname flag, and support the `aix-soname=aix'
# and `aix-soname=both' and `aix-soname=svr4' LT_INIT options. DEFAULT
# is either `aix', `both' or `svr4'. If omitted, it defaults to `aix'.
m4_define([_LT_WITH_AIX_SONAME],
[m4_define([_LT_WITH_AIX_SONAME_DEFAULT], [m4_if($1, svr4, svr4, m4_if($1, both, both, aix))])dnl
shared_archive_member_spec=
case $host,$enable_shared in
power*-*-aix[[5-9]]*,yes)
AC_MSG_CHECKING([which variant of shared library versioning to provide])
AC_ARG_WITH([aix-soname],
[AS_HELP_STRING([--with-aix-soname=aix|svr4|both],
[shared library versioning (aka "SONAME") variant to provide on AIX, @<:@default=]_LT_WITH_AIX_SONAME_DEFAULT[@:>@.])],
[case $withval in
aix|svr4|both)
;;
*)
AC_MSG_ERROR([Unknown argument to --with-aix-soname])
;;
esac
lt_cv_with_aix_soname=$with_aix_soname],
[AC_CACHE_VAL([lt_cv_with_aix_soname],
[lt_cv_with_aix_soname=]_LT_WITH_AIX_SONAME_DEFAULT)
with_aix_soname=$lt_cv_with_aix_soname])
AC_MSG_RESULT([$with_aix_soname])
if test aix != "$with_aix_soname"; then
# For the AIX way of multilib, we name the shared archive member
# based on the bitwidth used, traditionally 'shr.o' or 'shr_64.o',
# and 'shr.imp' or 'shr_64.imp', respectively, for the Import File.
# Even when GNU compilers ignore OBJECT_MODE but need '-maix64' flag,
# the AIX toolchain works better with OBJECT_MODE set (default 32).
if test 64 = "${OBJECT_MODE-32}"; then
shared_archive_member_spec=shr_64
else
shared_archive_member_spec=shr
fi
fi
;;
*)
with_aix_soname=aix
;;
esac
_LT_DECL([], [shared_archive_member_spec], [0],
[Shared archive member basename, for filename based shared library versioning on AIX])dnl
])# _LT_WITH_AIX_SONAME
LT_OPTION_DEFINE([LT_INIT], [aix-soname=aix], [_LT_WITH_AIX_SONAME([aix])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=both], [_LT_WITH_AIX_SONAME([both])])
LT_OPTION_DEFINE([LT_INIT], [aix-soname=svr4], [_LT_WITH_AIX_SONAME([svr4])])
# _LT_WITH_PIC([MODE])
# --------------------
# implement the --with-pic flag, and support the 'pic-only' and 'no-pic'
# LT_INIT options.
# MODE is either 'yes' or 'no'. If omitted, it defaults to 'both'.
m4_define([_LT_WITH_PIC],
[AC_ARG_WITH([pic],
[AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
[try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
[lt_p=${PACKAGE-default}
case $withval in
yes|no) pic_mode=$withval ;;
*)
pic_mode=default
# Look at the argument we got. We use all the common list separators.
lt_save_ifs=$IFS; IFS=$IFS$PATH_SEPARATOR,
for lt_pkg in $withval; do
IFS=$lt_save_ifs
if test "X$lt_pkg" = "X$lt_p"; then
pic_mode=yes
fi
done
IFS=$lt_save_ifs
;;
esac],
[pic_mode=m4_default([$1], [default])])
_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
])# _LT_WITH_PIC
LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
# Old name:
AU_DEFUN([AC_LIBTOOL_PICMODE],
[_LT_SET_OPTION([LT_INIT], [pic-only])
AC_DIAGNOSE([obsolete],
[$0: Remove this warning and the call to _LT_SET_OPTION when you
put the 'pic-only' option into LT_INIT's first parameter.])
])
dnl aclocal-1.4 backwards compatibility:
dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
## ----------------- ##
## LTDL_INIT Options ##
## ----------------- ##
m4_define([_LTDL_MODE], [])
LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
[m4_define([_LTDL_MODE], [nonrecursive])])
LT_OPTION_DEFINE([LTDL_INIT], [recursive],
[m4_define([_LTDL_MODE], [recursive])])
LT_OPTION_DEFINE([LTDL_INIT], [subproject],
[m4_define([_LTDL_MODE], [subproject])])
m4_define([_LTDL_TYPE], [])
LT_OPTION_DEFINE([LTDL_INIT], [installable],
[m4_define([_LTDL_TYPE], [installable])])
LT_OPTION_DEFINE([LTDL_INIT], [convenience],
[m4_define([_LTDL_TYPE], [convenience])])

123
m4/ltsugar.m4 vendored Normal file
View File

@ -0,0 +1,123 @@
# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
# Written by Gary V. Vaughan, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 6 ltsugar.m4
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
# lt_join(SEP, ARG1, [ARG2...])
# -----------------------------
# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
# associated separator.
# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
# versions in m4sugar had bugs.
m4_define([lt_join],
[m4_if([$#], [1], [],
[$#], [2], [[$2]],
[m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
m4_define([_lt_join],
[m4_if([$#$2], [2], [],
[m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
# lt_car(LIST)
# lt_cdr(LIST)
# ------------
# Manipulate m4 lists.
# These macros are necessary as long as will still need to support
# Autoconf-2.59 which quotes differently.
m4_define([lt_car], [[$1]])
m4_define([lt_cdr],
[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
[$#], 1, [],
[m4_dquote(m4_shift($@))])])
m4_define([lt_unquote], $1)
# lt_append(MACRO-NAME, STRING, [SEPARATOR])
# ------------------------------------------
# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
# Note that neither SEPARATOR nor STRING are expanded; they are appended
# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
# No SEPARATOR is output if MACRO-NAME was previously undefined (different
# than defined and empty).
#
# This macro is needed until we can rely on Autoconf 2.62, since earlier
# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
m4_define([lt_append],
[m4_define([$1],
m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
# ----------------------------------------------------------
# Produce a SEP delimited list of all paired combinations of elements of
# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
# has the form PREFIXmINFIXSUFFIXn.
# Needed until we can rely on m4_combine added in Autoconf 2.62.
m4_define([lt_combine],
[m4_if(m4_eval([$# > 3]), [1],
[m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
[[m4_foreach([_Lt_prefix], [$2],
[m4_foreach([_Lt_suffix],
]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
[_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
# -----------------------------------------------------------------------
# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
m4_define([lt_if_append_uniq],
[m4_ifdef([$1],
[m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
[lt_append([$1], [$2], [$3])$4],
[$5])],
[lt_append([$1], [$2], [$3])$4])])
# lt_dict_add(DICT, KEY, VALUE)
# -----------------------------
m4_define([lt_dict_add],
[m4_define([$1($2)], [$3])])
# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
# --------------------------------------------
m4_define([lt_dict_add_subkey],
[m4_define([$1($2:$3)], [$4])])
# lt_dict_fetch(DICT, KEY, [SUBKEY])
# ----------------------------------
m4_define([lt_dict_fetch],
[m4_ifval([$3],
m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
# -----------------------------------------------------------------
m4_define([lt_if_dict_fetch],
[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
[$5],
[$6])])
# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
# --------------------------------------------------------------
m4_define([lt_dict_filter],
[m4_if([$5], [], [],
[lt_join(m4_quote(m4_default([$4], [[, ]])),
lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
[lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
])

23
m4/ltversion.m4 vendored Normal file
View File

@ -0,0 +1,23 @@
# ltversion.m4 -- version numbers -*- Autoconf -*-
#
# Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# @configure_input@
# serial 4179 ltversion.m4
# This file is part of GNU Libtool
m4_define([LT_PACKAGE_VERSION], [2.4.6])
m4_define([LT_PACKAGE_REVISION], [2.4.6])
AC_DEFUN([LTVERSION_VERSION],
[macro_version='2.4.6'
macro_revision='2.4.6'
_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
_LT_DECL(, macro_revision, 0)
])

98
m4/lt~obsolete.m4 vendored Normal file
View File

@ -0,0 +1,98 @@
# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
#
# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
# Written by Scott James Remnant, 2004.
#
# This file is free software; the Free Software Foundation gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
# serial 5 lt~obsolete.m4
# These exist entirely to fool aclocal when bootstrapping libtool.
#
# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
# which have later been changed to m4_define as they aren't part of the
# exported API, or moved to Autoconf or Automake where they belong.
#
# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
# using a macro with the same name in our local m4/libtool.m4 it'll
# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
# and doesn't know about Autoconf macros at all.)
#
# So we provide this file, which has a silly filename so it's always
# included after everything else. This provides aclocal with the
# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
# because those macros already exist, or will be overwritten later.
# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
#
# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
# Yes, that means every name once taken will need to remain here until
# we give up compatibility with versions before 1.7, at which point
# we need to keep only those names which we still refer to.
# This is to help aclocal find these macros, as it can't see m4_define.
AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])

11
packaging/libxo.pc.in Normal file
View File

@ -0,0 +1,11 @@
prefix=@prefix@
exec_prefix=@exec_prefix@
libdir=@libdir@
includedir=@includedir@
Name: libxo
Version: @VERSION@
Description: The XML Output Library
Libs: @LIBXO_LIBDIR@ @LIBXO_LIBS@
Cflags: @LIBXO_INCLUDEDIR@

View File

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

44
packaging/libxo.spec.in Normal file
View File

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

32
tests/Makefile.am Normal file
View File

@ -0,0 +1,32 @@
#
# Copyright 2014, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
SUBDIRS = core xo
if HAVE_GETTEXT
SUBDIRS += gettext
endif
test tests:
@(cur=`pwd` ; for dir in $(SUBDIRS) ; do \
cd $$dir ; \
$(MAKE) tests ; \
cd $$cur ; \
done)
accept:
@(cur=`pwd` ; for dir in $(SUBDIRS) ; do \
cd $$dir ; \
$(MAKE) accept ; \
cd $$cur ; \
done)
valgrind:
@echo '## Running the regression tests under Valgrind'
@echo '## Go get a cup of coffee it is gonna take a while ...'
${MAKE} VALGRIND='valgrind -q' tests

129
tests/core/Makefile.am Normal file
View File

@ -0,0 +1,129 @@
#
# $Id$
#
# Copyright 2014, Juniper Networks, Inc.
# All rights reserved.
# This SOFTWARE is licensed under the LICENSE provided in the
# ../Copyright file. By downloading, installing, copying, or otherwise
# using the SOFTWARE, you agree to be bound by the terms of that
# LICENSE.
AM_CFLAGS = -I${top_srcdir} -I${top_srcdir}/libxo
# Ick: maintained by hand!
TEST_CASES = \
test_01.c \
test_02.c \
test_03.c \
test_04.c \
test_05.c \
test_06.c \
test_07.c \
test_08.c \
test_09.c \
test_10.c \
test_11.c
test_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_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}}
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 ${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_ONE = \
LIBXO_OPTIONS=:W$$fmt ${TEST_JIG}
TEST_TWO = \
LIBXO_OPTIONS=warn,encoder=test ${TEST_JIG}
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 ..."; \
${TEST_ONE}; \
true; \
done) ; \
(for fmt in E; do \
echo "... $$test ... $$fmt ..."; \
${TEST_TWO}; \
true; \
done) \
done)
one:
-@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true)
accept:
-@(for test in ${TEST_CASES} ; do \
base=`${BASENAME} $$test .c` ; \
(for fmt in ${TEST_FORMATS} E; do \
echo "... $$test ... $$fmt ..."; \
${CP} out/$$base.$$fmt.out ${srcdir}/saved/$$base.$$fmt.out ; \
${CP} out/$$base.$$fmt.err ${srcdir}/saved/$$base.$$fmt.err ; \
done) \
done)
.c.test:
$(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -o $@ $<
CLEANFILES = ${TEST_CASES:.c=.test}
CLEANDIRS = out
clean-local:
rm -rf ${CLEANDIRS}

View File

View File

@ -0,0 +1,119 @@
op create: [] []
op open_container: [top] []
op string: [host] [my-box]
op string: [domain] [example.com]
op attr: [test] [value]
op open_container: [data] []
op open_list: [item] []
op attr: [test2] [value2]
op open_instance: [item] []
op attr: [test3] [value3]
op string: [sku] [GRO-000-415]
op string: [name] [gum]
op content: [sold] [1412]
op content: [in-stock] [54]
op content: [on-order] [10]
op close_instance: [item] []
op open_instance: [item] []
op attr: [test3] [value3]
op string: [sku] [HRD-000-212]
op string: [name] [rope]
op content: [sold] [85]
op content: [in-stock] [4]
op content: [on-order] [2]
op close_instance: [item] []
op open_instance: [item] []
op attr: [test3] [value3]
op string: [sku] [HRD-000-517]
op string: [name] [ladder]
op content: [sold] [0]
op content: [in-stock] [2]
op content: [on-order] [1]
op close_instance: [item] []
op open_instance: [item] []
op attr: [test3] [value3]
op string: [sku] [HRD-000-632]
op string: [name] [bolt]
op content: [sold] [4123]
op content: [in-stock] [144]
op content: [on-order] [42]
op close_instance: [item] []
op open_instance: [item] []
op attr: [test3] [value3]
op string: [sku] [GRO-000-2331]
op string: [name] [water]
op content: [sold] [17]
op content: [in-stock] [14]
op content: [on-order] [2]
op close_instance: [item] []
op close_list: [item] []
op close_container: [data] []
op open_container: [data2] []
op open_list: [item] []
op open_instance: [item] []
op string: [sku] [GRO-000-415]
op string: [name] [gum]
op content: [sold] [1412.0]
op content: [in-stock] [54]
op content: [on-order] [10]
op close_instance: [item] []
op open_instance: [item] []
op string: [sku] [HRD-000-212]
op string: [name] [rope]
op content: [sold] [85.0]
op content: [in-stock] [4]
op content: [on-order] [2]
op close_instance: [item] []
op open_instance: [item] []
op string: [sku] [HRD-000-517]
op string: [name] [ladder]
op content: [sold] [0]
op content: [in-stock] [2]
op content: [on-order] [1]
op close_instance: [item] []
op open_instance: [item] []
op string: [sku] [HRD-000-632]
op string: [name] [bolt]
op content: [sold] [4123.0]
op content: [in-stock] [144]
op content: [on-order] [42]
op close_instance: [item] []
op open_instance: [item] []
op string: [sku] [GRO-000-2331]
op string: [name] [water]
op content: [sold] [17.0]
op content: [in-stock] [14]
op content: [on-order] [2]
op close_instance: [item] []
op close_list: [item] []
op close_container: [data2] []
op open_container: [data3] []
op open_list: [item] []
op open_instance: [item] []
op string: [sku] [GRO-000-533]
op string: [name] [fish]
op content: [sold] [1321.0]
op content: [in-stock] [45]
op content: [on-order] [1]
op close_instance: [item] []
op close_list: [item] []
op close_container: [data3] []
op open_container: [data4] []
op open_list: [item] []
op attr: [test4] [value4]
op string: [item] [gum]
op attr: [test4] [value4]
op string: [item] [rope]
op attr: [test4] [value4]
op string: [item] [ladder]
op attr: [test4] [value4]
op string: [item] [bolt]
op attr: [test4] [value4]
op string: [item] [water]
op close_list: [item] []
op close_container: [data4] []
op content: [cost] [425]
op content: [cost] [455]
op close_container: [top] []
op finish: [] []
op flush: [] []

View File

File diff suppressed because one or more lines are too long

View File

View File

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

View File

View File

@ -0,0 +1,303 @@
<div class="line">
<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>

View File

View File

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

View File

View File

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

View File

View File

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

View File

View File

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

View File

View File

@ -0,0 +1,96 @@
<top>
<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>
</top>

View File

View File

@ -0,0 +1,38 @@
Item Total Sold In Stock On Order SKU
gum 1412 54 10 GRO-000-415
rope 85 4 2 HRD-000-212
ladder 0 2 1 HRD-000-517
bolt 4123 144 42 HRD-000-632
water 17 14 2 GRO-000-2331
Item 'gum':
Total sold: 1412.0
In stock: 54
On order: 10
SKU: GRO-000-415
Item 'rope':
Total sold: 85.0
In stock: 4
On order: 2
SKU: HRD-000-212
Item 'ladder':
Total sold: 0
In stock: 2
On order: 1
SKU: HRD-000-517
Item 'bolt':
Total sold: 4123.0
In stock: 144
On order: 42
SKU: HRD-000-632
Item 'water':
Total sold: 17.0
In stock: 14
On order: 2
SKU: GRO-000-2331
Item 'fish':
Total sold: 1321.0
In stock: 45
On order: 1
SKU: GRO-000-533

View File

View File

@ -0,0 +1,68 @@
op create: [] []
op open_container: [top] []
op open_container: [data] []
op string: [what] [braces]
op string: [length] [abcdef]
op content: [fd] [-1]
op string: [error] [Bad file descriptor]
op string: [test] [good]
op content: [fd] [-1]
op string: [error] [Bad fi]
op string: [test] [good]
op content: [lines] [20]
op content: [words] [30]
op content: [characters] [40]
op open_leaf_list: [bytes] []
op content: [bytes] [0]
op content: [bytes] [1]
op content: [bytes] [2]
op content: [bytes] [3]
op content: [bytes] [4]
op close_leaf_list: [bytes] []
op content: [mbuf-current] [10]
op content: [mbuf-cache] [20]
op content: [mbuf-total] [30]
op content: [distance] [50]
op string: [location] [Boston]
op content: [memory] [64]
op content: [total] [640]
op content: [memory] [64]
op content: [total] [640]
op content: [ten] [10]
op content: [eleven] [11]
op content: [unknown] [1010]
op content: [unknown] [1010]
op content: [min] [15]
op content: [cur] [20]
op content: [max] [30]
op content: [min] [15]
op content: [cur] [20]
op content: [max] [125]
op content: [min] [15]
op content: [cur] [20]
op content: [max] [125]
op content: [min] [15]
op content: [cur] [20]
op content: [max] [125]
op content: [val1] [21]
op content: [val2] [58368]
op content: [val3] [100663296]
op content: [val4] [44470272]
op content: [val5] [1342172800]
op open_list: [flag] []
op string: [flag] [one]
op string: [flag] [two]
op string: [flag] [three]
op close_list: [flag] []
op content: [works] [null]
op content: [empty-tag] [true]
op string: [t1] [1000]
op string: [t2] [test5000]
op string: [t3] [ten-longx]
op string: [t4] [xtest]
op content: [count] [10]
op content: [test] [4]
op close_container: [data] []
op close_container: [top] []
op finish: [] []
op flush: [] []

View File

File diff suppressed because one or more lines are too long

View File

View File

@ -0,0 +1,225 @@
<div class="line">
<div class="text">We are </div>
<div class="text">{emit}</div>
<div class="text">{ting}</div>
<div class="text"> some </div>
<div class="data" data-tag="what" data-xpath="/top/data/what">braces</div>
</div>
<div class="line">
<div class="message">abcdef
</div>
</div>
<div class="line">
<div class="message">abcdef: Bad file descriptor
</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="text">length </div>
<div class="data" data-tag="length" data-xpath="/top/data/length">abcdef</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd" data-xpath="/top/data/fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error" data-xpath="/top/data/error">Bad file descriptor</div>
<div class="text"> </div>
<div class="data" data-tag="test" data-xpath="/top/data/test">good</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd" data-xpath="/top/data/fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error" data-xpath="/top/data/error">Bad fi</div>
<div class="text"> </div>
<div class="data" data-tag="test" data-xpath="/top/data/test">good</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines" data-xpath="/top/data/lines"> 20</div>
<div class="text"> </div>
<div class="data" data-tag="words" data-xpath="/top/data/words"> 30</div>
<div class="text"> </div>
<div class="data" data-tag="characters" data-xpath="/top/data/characters"> 40</div>
<div class="text"> </div>
<div class="data" data-tag="filename" data-xpath="/top/data/filename">file</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">0</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">1</div>
<div class="padding"> </div>
<div class="note">byte</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">2</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">3</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes" data-xpath="/top/data/bytes">4</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="mbuf-current" data-xpath="/top/data/mbuf-current">10</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-cache" data-xpath="/top/data/mbuf-cache">20</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-total" data-xpath="/top/data/mbuf-total">30</div>
<div class="text"> </div>
<div class="note">mbufs &lt;&amp;&gt; in use (current/cache/total)</div>
</div>
<div class="line">
<div class="data" data-tag="distance" data-units="miles" data-xpath="/top/data/distance">50</div>
<div class="padding"> </div>
<div class="text"> from </div>
<div class="data" data-tag="location" data-xpath="/top/data/location">Boston</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data/memory">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kb" data-xpath="/top/data/total">640</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k" data-xpath="/top/data/memory">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kilobytes" data-xpath="/top/data/total">640</div>
</div>
<div class="line">
<div class="title">beforeworkingafter:</div>
</div>
<div class="line">
<div class="data" data-tag="some" data-xpath="/top/data/some">string</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="ten" data-xpath="/top/data/ten">10</div>
<div class="data" data-tag="eleven" data-xpath="/top/data/eleven">11</div>
</div>
<div class="line">
<div class="data" data-tag="unknown" data-xpath="/top/data/unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="data" data-tag="unknown" data-xpath="/top/data/unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min" data-xpath="/top/data/min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur" data-xpath="/top/data/cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max" data-xpath="/top/data/max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">Humanize: </div>
<div class="data" data-tag="val1" data-xpath="/top/data/val1" data-number="21">21</div>
<div class="text">, </div>
<div class="data" data-tag="val2" data-xpath="/top/data/val2" data-number="58368">57 K</div>
<div class="text">, </div>
<div class="data" data-tag="val3" data-xpath="/top/data/val3" data-number="100663296">96M</div>
<div class="text">, </div>
<div class="data" data-tag="val4" data-xpath="/top/data/val4" data-number="44470272">44M</div>
<div class="text">, </div>
<div class="data" data-tag="val5" data-xpath="/top/data/val5" data-number="1342172800">1.2G</div>
</div>
<div class="line">
<div class="data" data-tag="flag" data-xpath="/top/data/flag">one</div>
<div class="text"> </div>
<div class="data" data-tag="flag" data-xpath="/top/data/flag">two</div>
<div class="text"> </div>
<div class="data" data-tag="flag" data-xpath="/top/data/flag">three</div>
</div>
<div class="line">
<div class="data" data-tag="works" data-xpath="/top/data/works">(null)</div>
</div>
<div class="line">
<div class="text">1:</div>
<div class="data" data-tag="t1" data-xpath="/top/data/t1"> 1000</div>
<div class="text"> 2:</div>
<div class="data" data-tag="t2" data-xpath="/top/data/t2">test5000 </div>
<div class="text"> 3:</div>
<div class="data" data-tag="t3" data-xpath="/top/data/t3"> ten-longx</div>
<div class="text"> 4:</div>
<div class="data" data-tag="t4" data-xpath="/top/data/t4">xtest </div>
</div>
<div class="line">
<div class="error">this is an error</div>
</div>
<div class="line">
<div class="error">two more errors</div>
</div>
<div class="line">
<div class="warning">this is an warning</div>
</div>
<div class="line">
<div class="warning">two more warnings</div>
</div>
<div class="line">
<div class="label">V1/V2 packets</div>
<div class="text">: </div>
<div class="data" data-tag="count" data-xpath="/top/data/count">10</div>
</div>
<div class="line">
<div class="data" data-tag="test" data-xpath="/top/data/test">0004</div>
<div class="text"> </div>
<div class="label">tries</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="error">Shut 'er down, Clancey! She's a-pumpin' mud! &lt;&gt;!,"!&lt;&gt;
</div>
</div>

View File

View File

@ -0,0 +1,225 @@
<div class="line">
<div class="text">We are </div>
<div class="text">{emit}</div>
<div class="text">{ting}</div>
<div class="text"> some </div>
<div class="data" data-tag="what">braces</div>
</div>
<div class="line">
<div class="message">abcdef
</div>
</div>
<div class="line">
<div class="message">abcdef: Bad file descriptor
</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="text">length </div>
<div class="data" data-tag="length">abcdef</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error">Bad file descriptor</div>
<div class="text"> </div>
<div class="data" data-tag="test">good</div>
</div>
<div class="line">
<div class="text">close </div>
<div class="data" data-tag="fd">-1</div>
<div class="text"> returned </div>
<div class="data" data-tag="error">Bad fi</div>
<div class="text"> </div>
<div class="data" data-tag="test">good</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="text"> </div>
<div class="data" data-tag="lines"> 20</div>
<div class="text"> </div>
<div class="data" data-tag="words"> 30</div>
<div class="text"> </div>
<div class="data" data-tag="characters"> 40</div>
<div class="text"> </div>
<div class="data" data-tag="filename">file</div>
</div>
<div class="line">
<div class="data" data-tag="bytes">0</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes">1</div>
<div class="padding"> </div>
<div class="note">byte</div>
</div>
<div class="line">
<div class="data" data-tag="bytes">2</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes">3</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="bytes">4</div>
<div class="padding"> </div>
<div class="note">bytes</div>
</div>
<div class="line">
<div class="data" data-tag="mbuf-current">10</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-cache">20</div>
<div class="text">/</div>
<div class="data" data-tag="mbuf-total">30</div>
<div class="text"> </div>
<div class="note">mbufs &lt;&amp;&gt; in use (current/cache/total)</div>
</div>
<div class="line">
<div class="data" data-tag="distance" data-units="miles">50</div>
<div class="padding"> </div>
<div class="text"> from </div>
<div class="data" data-tag="location">Boston</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kb">640</div>
</div>
<div class="line">
<div class="data" data-tag="memory" data-units="k">64</div>
<div class="text"> left out of </div>
<div class="data" data-tag="total" data-units="kilobytes">640</div>
</div>
<div class="line">
<div class="title">beforeworkingafter:</div>
</div>
<div class="line">
<div class="data" data-tag="some">string</div>
<div class="decoration">:</div>
<div class="padding"> </div>
<div class="data" data-tag="ten">10</div>
<div class="data" data-tag="eleven">11</div>
</div>
<div class="line">
<div class="data" data-tag="unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="data" data-tag="unknown">1010</div>
<div class="text"> </div>
<div class="note">packets here/there/everywhere</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="padding"> </div>
<div class="data" data-tag="min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max">125</div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">(</div>
<div class="data" data-tag="min">15</div>
<div class="text">/</div>
<div class="data" data-tag="cur">20</div>
<div class="text">/</div>
<div class="data" data-tag="max">125</div>
<div class="padding"> </div>
<div class="text">)</div>
</div>
<div class="line">
<div class="text">Humanize: </div>
<div class="data" data-tag="val1" data-number="21">21</div>
<div class="text">, </div>
<div class="data" data-tag="val2" data-number="58368">57 K</div>
<div class="text">, </div>
<div class="data" data-tag="val3" data-number="100663296">96M</div>
<div class="text">, </div>
<div class="data" data-tag="val4" data-number="44470272">44M</div>
<div class="text">, </div>
<div class="data" data-tag="val5" data-number="1342172800">1.2G</div>
</div>
<div class="line">
<div class="data" data-tag="flag">one</div>
<div class="text"> </div>
<div class="data" data-tag="flag">two</div>
<div class="text"> </div>
<div class="data" data-tag="flag">three</div>
</div>
<div class="line">
<div class="data" data-tag="works">(null)</div>
</div>
<div class="line">
<div class="text">1:</div>
<div class="data" data-tag="t1"> 1000</div>
<div class="text"> 2:</div>
<div class="data" data-tag="t2">test5000 </div>
<div class="text"> 3:</div>
<div class="data" data-tag="t3"> ten-longx</div>
<div class="text"> 4:</div>
<div class="data" data-tag="t4">xtest </div>
</div>
<div class="line">
<div class="error">this is an error</div>
</div>
<div class="line">
<div class="error">two more errors</div>
</div>
<div class="line">
<div class="warning">this is an warning</div>
</div>
<div class="line">
<div class="warning">two more warnings</div>
</div>
<div class="line">
<div class="label">V1/V2 packets</div>
<div class="text">: </div>
<div class="data" data-tag="count">10</div>
</div>
<div class="line">
<div class="data" data-tag="test">0004</div>
<div class="text"> </div>
<div class="label">tries</div>
</div>
<div class="line">
<div class="message">improper use of profanity; ten yard penalty; first down
</div>
</div>
<div class="line">
<div class="error">Shut 'er down, Clancey! She's a-pumpin' mud! &lt;&gt;!,"!&lt;&gt;
</div>
</div>

View File

View File

@ -0,0 +1,2 @@
{"top": {"data": {"what":"braces","length":"abcdef","fd":-1,"error":"Bad file descriptor","test":"good","fd":-1,"error":"Bad fi","test":"good","lines":20,"words":30,"characters":40, "bytes": [0,1,2,3,4],"mbuf-current":10,"mbuf-cache":20,"mbuf-total":30,"distance":50,"location":"Boston","memory":64,"total":640,"memory":64,"total":640,"ten":10,"eleven":11,"unknown":1010,"unknown":1010,"min":15,"cur":20,"max":30,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"min":15,"cur":20,"max":125,"val1":21,"val2":58368,"val3":100663296,"val4":44470272,"val5":1342172800, "flag": ["one","two","three"],"works":null,"empty-tag":true,"t1":"1000","t2":"test5000","t3":"ten-longx","t4":"xtest", "__error": {"message":"this is an error"}, "__error": {"message":"two more errors"}, "__warning": {"message":this is an warning}, "__warning": {"message":"two more warnings"},"count":10,"test":4, "error": {"message":"Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"}}}
}

View File

View File

@ -0,0 +1,82 @@
{
"top": {
"data": {
"what": "braces",
"length": "abcdef",
"fd": -1,
"error": "Bad file descriptor",
"test": "good",
"fd": -1,
"error": "Bad fi",
"test": "good",
"lines": 20,
"words": 30,
"characters": 40,
"bytes": [
0,
1,
2,
3,
4
],
"mbuf-current": 10,
"mbuf-cache": 20,
"mbuf-total": 30,
"distance": 50,
"location": "Boston",
"memory": 64,
"total": 640,
"memory": 64,
"total": 640,
"ten": 10,
"eleven": 11,
"unknown": 1010,
"unknown": 1010,
"min": 15,
"cur": 20,
"max": 30,
"min": 15,
"cur": 20,
"max": 125,
"min": 15,
"cur": 20,
"max": 125,
"min": 15,
"cur": 20,
"max": 125,
"val1": 21,
"val2": 58368,
"val3": 100663296,
"val4": 44470272,
"val5": 1342172800,
"flag": [
"one",
"two",
"three"
],
"works": null,
"empty-tag": true,
"t1": "1000",
"t2": "test5000",
"t3": "ten-longx",
"t4": "xtest",
"__error": {
"message": "this is an error"
},
"__error": {
"message": "two more errors"
},
"__warning": {
"message": this is an warning
},
"__warning": {
"message": "two more warnings"
},
"count": 10,
"test": 4,
"error": {
"message": "Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"
}
}
}
}

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