diff --git a/contrib/libxo/.gitignore b/contrib/libxo/.gitignore new file mode 100644 index 000000000000..386bfc883cb5 --- /dev/null +++ b/contrib/libxo/.gitignore @@ -0,0 +1,43 @@ +# Object files +*.o + +# Libraries +*.lib +*.a + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.app + +*~ +*.orig + +aclocal.m4 +ar-lib +autom4te.cache +build +compile +config.guess +config.h.in +config.sub +depcomp +ltmain.sh +missing + +Makefile.in +configure +.DS_Store + +xoconfig.h.in + +.gdbinit +.gdbinit.local +xtest +xtest.dSYM +tests/w diff --git a/contrib/libxo/.travis.yml b/contrib/libxo/.travis.yml new file mode 100644 index 000000000000..e26a7699ca23 --- /dev/null +++ b/contrib/libxo/.travis.yml @@ -0,0 +1,12 @@ +language: c + +script: printenv && uname -a && /bin/sh ./bin/setup.sh && cd build && ../configure --enable-warnings && make && sudo make install && make test + +notifications: + recipients: + - libslax-noise@googlegroups.com + +branches: + only: + - master + - develop diff --git a/contrib/libxo/Copyright b/contrib/libxo/Copyright new file mode 100644 index 000000000000..94ba75e4ffa2 --- /dev/null +++ b/contrib/libxo/Copyright @@ -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. diff --git a/contrib/libxo/LICENSE b/contrib/libxo/LICENSE new file mode 100644 index 000000000000..874da7b2d8a8 --- /dev/null +++ b/contrib/libxo/LICENSE @@ -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. diff --git a/contrib/libxo/Makefile.am b/contrib/libxo/Makefile.am new file mode 100644 index 000000000000..f1fc9997b8ac --- /dev/null +++ b/contrib/libxo/Makefile.am @@ -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 xolint tests doc +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/ +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 ..." \ + && cp doc/libxo-manual.html ${GH_PAGES_DIR} \ + && (cd ${GH_PAGES_DIR} \ + && git commit -m 'new docs' \ + libxo-manual.html \ + && 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 = packaging/${PACKAGE_VERSION} +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}'`" \ + && mkdir -p ${GH_PAGES_PACKAGE_DIR}/freebsd \ + && 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 \ + && echo "... ${GH_PAGES_PACKAGE_DIR}/freebsd ..." \ + && sed ${UPDATE_PACKAGE_FILE} \ + ${srcdir}/packaging/freebsd/distinfo.base \ + > ${GH_PAGES_PACKAGE_DIR}/freebsd/distinfo \ + && cp ${srcdir}/packaging/freebsd/pkg-descr \ + ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-descr \ + && cp ${srcdir}/packaging/freebsd/pkg-plist \ + ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-plist \ + && cp ${srcdir}/packaging/freebsd/pkg-plist \ + ${GH_PAGES_PACKAGE_DIR}/freebsd/pkg-plist \ + && cp packaging/freebsd/port-Makefile \ + ${GH_PAGES_PACKAGE_DIR}/freebsd/Makefile \ + && (cd ${GH_PAGES_DIR} \ + && git add ${GH_PACKAGING_DIR} \ + && git commit -m 'new packaging data' \ + ${GH_PACKAGING_DIR} \ + && git push origin gh-pages ) ; true diff --git a/contrib/libxo/README.md b/contrib/libxo/README.md new file mode 100644 index 000000000000..40c162b0875a --- /dev/null +++ b/contrib/libxo/README.md @@ -0,0 +1,62 @@ +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 + + + /etc/motd + 25 + 165 + 1140 + + + % 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 +
+
+
25
+
+
165
+
+
1140
+
+
/etc/motd
+
+``` + +View the beautiful documentation at: + +http://juniper.github.io/libxo/libxo-manual.html diff --git a/contrib/libxo/bin/Makefile.am b/contrib/libxo/bin/Makefile.am new file mode 100644 index 000000000000..3bda1be4fd29 --- /dev/null +++ b/contrib/libxo/bin/Makefile.am @@ -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 diff --git a/contrib/libxo/bin/Zaliases b/contrib/libxo/bin/Zaliases new file mode 100644 index 000000000000..a24d33e7a522 --- /dev/null +++ b/contrib/libxo/bin/Zaliases @@ -0,0 +1,24 @@ +set top_src=`pwd` +alias Zautoreconf "(cd $top_src ; autoreconf --install)" + +set opts=' \ +--with-libslax-prefix=/Users/phil/work/root \ +--enable-debug \ +--enable-warnings \ +--enable-printflike \ +--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' diff --git a/contrib/libxo/bin/setup.sh b/contrib/libxo/bin/setup.sh new file mode 100755 index 000000000000..5e03ff35e142 --- /dev/null +++ b/contrib/libxo/bin/setup.sh @@ -0,0 +1,31 @@ +# +# 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 + + 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 diff --git a/contrib/libxo/build/.create b/contrib/libxo/build/.create new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/contrib/libxo/configure.ac b/contrib/libxo/configure.ac new file mode 100644 index 000000000000..2412d12cf0a9 --- /dev/null +++ b/contrib/libxo/configure.ac @@ -0,0 +1,263 @@ +# +# $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.1.4], [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([sysctlbyname]) +AC_CHECK_FUNCS([flock]) +AC_CHECK_FUNCS([asprintf]) + +AC_CHECK_HEADERS([dlfcn.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_LIB([crypto], [MD5_Init]) +AM_CONDITIONAL([HAVE_LIBCRYPTO], [test "$HAVE_LIBCRYPTO" != "no"]) + +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) +else + LIBSLAX_VERSION= + SLAX_BINDIR= + SLAX_OXTRADOCDIR= + AC_MSG_RESULT([no]) +fi + +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_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 + ;; + Linux*|linux*) + CFLAGS="-D_GNU_SOURCE $CFLAGS" + LDFLAGS=-ldl + ;; + cygwin*|CYGWIN*) + LDFLAGS=-no-undefined + ;; +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_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_CONFIG_HEADERS([libxo/xoconfig.h]) +AC_CONFIG_FILES([ + Makefile + libxo-config + xohtml/xohtml.sh + libxo/Makefile + libxo/xoversion.h + xo/Makefile + xolint/Makefile + packaging/libxo.pc + doc/Makefile + tests/Makefile + tests/core/Makefile + tests/xo/Makefile + packaging/libxo.spec +]) +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} + + 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} +]) diff --git a/contrib/libxo/doc/Makefile.am b/contrib/libxo/doc/Makefile.am new file mode 100644 index 000000000000..c0c327197a0b --- /dev/null +++ b/contrib/libxo/doc/Makefile.am @@ -0,0 +1,65 @@ +# +# $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. + +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.txt + +EXTRA_DIST = \ + ${INPUT} \ + ${OUTPUT}.html \ + ${OUTPUT}.txt + +doc docs: ${OUTPUT}.txt ${OUTPUT}.html + +${OUTPUT}.txt: ${INPUT} ${OXTRADOC} xolint.txt + ${OXTRADOC_CMD} -m text -o $@ $< + +${OUTPUT}.html: ${INPUT} ${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 = \ +${OUTPUT}.xml \ +${OUTPUT}.txt \ +${OUTPUT}.fxml \ +${OUTPUT}.html diff --git a/contrib/libxo/doc/libxo.txt b/contrib/libxo/doc/libxo.txt new file mode 100644 index 000000000000..5148de0f74a9 --- /dev/null +++ b/contrib/libxo/doc/libxo.txt @@ -0,0 +1,2400 @@ +# +# 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 +# + +* libxo + +libxo - A Library for Generating Text, XML, JSON, and HTML Output + +You live in the present, but you want to live in the future. You'd +love a flying car, but need to get to work today. You want to support +features like XML, JSON, and HTML rendering to allow integration with +NETCONF, REST, and web browsers, but you need to make text output for +command line users. And you don't want multiple code paths that can't +help but get out of sync. None of this "if (xml) {... } else {...}" +logic. And ifdefs are right out. But you'd really, really like all +the fancy features that modern encoding formats can provide. + +The libxo library allows an application to generate text, XML, JSON, +and HTML output using a common set of function calls. The application +decides at run time which output style should be produced. The +application calls a function "xo_emit" to product output that is +described in a format string. A "field descriptor" tells libxo what +the field is and what it means. Each field descriptor is placed in +braces with a printf-like format string: + + xo_emit(" {:lines/%7ju} {:words/%7ju} " + "{:characters/%7ju}{d:filename/%s}\n", + linect, wordct, charct, file); + +Each field can have a role, with the 'value' role being the default, +and the role tells libxo how and when to render that field. 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 + + + /etc/motd + 25 + 165 + 1140 + + + % 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 +
+
+
25
+
+
165
+
+
1140
+
+
/etc/motd
+
+ +** Getting libxo + +libxo lives on github as: + + https://github.com/Juniper/libxo + +The latest release of libxo is available at: + + https://github.com/Juniper/libxo/releases + +We are following the branching scheme from +^http://nvie.com/posts/a-successful-git-branching-model/^ +which means we will do development under the "develop" branch, and +release from the master. To clone a developer tree, run the following +command: + + git clone https://github.com/Juniper/libxo.git -b develop + +We're using semantic release numbering. + +* Overview + +Most unix commands emit text output aimed at humans. It is designed +to be parsed and understood by a user. Humans are gifted at extracted +details and pattern matching. Often programmers need to extract +information from this human-oriented output. Programmers use tools +like grep, awk, and regular expressions to ferret out the pieces of +information they need. Such solutions are fragile and require +updates when output contents change or evolve, requiring testing and +validation. + +Modern tool developers favors 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. + +In addition, modern reality means that more output ends up in web +browsers than in terminals, making HTML output valuable. + +libxo allows a single set of function calls in source code to generate +traditional text output, as well as XML and JSON formatted data. HTML +can also be generated; "
" elements surround the traditional text +output, with attributes that detail how to render the data. + +A single libxo function call in source code is all that's required: + + xo_emit("Connecting to {:host}.{:domain}...\n", host, domain); + + Text: + Connection to my-box.example.com... + XML: + my-box + example.com + JSON: + "host": my-box", + "domain": "example.com" + +For brevity, the HTML output is emitted. + +** Encoding Styles + +There are four encoding styles supported by libxo: TEXT, HTML, JSON, +and XML. JSON and XML are suitable for encoding data, while TEXT and +HTML are suited for display to the user. TEXT output can be display +on a terminal session, allowing compatibility with traditional usage. +HTML can be matched with a small CSS file to permit rendering in any +HTML5 browser. XML output is suitable for tools like XPath and +protocols like NETCONF. JSON output can be used for RESTful APIs. + +*** Text Output + +Most traditional programs generate text output on standard output, +with contents like: + + 36 ./src + 40 ./bin + 90 . + +In this example (taken from du source code), the code to generate this +data might look like: + + printf("%d\t%s\n", num_blocks, path); + +Simple, direct, obvious. But it's only making text output. Imagine +using a single code path to make text, XML, JSON or HTML, deciding at +run time which to generate. + +libxo expands on the idea of printf format strings to make a single +format containing instructions for creating multiple output styles: + + xo_emit("{:blocks/%d}\t{:path/%s}\n", num_blocks, path); + +This line will generate the same text output as the earlier printf +call, but also has enough information to generate XML, JSON, and HTML. + +The following sections introduce the other formats. + +*** XML Output + +XML output consists of a hierarchical set of elements, each encoded +with a start tag and an end tag. The element should be named for data +value that it is encoding: + + + 36 + ./src + + + 40 + ./bin + + + 90 + . + + +XML is a W3C standard for encoding data. See w3c.org/TR/xml for +additional information. + +*** JSON Output + +JSON output consists of a hierarchical set of objects and lists, each +encoded with a quoted name, a colon, and a value. If the value is a +string, it must be quoted, but numbers are not quoted. Objects are +encoded using braces; lists are encoded using square brackets. +Data inside objects and lists is separated using commas: + + items: [ + { "blocks": 36, "path" : "./src" }, + { "blocks": 40, "path" : "./bin" }, + { "blocks": 90, "path" : "./" } + ] + +*** HTML Output + +HTML output is designed to allow the output to be rendered in a web +browser with minimal effort. Each piece of output data is rendered +inside a
element, with a class name related to the role of the +data. By using a small set of class attribute values, a CSS +stylesheet can render the HTML into rich text that mirrors the +traditional text content. + +Additional attributes can be enabled to provide more details about the +data, including data type, description, and an XPath location. + +
+
36
+
+
./src
+
+
+
40
+
+
./bin
+
+
+
90
+
+
./
+
+ +** Format Strings @format-strings@ + +libxo uses format strings to control the rendering of data into the +various output styles. Each format string contains a set of zero or +more field descriptions, which describe independent data fields. Each +field description contains a set of modifiers, a content string, and +zero, one, or two format descriptors. The modifiers tell libxo what +the field is and how to treat it, while the format descriptors are +formatting instructions using printf-style format strings, telling +libxo how to format the field. The field description is placed inside +a set of braces, with a colon (":") after the modifiers and a slash +("/") before each format descriptors. Text may be intermixed with +field descriptions within the format string. + +The field description is given as follows: + + '{' [ role | modifier ]* ':' [ content ] + [ '/' field-format [ '/' encoding-format ]] '}' + +The role describes the function of the field, while the modifiers +enable optional behaviors. The contents, field-format, and +encoding-format are used in varying ways, based on the role. These +are described in the following sections. + +In the following example, three field descriptors appear. The first +is a padding field containing three spaces of padding, the second is a +label ("In stock"), and the third is a value field ("in-stock"). The +in-stock field has a "%u" format that will parse the next argument +passed to the xo_emit function as an unsigned integer. + + xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", 65); + +This single line of code can generate text (" In stock: 65\n"), XML +("65"), JSON ('"in-stock": 6'), or HTML (too +lengthy to be listed here). + +*** Modifier Roles + +Modifiers are optional, and indicate the role and formatting of the +content. The roles are listed below; only one role is permitted: + +|---+--------------+-------------------------------------------------| +| M | Name | Description | +|---+--------------+-------------------------------------------------| +| D | decoration | Field is non-text (e.g. colon, comma) | +| E | error | Field is an error message | +| L | label | Field is text that prefixes a value | +| N | note | Field is text that follows a value | +| P | padding | Field is spaces needed for vertical alignment | +| T | title | Field is a title value for headings | +| U | units | Field is the units for the previous value field | +| V | value | Field is the name of field (the default) | +| W | warning | Field is a warning message | +| [ | start anchor | Begin a section of anchored variable-width text | +| ] | stop anchor | End a section of anchored variable-width text | +|---+--------------+-------------------------------------------------| + +**** The Decoration Role ({D:}) + +Decorations are typically punctuation marks such as colons, +semi-colons, and commas used to decorate the text and make it simpler +for human readers. By marking these distinctly, HTML usage scenarios +can use CSS to direct their display parameters. + + xo_emit("{D:((}{:name}{D:))}\n", name); + +**** The Label Role ({L:}) + +Labels are text that appears before a value. + + xo_emit("{Lwc:Cost}{:cost/%u}\n", cost); + +**** The Note Role ({N:}) + +Notes are text that appears after a value. + + xo_emit("{:cost/%u} {N:per year}\n", cost); + +**** The Padding Role ({P:}) + +Padding represents whitespace used before and between fields. + +The padding content can be either static, when placed directly within +the field descriptor, or a printf-style format descriptor can be used, +if preceded by a slash ("/"): + + xo_emit("{P: }{Lwc:Cost}{:cost/%u}\n", cost); + xo_emit("{P:/30s}{Lwc:Cost}{:cost/%u}\n", "", cost); + +**** The Title Role ({T:}) + +Title are heading or column headers that are meant to be displayed to +the user. The title can be either static, when placed directly within +the field descriptor, or a printf-style format descriptor can be used, +if preceded by a slash ("/"): + + xo_emit("{T:Interface Statistics}\n"); + xo_emit("{T:/%20.20s}{T:/%6.6s}\n", "Item Name", "Cost"); + +**** The Units Role ({U:}) + +Units are the dimension by which values are measured, such as degrees, +miles, bytes, and decibels. The units field carries this information +for the previous value field. + + xo_emit("{Lwc:Distance}{:distance/%u}{Uw:miles}\n", miles); + +Note that the sense of the 'w' modifier is reversed for units; +a blank is added before the contents, rather than after it. + +When the XOF_UNITS flag is set, units are rendered in XML as the +"units" attribute: + + 50 + +Units can also be rendered in HTML as the "data-units" attribute: + +
50
+ +**** The Value Role ({V:} and {:}) + +The value role is used to represent the a data value that is +interesting for the non-display output styles (XML and JSON). Value +is the default role; if no other role designation is given, the field +is a value. The field name must appear within the field descriptor, +followed by one or two format descriptors. The first format +descriptor is used for display styles (TEXT and HTML), while the +second one is used for encoding styles (XML and JSON). If no second +format is given, the encoding format defaults to the first format, +with any minimum width removed. If no first format is given, both +format descriptors default to "%s". + + xo_emit("{:length/%02u}x{:width/%02u}x{:height/%02u}\n", + length, width, height); + xo_emit("{:author} wrote \"{:poem}\" in {:year/%4d}\n, + author, poem, year); + +**** The Anchor Modifiers ({[:} and {]:}) + +The anchor roles allow a set of strings by be padded as a group, +but still be visible to xo_emit as distinct fields. Either the start +or stop anchor can give a field width and it can be either directly in +the descriptor or passed as an argument. Any fields between the start +and stop anchor are padded to meet the minimum width given. + +To give a width directly, encode it as the content of the anchor tag: + + xo_emit("({[:10}{:min/%d}/{:max/%d}{]:})\n", min, max); + +To pass a width as an argument, use "%d" as the format, which must +appear after the "/". Note that only "%d" is supported for widths. +Using any other value could ruin your day. + + xo_emit("({[:/%d}{:min/%d}/{:max/%d}{]:})\n", width, min, max); + +If the width is negative, padding will be added on the right, suitable +for left justification. Otherwise the padding will be added to the +left of the fields between the start and stop anchors, suitable for +right justification. If the width is zero, nothing happens. If the +number of columns of output between the start and stop anchors is less +than the absolute value of the given width, nothing happens. + +Widths over 8k are considered probable errors and not supported. If +XOF_WARN is set, a warning will be generated. + +*** Modifier Flags + +The modifiers can also include the following flags, which modify the +content emitted for some output styles: + +|---+--------------+-------------------------------------------------| +| M | Name | Description | +|---+--------------+-------------------------------------------------| +| c | colon | A colon (":") is appended after the label | +| d | display | Only emit field for display styles (text/HTML) | +| e | encoding | Only emit for encoding styles (XML/JSON) | +| k | key | Field is a key, suitable for XPath predicates | +| n | no-quotes | Do not quote the field when using JSON style | +| q | quotes | Quote the field when using JSON style | +| w | white space | A blank (" ") is appended after the label | +|---+--------------+-------------------------------------------------| + +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. + +**** The Colon Modifier ({c:}) + +The colon modifier appends a single colon to the data value: + + EXAMPLE: + xo_emit("{Lc:Name}{:name}\n", "phil"); + TEXT: + Name:phil + +The colon modifier is only used for the TEXT and HTML output +styles. It is commonly combined with the space modifier ('{w:'). +It is purely a convenience feature. + +**** The Display Modifier ({d:}) + +The display modifier indicated the field should only be generated for +the display output styles, TEXT and HTML. + + EXAMPLE: + xo_emit("{Lcw:Name}{d:name} {:id/%d}\n", "phil", 1); + TEXT: + Name: phil 1 + XML: + 1 + +The display modifier is the opposite of the encoding modifier, and +they are often used to give to distinct views of the underlying data. + +**** The Encoding Modifier ({e:}) @e-modifier@ + +The display modifier indicated the field should only be generated for +the display output styles, TEXT and HTML. + + EXAMPLE: + xo_emit("{Lcw:Name}{:name} {e:id/%d}\n", "phil", 1); + TEXT: + Name: phil + XML: + phil1 + +The encoding modifier is the opposite of the display modifier, and +they are often used to give to distinct views of the underlying data. + +**** The Key Modifier ({k:}) + +The key modifier is used to indicate that a particular field helps +uniquely identify an instance of list data. + + EXAMPLE: + xo_open_list("user"); + for (i = 0; i < num_users; i++) { + xo_open_instance("user"); + xo_emit("User {k:name} has {:count} tickets\n", + user[i].u_name, user[i].u_tickets); + xo_close_instance("user"); + } + xo_close_list("user"); + +Currently the key modifier is only used when generating XPath value +for the HTML output style when XOF_XPATH is set, but other uses are +likely in the near future. + +**** 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 value, but no quotes for numeric, boolean, and null data. +xo_emit applies a simple heuristic to determine whether quotes are +needed, but often this needs to be controlled by the caller. + + EXAMPLE: + const char *bool = is_true ? "true" : "false"; + xo_emit("{n:fancy/%s}", bool); + JSON: + "fancy": true + +**** 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 value, but no quotes for numeric, boolean, and null data. +xo_emit applies a simple heuristic to determine whether quotes are +needed, but often this needs to be controlled by the caller. + + EXAMPLE: + xo_emit("{q:time/%d}", 2014); + JSON: + "year": "2014" + +**** The White Space Modifier ({w:}) + +The white space modifier appends a single space to the data value: + + EXAMPLE: + xo_emit("{Lw:Name}{:name}\n", "phil"); + TEXT: + Name phil + +The white space modifier is only used for the TEXT and HTML output +styles. It is commonly combined with the colon modifier ('{c:'). +It is purely a convenience feature. + +Note that the sense of the 'w' modifier is reversed for the units role +({Uw:}); a blank is added before the contents, rather than after it. + +*** Field Formatting + +The field format is similar to the format string for printf(3). It's +used varies based on the role of the field, but generally is used to +format the field's contents. + +If not provided, the format string defaults to "%s". + +Note a field definition can contain zero or more printf-style +'directives', which are sequences that start with a '%' and end with a +one of following characters: "diouxXDOUeEfFgGaAcCsSp". Each directive +is matched by one of more arguments to the xo_emit function. + +The format string has the form: + + '%' format-modifier * format-character + +The format- modifier can be: +- a '#' character, indicating the output value should be prefixed with +'0x', typically to indicate a base 16 (hex) value. +- a minus sign ('-'), indicating the output value should be padded on +the right instead of the left. +- a leading zero ('0') indicating the output value should be padded on the +left with zeroes instead of spaces (' '). +- one or more digits ('0' - '9') indicating the minimum width of the +argument. If the width in columns of the output value is less that +the minumum width, the value will be padded to reach the minimum. +- a period followed by one or more digits indicating the maximum +number of bytes which will be examined for a string argument, or the maximum +width for a non-string argument. When handling ASCII strings this is +functions as the field width but for multi-byte characters, a single +character may be composed of multiple bytes. +xo_emit will never dereference memory beyond the given number of bytes. +- a second period followed by one or more digits indicating the maximum +width for a string argument. This modifier cannot be given for non-string +arguments. +- one or more 'h' characters, indicating shorter input data. +- one or more 'l' characters, indicating longer input data. +- a 'z' character, indicating a 'size_t' argument. +- a 't' character, indicating a 'ptrdiff_t' argument. +- a ' ' character, indicating a space should be emitted before +positive numbers. +- a '+' character, indicating sign should emitted before any number. + +Note that 'q', 'D', 'O', and 'U' are considered deprecated and will be +removed eventually. + +The format character is described in the following table: + +|-----+-----------------+----------------------| +| Ltr | Argument Type | Format | +|-----+-----------------+----------------------| +| d | int | base 10 (decimal) | +| i | int | base 10 (decimal) | +| o | int | base 8 (octal) | +| u | unsigned | base 10 (decimal) | +| x | unsigned | base 16 (hex) | +| X | unsigned long | base 16 (hex) | +| D | long | base 10 (decimal) | +| O | unsigned long | base 8 (octal) | +| U | unsigned long | base 10 (decimal) | +| e | double | [-]d.ddde+-dd | +| E | double | [-]d.dddE+-dd | +| f | double | [-]ddd.ddd | +| F | double | [-]ddd.ddd | +| g | double | as 'e' or 'f' | +| G | double | as 'E' or 'F' | +| a | double | [-]0xh.hhhp[+-]d | +| A | double | [-]0Xh.hhhp[+-]d | +| c | unsigned char | a character | +| C | wint_t | a character | +| s | char * | a UTF-8 string | +| S | wchar_t * | a unicode/WCS string | +| p | void * | '%#lx' | +|-----+-----------------+----------------------| + +The 'h' and 'l' modifiers affect the size and treatment of the +argument: + +|-----+-------------+--------------------| +| Mod | d, i | o, u, x, X | +|-----+-------------+--------------------| +| hh | signed char | unsigned char | +| h | short | unsigned short | +| l | long | unsigned long | +| ll | long long | unsigned long long | +| j | intmax_t | uintmax_t | +| t | ptrdiff_t | ptrdiff_t | +| z | size_t | size_t | +| q | quad_t | u_quad_t | +|-----+-------------+--------------------| + +*** UTF-8 and Locale Strings + +For strings, the 'h' and 'l' modifiers affect the interpretation of +the bytes pointed to argument. The default '%s' string is a 'char *' +pointer to a string encoded as UTF-8. Since UTF-8 is compatible with +ASCII data, a normal 7-bit ASCII string can be used. '%ls' expects a +'wchar_t *' pointer to a wide-character string, encoded as a 32-bit +Unicode values. '%hs' expects a 'char *' pointer to a multi-byte +string encoded with the current locale, as given by the LC_CTYPE, +LANG, or LC_ALL environment varibles. The first of this list of +variables is used and if none of the variables, the locale defaults to +"UTF-8". + +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. + + void print_order (const char *name, int size, + struct tm *timep) { + char buf[32]; + const char *size_val = "unknown"; + + if (size > 0) + snprintf(buf, sizeof(buf), "%d", size); + size_val = buf; + } + + wchar_t when[32]; + wcsftime(when, sizeof(when), L"%d%b%y", timep); + + xo_emit("The hat for {:name/%hs} is {:size/%s}.\n", + name, size_val); + xo_emit("It was ordered on {:order-time/%ls}.\n", + when); + } + +It is important to note that xo_emit will perform the conversion +required to make appropriate output. Text style output uses the +current locale (as described above), while XML, JSON, and HTML use +UTF-8. + +UTF-8 and locale-encoded strings can use multiple bytes to encode one +column of data. The traditional "precision'" (aka "max-width") value +for "%s" printf formatting becomes overloaded since it specifies both +the number of bytes that can be safely referenced and the maximum +number of columns to emit. xo_emit uses the precision as the former, +and adds a third value for specifying the maximum number of columns. + +In this example, the name field is printed with a minimum of 3 columns +and a maximum of 6. Up to ten bytes are in used in filling those +columns. + + xo_emit("{:name/%3.10.6s}", name); + +*** Characters Outside of Field Definitions + +Characters in the format string 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
with +class "text". + + EXAMPLE: + xo_emit("The hat is {:size/%s}.\n", size_val); + TEXT: + The hat is extra small. + XML: + extra small + JSON: + "size": "extra small" + HTML: +
The hat is
+
extra small
+
.
+ +*** "%n" is Not Supported + +libxo does not support the '%n' directive. It's a bad idea and we +just don't do it. + +*** The Encoding Format (eformat) + +The "eformat" string is the format string used when encoding the field +for JSON and XML. If not provided, it defaults to the primary format +with any minimum width removed. If the primary is not given, both +default to "%s". + +*** Content Strings + +For padding and labels, the content string is considered the content, +unless a format is given. + +*** Example + +In this example, the value for the number of items in stock is emitted: + + xo_emit("{P: }{Lwc:In stock}{:in-stock/%u}\n", + instock); + +This call will generate the following output: + + TEXT: + In stock: 144 + XML: + 144 + JSON: + "in-stock": 144, + HTML: +
+
+
In stock
+
:
+
+
144
+
+ +Clearly HTML wins the verbosity award, and this output does +not include XOF_XPATH or XOF_INFO data, which would expand the +penultimate line to: + +
144
+ +** Command-line Arguments + +libxo uses command line options to trigger rendering behavior. The +following options are recognised: + +- --libxo +- --libxo= +- --libxo: + +Options is a comma-separated list of tokens that correspond to output +styles, flags, or features: + +|-----------+-------------------------------------------------------| +| Token | Action | +|-----------+-------------------------------------------------------| +| dtrt | Enable "Do The Right Thing" mode | +| html | Emit HTML output | +| indent=xx | Set the indentation level | +| info | Add info attributes (HTML) | +| json | Emit JSON output | +| keys | Emit the key attribute for keys (XML) | +| no-locale | Do not initialize the locale setting | +| no-top | Do not emit a top set of braces (JSON) | +| not-first | Pretend the 1st output item was not 1st (JSON) | +| pretty | Emit pretty-printed output | +| text | Emit TEXT output | +| units | Add the 'units' (XML) or 'data-units (HTML) attribute | +| warn | Emit warnings when libxo detects bad calls | +| warn-xml | Emit warnings in XML | +| xml | Emit XML output | +| xpath | Add XPath expressions (HTML) | +|-----------+-------------------------------------------------------| + +The brief options are detailed in ^LIBXO_OPTIONS^. + +** Representing Hierarchy + +For XML and JSON, individual fields appear inside hierarchies which +provide context and meaning to the fields. Unfortunately, these +encoding have a basic disconnect between how lists is similar objects +are represented. + +XML encodes lists as set of sequential elements: + + phil + pallavi + sjg + +JSON encodes lists using a single name and square brackets: + + "user": [ "phil", "pallavi", "sjg" ] + +This means libxo needs three distinct indications of hierarchy: one +for containers of hierarchy appear only once for any specific parent, +one for lists, and one for each item in a list. + +*** Containers + +A "container" is an element of a hierarchy that appears only once +under any specific parent. The container has no value, but serves to +contain other nodes. + +To open a container, call xo_open_container() or +xo_open_container_h(). The former uses the default handle and +the latter accepts a specific handle. + + int xo_open_container_h (xo_handle_t *xop, const char *name); + int xo_open_container (const char *name); + +To close a level, use the xo_close_container() or +xo_close_container_h() functions: + + int xo_close_container_h (xo_handle_t *xop, const char *name); + int xo_close_container (const char *name); + +Each open call must have a matching close call. If the XOF_WARN flag +is set and the name given does not match the name of the currently open +container, a warning will be generated. + + 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: + + + my-host.example.org + + + JSON: + "top" : { + "system" : { + "host-name": "my-host.example.org" + } + } + HTML: +
my-host.example.org
+ +*** Lists and Instances + +A list is set of one or more instances that appear under the same +parent. The instances contains 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: + + 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"); + +Getting the list and instance calls correct is critical to the proper +generation of XML and JSON data. + +*** DTRT Mode + +Some user may find tracking the names of open containers, lists, and +instances inconvenient. libxo offers "Do The Right Thing" mode, where +libxo will track the names of open containers, lists, and instances so +the close function can be called without a name. To enable DTRT mode, +turn on the XOF_DTRT flag prior to making any other libxo output. + + xo_set_flags(NULL, XOF_DTRT); + +Each open and close function has a version with the suffix "_d", which +will close the open container, list, or instance: + + xo_open_container("top"); + ... + xo_close_container_d(); + +Note that the XOF_WARN flag will also cause libxo to track open +containers, lists, and instances. A warning is generated with the +name given to the close function and the name recorded do not match. + +** Handles + +libxo uses "handles" to control its rendering functionality. The +handle contains state and buffered data, as well as callback functions +to process data. + +A default handle is used when a NULL is passed to functions accepting +a handle. This handle is initialized to write its data to stdout +using the default style of text (XO_STYLE_TEXT). + +For the convenience of callers, the libxo library includes handle-less +functions that implicitly use the default handle. Any function that +takes a handle will use the default handle is a value of NULL is +passed in place of a valid handle. + +For example, the following are equivalent: + + xo_emit("test"); + xo_emit_h(NULL, "test"); + +Handles are created using xo_create() and destroy using xo_destroy(). + +** UTF-8 + +All strings for libxo must be UTF-8. libxo will handle turning them +into locale-based strings for display to the user. + +The only exception is argument formatted using the "%ls" format, which +require a wide character string (wchar_t *) as input. libxo will +convert these arguments as needed to either UTF-8 (for XML, JSON, and +HTML styles) or locale-based strings for display in text style. + + xo_emit("Alll strings are utf-8 content {:tag/%ls}", + L"except for wide strings"); + +"%S" is equivalent to "%ls". + +* The libxo API + +This section gives details about the functions in libxo, how to call +them, and the actions they perform. + +** Handles + +Handles give an abstraction for libxo that encapsulates the state of a +stream of output. Handles have the data type "xo_handle_t" and are +opaque to the caller. + +The library has a default handle that is automatically initialized. +By default, this handle will send text style output to standard output. +The xo_set_style and xo_set_flags functions can be used to change this +behavior. + +Many libxo functions take a handle as their first parameter; most that +do not use the default handle. Any function taking a handle can +be passed NULL to access the default handle. + +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. + +*** xo_create + +A handle can be allocated using the xo_create() function: + + xo_handle_t *xo_create (unsigned style, unsigned flags); + + Example: + xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN); + .... + xo_emit_h(xop, "testing\n"); + +See also ^styles^ and ^flags^. + +*** xo_create_to_file + +By default, libxo writes output to standard output. A convenience +function is provided for situations when output should be written to +different file: + + xo_handle_t *xo_create_to_file (FILE *fp, unsigned style, + unsigned flags); + +Use the XOF_CLOSE_FP flag to trigger a call to fclose() for +the FILE pointer when the handle is destroyed. + +*** xo_set_writer + +The xo_set_writer function allows custom 'write' functions +which can tailor how libxo writes data. An opaque argument is +recorded and passed back to the write function, allowing the function +to acquire context information. The 'close' function can +release this opaque data and any other resources as needed. + + void xo_set_writer (xo_handle_t *xop, void *opaque, + xo_write_func_t write_func, + xo_close_func_t close_func); + +*** xo_set_style + +To set the style, use the xo_set_style() function: + + void xo_set_style(xo_handle_t *xop, unsigned style); + +To use the default handle, pass a NULL handle: + + xo_set_style(NULL, XO_STYLE_XML); + +**** Output Styles (XO_STYLE_*) @styles@ + +The libxo functions accept a set of output styles: + +|---------------+-------------------------| +| Flag | Description | +|---------------+-------------------------| +| XO_STYLE_TEXT | Traditional text output | +| XO_STYLE_XML | XML encoded data | +| XO_STYLE_JSON | JSON encoded data | +| XO_STYLE_HTML | HTML encoded data | +|---------------+-------------------------| + +**** xo_set_style_name + +The xo_set_style_name() can be used to set the style based on a name +encoded as a string: + + int xo_set_style_name (xo_handle_t *xop, const char *style); + +The name can be any of the styles: "text", "xml", "json", or "html". + + EXAMPLE: + xo_set_style_name(NULL, "html"); + +*** xo_set_flags + +To set the flags, use the xo_set_flags() function: + + void xo_set_flags(xo_handle_t *xop, unsigned flags); + +To use the default handle, pass a NULL handle: + + xo_set_style(NULL, XO_STYLE_XML); + +**** Flags (XOF_*) @flags@ + +The set of valid flags include: + +|-----------------+---------------------------------------| +| Flag | Description | +|-----------------+---------------------------------------| +| XOF_CLOSE_FP | Close file pointer on xo_destroy() | +| XOF_DTRT | Enable "do the right thing" mode | +| XOF_INFO | Display info data attributes (HTML) | +| XOF_KEYS | Emit the key attribute (XML) | +| XOF_NO_ENV | Do not use the LIBXO_OPTIONS env var | +| XOF_PRETTY | Make 'pretty printed' output | +| XOF_UNDERSCORES | Replaces hyphens with underscores | +| XOF_UNITS | Display units (XML and HMTL) | +| XOF_WARN | Generate warnings for broken calls | +| XOF_WARN_XML | Generate warnings in XML on stdout | +| XOF_XPATH | Emit XPath expressions (HTML) | +| XOF_COLUMNS | Force xo_emit to return columns used | +| XOF_FLUSH | Flush output after each xo_emit call | +|-----------------+---------------------------------------| + +The XOF_CLOSE_FP flag will trigger the call of the close_func +(provided via xo_set_writer()) when the handle is destroyed. + +The XOF_PRETTY flag requests 'pretty printing', which will trigger the +addition of indentation and newlines to enhance the readability of +XML, JSON, and HTML output. Text output is not affected. + +The XOF_WARN flag requests that warnings will trigger diagnostic +output (on standard error) when the library notices errors during +operations, or with arguments to functions. Without warning enabled, +such conditions are ignored. + +Warnings allow developers to debug their interaction with libxo. +The function "xo_failure" can used as a breakpoint for a debugger, +regardless of whether warnings are enabled. + +If the style is XO_STYLE_HTML, the following additional flags can be +used: + +|---------------+-----------------------------------------| +| Flag | Description | +|---------------+-----------------------------------------| +| XOF_XPATH | Emit "data-xpath" attributes | +| XOF_INFO | Emit additional info fields | +|---------------+-----------------------------------------| + +The 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. + +The XOF_INFO flag encodes additional informational fields for HTML +output. See ^info^ for details. + +If the style is XO_STYLE_XML, the following additional flags can be +used: + +|---------------+-----------------------------------------| +| Flag | Description | +|---------------+-----------------------------------------| +| XOF_KEYS | Flag 'key' fields for xml | +|---------------+-----------------------------------------| + +The XOF_KEYS flag adds 'key' attribute to the XML encoding for +field definitions that use the 'k' modifier. The key attribute has +the value "key": + + xo_emit("{k:name}", item); + + XML: + truck + +**** xo_clear_flags + +The xo_clear_flags() function turns off the given flags in a specific +handle. + + void xo_clear_flags (xo_handle_t *xop, xo_xof_flags_t flags); + +**** xo_set_options + +The xo_set_options() function accepts a comma-separated list of styles +and flags and enables them for a specific handle. + + int xo_set_options (xo_handle_t *xop, const char *input); + +The options are identical to those listed in ^command-line-arguments^. + +*** xo_destroy + +The xo_destroy function releases a handle and any resources it is +using. Calling xo_destroy with a NULL handle will release any +resources associated with the default handle. + + void xo_destroy(xo_handle_t *xop); + +** Emitting Content (xo_emit) + +The following functions are used to emit output: + + int xo_emit (const char *fmt, ...); + int xo_emit_h (xo_handle_t *xop, const char *fmt, ...); + int xo_emit_hv (xo_handle_t *xop, const char *fmt, va_list vap); + +The "fmt" argument is a string containing field descriptors as +specified in ^format-strings^. The use of a handle is optional and +NULL can be passed to access the internal 'default' handle. See +^handles^. + +The remaining arguments to xo_emit() and xo_emit_h() are a set of +arguments corresponding to the fields in the format string. Care must +be taken to ensure the argument types match the fields in the format +string, since an inappropriate cast can ruin your day. The vap +argument to xo_emit_hv() points to a variable argument list that can +be used to retrieve arguments via va_arg(). + +*** Attributes (xo_attr) @xo_attr@ + +The xo_attr() function emits attributes for the XML output style. + + + int xo_attr (const char *name, const char *fmt, ...); + 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); + +The name parameter give the name of the attribute to be encoded. The +fmt parameter gives a printf-style format string used to format the +value of the attribute using any remaining arguments, or the vap +parameter passed to xo_attr_hv(). + + 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: + 00:14 + +*** Flushing Output (xo_flush) + +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 +xo_flush() call is used for this: + + void xo_flush (void); + void xo_flush_h (xo_handle_t *xop); + +*** Finishing Output (xo_finish) + +When the program is ready to exit or close a handle, a call to +xo_finish() is required. This flushes any buffered data, closes +open libxo constructs, and completes any pending operations. + + void xo_finish (void); + void xo_finish_h (xo_handle_t *xop); + +Calling this function is vital to the proper operation of libxo, +especially for the non-TEXT output styles. + +** Emitting Hierarchy + +libxo represents to types of hierarchy: containers and 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. + +To create a container, use the xo_open_container and +xo_close_container functions: + + int xo_open_container (const char *name); + int xo_open_container_h (xo_handle_t *xop, 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 (const char *name); + int xo_close_container_h (xo_handle_t *xop, const char *name); + int xo_close_container_hd (xo_handle_t *xop); + int xo_close_container_d (void); + +The name parameter gives the name of the container, encoded in UTF-8. +Since ASCII is a proper subset of UTF-8, traditional C strings can be +used directly. + +The close functions with the "_d" suffix are used in "Do The Right +Thing" mode, where the name of the open containers, lists, and +instances are maintained internally by libxo to allow the caller to +avoid keeping track of the open container name. + +Use the XOF_WARN flag to generate a warning if the name given on the +close does not match the current open container. + +For TEXT and HTML output, containers are not rendered into output +text, though for HTML they are used when the XOF_XPATH flag is set. + + EXAMPLE: + xo_open_container("system"); + xo_emit("The host name is {:host-name}\n", hn); + xo_close_container("system"); + XML: + foo + +*** Lists and Instances + +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. + +The name given to all calls must be identical, and it is strong +suggested that the name be singular, not plural, as a matter of +style and usage expectations. + + 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: + + phil + 1001 + 1001 + /home/phil + + + pallavi + 1002 + 1002 + /home/pallavi + + JSON: + user: [ + { + "name": "phil", + "uid": 1001, + "gid": 1001, + "home": "/home/phil", + }, + { + "name": "pallavi", + "uid": 1002, + "gid": 1002, + "home": "/home/pallavi", + } + ] + +** Additional Functionality + +*** Parsing Command-line Arguments (xo_parse_args) + +The xo_parse_args() function is used to process a program's +arguments. 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. + + argc = xo_parse_args(argc, argv); + if (argc < 0) + exit(1); + +Following the call to xo_parse_args, the application can process the +remaining arguments in a normal manner. See ^command-line-arguments^ +for a description of valid arguments. + +*** Field Information (xo_info_t) @info@ + +HTML data can include additional information in attributes that +begin with "data-". To enable this, three things must occur: + +First the application must build an array of xo_info_t structures, +one per tag. The array must be sorted by name, since libxo uses a +binary search to find the entry that matches names from format +instructions. + +Second, the application must inform libxo about this information using +the xo_set_info() call: + + 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; + + void xo_set_info (xo_handle_t *xop, xo_info_t *infop, int count); + +Like other libxo calls, passing NULL for the handle tells libxo to use +the default handle. + +If the count is -1, libxo will count the elements of infop, but there +must be an empty element at the end. More typically, the number is +known to the application: + + 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); + +Third, the emitting of info must be triggered with the XOF_INFO flag +using either the xo_set_flags() function or the "--libxo=info" command +line argument. + +The type and help values, if present, are emitted as the "data-type" +and "data-help" attributes: + +
GRO-000-533
+ +*** Memory Allocation + +The xo_set_allocator function allows libxo to be used in environments +where the standard realloc() and free() functions are not available. + + void xo_set_allocator (xo_realloc_func_t realloc_func, + xo_free_func_t free_func); + +realloc_func should expect the same arguments as realloc(3) and return +a pointer to memory following the same convention. free_func will +receive the same argument as free(3) and should release it, as +appropriate for the environment. + +By default, the standard realloc() and free() functions are used. + +*** LIBXO_OPTIONS @LIBXO_OPTIONS@ + +The environment variable "LIBXO_OPTIONS" can be set to a string of +options: + +|--------+-------------------------------------------| +| Option | Action | +|--------+-------------------------------------------| +| H | Enable HTML output (XO_STYLE_HTML) | +| I | Enable info output (XOF_INFO) | +| i | Indent by | +| J | Enable JSON output (XO_STYLE_JSON) | +| P | Enable pretty-printed output (XOF_PRETTY) | +| T | Enable text output (XO_STYLE_TEXT) | +| W | Enable warnings (XOF_WARN) | +| X | Enable XML output (XO_STYLE_XML) | +| x | Enable XPath data (XOF_XPATH) | +|--------+-------------------------------------------| + +For example, warnings can be enabled by: + + % env LIBXO_OPTIONS=W my-app + +Complete HTML output can be generated with: + + % env LIBXO_OPTIONS=HXI my-app + +*** Errors, Warnings, and Messages + +Many programs make use of the standard library functions err() and +warn() to generate errors and warnings for the user. libxo wants to +pass that information via the current output style, and provides +compatible functions to allow this: + + void xo_warn (const char *fmt, ...); + void xo_warnx (const char *fmt, ...); + void xo_warn_c (int code, const char *fmt, ...); + void xo_warn_hc (xo_handle_t *xop, int code, + const char *fmt, ...); + void xo_err (int eval, const char *fmt, ...); + void xo_errc (int eval, int code, const char *fmt, ...); + void xo_errx (int eval, const char *fmt, ...); + void xo_message (const char *fmt, ...); + void xo_message_c (int code, const char *fmt, ...); + void xo_message_hc (xo_handle_t *xop, int code, + const char *fmt, ...); + void xo_message_hcv (xo_handle_t *xop, int code, + const char *fmt, va_list vap); + +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 "errno" or the "code" parameter. + + EXAMPLE: + if (open(filename, O_RDONLY) < 0) + xo_err(1, "cannot open file '%s'", filename); + +*** xo_no_setlocale + +libxo automatically initializes the locale based on setting of the +environment variables LC_CTYPE, LANG, and LC_ALL. The first of this +list of variables is used and if none of the variables, the locale +defaults to "UTF-8". The caller may wish to avoid this behavior, and +can do so by calling the xo_no_setlocale() function. + + void xo_no_setlocale (void); + +* The "xo" Utility + +The "xo" utility allows command line access to the functionality of +the libxo library. Using "xo", shell scripts can emit XML, JSON, and +HTML using the same commands that emit text output. + +The style of output can be selected using a specific option: "-X" for +XML, "-J" for JSON, "-H" for HTML, or "-T" for TEXT, which is the +default. The "--style