diff --git a/contrib/libxo/.gitignore b/contrib/libxo/.gitignore index 8d70b6cc155..f4ace8fe0a8 100644 --- a/contrib/libxo/.gitignore +++ b/contrib/libxo/.gitignore @@ -1,46 +1,32 @@ -# Object files -*.o - -# Libraries -*.lib -*.a - -# Shared objects (inc. Windows DLLs) -*.dll -*.so -*.so.* -*.dylib - -# Executables -*.exe -*.app - -*~ -*.orig - +tag.sh +Makefile.in aclocal.m4 ar-lib autom4te.cache -build +bin +build* compile +configure config.guess -config.h.in config.sub depcomp +doc/Makefile.in +info* install-sh ltmain.sh -missing m4 - -Makefile.in -configure -.DS_Store - -xoconfig.h.in -xo_config.h.in - -.gdbinit -.gdbinit.local -xtest -xtest.dSYM -tests/w +missing +patches* +doc/Makefile.in +encoder/Makefile.in +encoder/cbor/Makefile.in +encoder/test/Makefile.in +libxo/Makefile.in +tests/Makefile.in +tests/core/Makefile.in +tests/gettext/Makefile.in +tests/xo/Makefile.in +xo/Makefile.in +xohtml/Makefile.in +xolint/Makefile.in +xopo/Makefile.in diff --git a/contrib/libxo/.svnignore b/contrib/libxo/.svnignore deleted file mode 100644 index 8327c93fdd1..00000000000 --- a/contrib/libxo/.svnignore +++ /dev/null @@ -1,18 +0,0 @@ -Makefile.in -aclocal.m4 -ar-lib -autom4te.cache -bin* -build* -compile -configure -config.guess -config.sub -depcomp -doc/Makefile.in -info* -install-sh -ltmain.sh -m4 -missing -patches* diff --git a/contrib/libxo/Makefile.am b/contrib/libxo/Makefile.am index 286bef97b78..617e3b1af87 100644 --- a/contrib/libxo/Makefile.am +++ b/contrib/libxo/Makefile.am @@ -10,7 +10,7 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = libxo xo xopo xolint xohtml tests doc encoder +SUBDIRS = bin libxo xo xopo xolint xohtml tests doc encoder bin_SCRIPTS=libxo-config dist_doc_DATA = Copyright @@ -32,7 +32,6 @@ errors: docs: @(cd doc ; ${MAKE} docs) - DIST_FILES_DIR = ~/Dropbox/dist-files/ GH_PAGES_DIR = gh-pages/ GH_PAGES_DIR_VER = gh-pages/${PACKAGE_VERSION} @@ -49,18 +48,20 @@ upload: dist upload-docs upload-xohtml-files @echo "Remember to run:" @echo " gt tag ${PACKAGE_VERSION}" -upload-docs: docs - @echo "Uploading libxo-manual.html ... " - @-[ -d ${GH_PAGES_DIR} ] \ - && echo "Updating manual on gh-pages ..." \ - && mkdir -p ${GH_PAGES_DIR_VER} \ - && cp doc/libxo-manual.html ${GH_PAGES_DIR} \ - && cp doc/libxo-manual.html ${GH_PAGES_DIR_VER} \ +upload-docs: docs upload-html + +upload-html: + @echo "Uploading html ... " + @-[ -d ${GH_PAGES_DIR} -a -d doc/html ] \ + && echo "Updating html on gh-pages ..." \ + && mkdir -p ${GH_PAGES_DIR_VER}/html \ + && cp doc/top-link.html ${GH_PAGES_DIR}/libxo.html \ + && cp -r doc/html/* ${GH_PAGES_DIR_VER}/html/ \ && (cd ${GH_PAGES_DIR} \ - && git add ${PACKAGE_VERSION} \ - && git add libxo-manual.html \ + && git add libxo.html \ + && git add ${PACKAGE_VERSION}/html \ && git commit -m 'new docs' \ - libxo-manual.html ${PACKAGE_VERSION} \ + libxo.html ${PACKAGE_VERSION}/html \ && git push origin gh-pages ) ; true upload-xohtml-files: diff --git a/contrib/libxo/README.md b/contrib/libxo/README.md index e9b3b4bd093..fdba97a001b 100644 --- a/contrib/libxo/README.md +++ b/contrib/libxo/README.md @@ -10,6 +10,9 @@ 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. +Imagine a simplified ``wc`` that emits its output fields in a single +xo_emit call: + ``` xo_emit(" {:lines/%7ju/%ju} {:words/%7ju/%ju} " "{:characters/%7ju/%ju}{d:filename/%s}\n", diff --git a/contrib/libxo/configure.ac b/contrib/libxo/configure.ac index 852fed5818c..2f5681d4276 100644 --- a/contrib/libxo/configure.ac +++ b/contrib/libxo/configure.ac @@ -11,8 +11,8 @@ # a particular user has the dist or svn release. # -AC_PREREQ(2.2) -AC_INIT([libxo], [1.0.4], [phil@juniper.net]) +AC_PREREQ([2.69]) +AC_INIT([libxo],[1.6.0],[phil@juniper.net]) AM_INIT_AUTOMAKE([-Wall -Werror foreign -Wno-portability]) # Support silent build rules. Requires at least automake-1.11. @@ -38,8 +38,6 @@ AC_PATH_PROG(MV, mv, /bin/mv) AC_PATH_PROG(RM, rm, /bin/rm) AC_PATH_PROG(SED, sed, /bin/sed) -AC_STDC_HEADERS - # Checks for typedefs, structures, and compiler characteristics. AC_C_INLINE AC_TYPE_SIZE_T @@ -335,9 +333,10 @@ AM_CONDITIONAL([HAVE_LIBM], [test "$HAVE_LIBM" != "no"]) AC_MSG_CHECKING([compiler for gcc]) HAVE_GCC=no if test "${CC}" != ""; then - HAVE_GCC=`${CC} --version 2>&1 | grep GCC` + HAVE_GCC=`${CC} --version 2>&1 | grep -i GCC` if test "${HAVE_GCC}" != ""; then HAVE_GCC=yes + AC_DEFINE([HAVE_GCC], [1], [Using real gcc]) else HAVE_GCC=no fi @@ -450,8 +449,10 @@ AC_CONFIG_FILES([ xohtml/xohtml.sh libxo/Makefile libxo/add.man + bin/Makefile encoder/Makefile encoder/cbor/Makefile + encoder/csv/Makefile encoder/test/Makefile xo/Makefile xolint/Makefile @@ -459,6 +460,7 @@ AC_CONFIG_FILES([ xopo/Makefile packaging/libxo.pc doc/Makefile + doc/top-link.html tests/Makefile tests/core/Makefile tests/gettext/Makefile diff --git a/contrib/libxo/encoder/Makefile.am b/contrib/libxo/encoder/Makefile.am index 10d19de7322..6eb55570373 100644 --- a/contrib/libxo/encoder/Makefile.am +++ b/contrib/libxo/encoder/Makefile.am @@ -1,9 +1,12 @@ # -# Copyright 2015, Juniper Networks, Inc. +# Copyright 2015-2019, 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 +SUBDIRS = \ + cbor \ + csv \ + test diff --git a/contrib/libxo/encoder/cbor/enc_cbor.c b/contrib/libxo/encoder/cbor/enc_cbor.c index 08ed4a06b37..28ca0f7ea3e 100644 --- a/contrib/libxo/encoder/cbor/enc_cbor.c +++ b/contrib/libxo/encoder/cbor/enc_cbor.c @@ -208,9 +208,9 @@ cbor_content (xo_handle_t *xop, cbor_private_t *cbor, xo_buffer_t *xbp, unsigned offset = xo_buf_offset(xbp); - if (value == NULL || *value == '\0' || strcmp(value, "true") == 0) + if (value == NULL || *value == '\0' || xo_streq(value, "true")) cbor_append(xop, cbor, &cbor->c_data, CBOR_TRUE, 0, NULL); - else if (strcmp(value, "false") == 0) + else if (xo_streq(value, "false")) cbor_append(xop, cbor, &cbor->c_data, CBOR_FALSE, 0, NULL); else { int negative = 0; @@ -360,6 +360,7 @@ int xo_encoder_library_init (XO_ENCODER_INIT_ARGS) { arg->xei_handler = cbor_handler; + arg->xei_version = XO_ENCODER_VERSION; return 0; } diff --git a/contrib/libxo/encoder/csv/Makefile.am b/contrib/libxo/encoder/csv/Makefile.am new file mode 100644 index 00000000000..17faf718267 --- /dev/null +++ b/contrib/libxo/encoder/csv/Makefile.am @@ -0,0 +1,51 @@ +# +# $Id$ +# +# Copyright 2015-2019, 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_csvincdir = ${includedir}/libxo + +AM_CFLAGS = \ + -I${top_srcdir}/libxo \ + -I${top_builddir}/libxo \ + ${WARNINGS} + +LIBNAME = libenc_csv +pkglib_LTLIBRARIES = libenc_csv.la +LIBS = \ + -L${top_builddir}/libxo -lxo + +LDADD = ${top_builddir}/libxo/libxo.la + +libenc_csv_la_SOURCES = \ + enc_csv.c + +pkglibdir = ${XO_ENCODERDIR} + +UGLY_NAME = csv.enc + +install-exec-hook: + @DLNAME=`sh -c '. ./libenc_csv.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} diff --git a/contrib/libxo/encoder/csv/enc_csv.c b/contrib/libxo/encoder/csv/enc_csv.c new file mode 100644 index 00000000000..10f9110f493 --- /dev/null +++ b/contrib/libxo/encoder/csv/enc_csv.c @@ -0,0 +1,834 @@ +/* + * 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 + */ + +/* + * CSV encoder generates comma-separated value files for specific + * subsets of data. This is not (and cannot be) a generalized + * facility, but for specific subsets of data, CSV data can be + * reasonably generated. For example, the df XML content: + * + * procfs + * 4 + * 4 + * 0 + * 100 + * /proc + * + * + * could be represented as: + * + * #+name,total-blocks,used-blocks,available-blocks,used-percent,mounted-on + * procfs,4,4,0,100,/proc + * + * Data is then constrained to be sibling leaf values. In addition, + * singular leafs can also be matched. The costs include recording + * the specific leaf names (to ensure consistency) and some + * buffering. + * + * Some escaping is needed for CSV files, following the rules of RFC4180: + * + * - Fields containing a line-break, double-quote or commas should be + * quoted. (If they are not, the file will likely be impossible to + * process correctly). + * - A (double) quote character in a field must be represented by two + * (double) quote characters. + * - Leading and trialing whitespace require fields be quoted. + * + * Cheesy, but simple. The RFC also requires MS-DOS end-of-line, + * which we only do with the "dos" option. Strange that we still live + * in a DOS-friendly world, but then again, we make spaceships based + * on the horse butts (http://www.astrodigital.org/space/stshorse.html + * though the "built by English expatriates” bit is rubbish; better to + * say the first engines used in America were built by Englishmen.) + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xo.h" +#include "xo_encoder.h" +#include "xo_buf.h" + +#ifndef UNUSED +#define UNUSED __attribute__ ((__unused__)) +#endif /* UNUSED */ + +/* + * The CSV encoder has three moving parts: + * + * - The path holds the path we are matching against + * - This is given as input via "options" and does not change + * + * - The stack holds the current names of the open elements + * - The "open" operations push, while the "close" pop + * - Turns out, at this point, the stack is unused, but I've + * left "drippings" in the code because I see this as useful + * for future features (under CSV_STACK_IS_NEEDED). + * + * - The leafs record the current set of leaf + * - A key from the parent list counts as a leaf (unless CF_NO_KEYS) + * - Once the path is matched, all other leafs at that level are leafs + * - Leafs are recorded to get the header comment accurately recorded + * - Once the first line is emited, the set of leafs _cannot_ change + * + * We use offsets into the buffers, since we know they can be + * realloc'd out from under us, as the size increases. The 'path' + * is fixed, we allocate it once, so it doesn't need offsets. + */ +typedef struct path_frame_s { + char *pf_name; /* Path member name; points into c_path_buf */ + uint32_t pf_flags; /* Flags for this path element (PFF_*) */ +} path_frame_t; + +typedef struct stack_frame_s { + ssize_t sf_off; /* Element name; offset in c_stack_buf */ + uint32_t sf_flags; /* Flags for this frame (SFF_*) */ +} stack_frame_t; + +/* Flags for sf_flags */ + +typedef struct leaf_s { + ssize_t f_name; /* Name of leaf; offset in c_name_buf */ + ssize_t f_value; /* Value of leaf; offset in c_value_buf */ + uint32_t f_flags; /* Flags for this value (FF_*) */ +#ifdef CSV_STACK_IS_NEEDED + ssize_t f_depth; /* Depth of stack when leaf was recorded */ +#endif /* CSV_STACK_IS_NEEDED */ +} leaf_t; + +/* Flags for f_flags */ +#define LF_KEY (1<<0) /* Leaf is a key */ +#define LF_HAS_VALUE (1<<1) /* Value has been set */ + +typedef struct csv_private_s { + uint32_t c_flags; /* Flags for this encoder */ + + /* The path for which we select leafs */ + char *c_path_buf; /* Buffer containing path members */ + path_frame_t *c_path; /* Array of path members */ + ssize_t c_path_max; /* Depth of c_path[] */ + ssize_t c_path_cur; /* Current depth in c_path[] */ + + /* A stack of open elements (xo_op_list, xo_op_container) */ +#if CSV_STACK_IS_NEEDED + xo_buffer_t c_stack_buf; /* Buffer used for stack content */ + stack_frame_t *c_stack; /* Stack of open tags */ + ssize_t c_stack_max; /* Maximum stack depth */ +#endif /* CSV_STACK_IS_NEEDED */ + ssize_t c_stack_depth; /* Current stack depth */ + + /* List of leafs we are emitting (to ensure consistency) */ + xo_buffer_t c_name_buf; /* String buffer for leaf names */ + xo_buffer_t c_value_buf; /* String buffer for leaf values */ + leaf_t *c_leaf; /* List of leafs */ + ssize_t c_leaf_depth; /* Current depth of c_leaf[] (next free) */ + ssize_t c_leaf_max; /* Max depth of c_leaf[] */ + + xo_buffer_t c_data; /* Buffer for creating data */ +} csv_private_t; + +#define C_STACK_MAX 32 /* default c_stack_max */ +#define C_LEAF_MAX 32 /* default c_leaf_max */ + +/* Flags for this structure */ +#define CF_HEADER_DONE (1<<0) /* Have already written the header */ +#define CF_NO_HEADER (1<<1) /* Do not generate header */ +#define CF_NO_KEYS (1<<2) /* Do not generate excess keys */ +#define CF_VALUE_ONLY (1<<3) /* Only generate the value */ + +#define CF_DOS_NEWLINE (1<<4) /* Generate CR-NL, just like MS-DOS */ +#define CF_LEAFS_DONE (1<<5) /* Leafs are already been recorded */ +#define CF_NO_QUOTES (1<<6) /* Do not generate quotes */ +#define CF_RECORD_DATA (1<<7) /* Record all sibling leafs */ + +#define CF_DEBUG (1<<8) /* Make debug output */ +#define CF_HAS_PATH (1<<9) /* A "path" option was provided */ + +/* + * A simple debugging print function, similar to psu_dbg. Controlled by + * the undocumented "debug" option. + */ +static void +csv_dbg (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED, + const char *fmt, ...) +{ + if (csv == NULL || !(csv->c_flags & CF_DEBUG)) + return; + + va_list vap; + + va_start(vap, fmt); + vfprintf(stderr, fmt, vap); + va_end(vap); +} + +/* + * Create the private data for this handle, initialize it, and record + * the pointer in the handle. + */ +static int +csv_create (xo_handle_t *xop) +{ + csv_private_t *csv = xo_realloc(NULL, sizeof(*csv)); + if (csv == NULL) + return -1; + + bzero(csv, sizeof(*csv)); + xo_buf_init(&csv->c_data); + xo_buf_init(&csv->c_name_buf); + xo_buf_init(&csv->c_value_buf); +#ifdef CSV_STACK_IS_NEEDED + xo_buf_init(&csv->c_stack_buf); +#endif /* CSV_STACK_IS_NEEDED */ + + xo_set_private(xop, csv); + + return 0; +} + +/* + * Clean up and release any data in use by this handle + */ +static void +csv_destroy (xo_handle_t *xop UNUSED, csv_private_t *csv) +{ + /* Clean up */ + xo_buf_cleanup(&csv->c_data); + xo_buf_cleanup(&csv->c_name_buf); + xo_buf_cleanup(&csv->c_value_buf); +#ifdef CSV_STACK_IS_NEEDED + xo_buf_cleanup(&csv->c_stack_buf); +#endif /* CSV_STACK_IS_NEEDED */ + + if (csv->c_leaf) + xo_free(csv->c_leaf); + if (csv->c_path_buf) + xo_free(csv->c_path_buf); +} + +/* + * Return the element name at the top of the path stack. This is the + * item that we are currently trying to match on. + */ +static const char * +csv_path_top (csv_private_t *csv, ssize_t delta) +{ + if (!(csv->c_flags & CF_HAS_PATH) || csv->c_path == NULL) + return NULL; + + ssize_t cur = csv->c_path_cur + delta; + + if (cur < 0) + return NULL; + + return csv->c_path[cur].pf_name; +} + +/* + * Underimplemented stack functionality + */ +static inline void +csv_stack_push (csv_private_t *csv UNUSED, const char *name UNUSED) +{ +#ifdef CSV_STACK_IS_NEEDED + csv->c_stack_depth += 1; +#endif /* CSV_STACK_IS_NEEDED */ +} + +/* + * Underimplemented stack functionality + */ +static inline void +csv_stack_pop (csv_private_t *csv UNUSED, const char *name UNUSED) +{ +#ifdef CSV_STACK_IS_NEEDED + csv->c_stack_depth -= 1; +#endif /* CSV_STACK_IS_NEEDED */ +} + +/* Flags for csv_quote_flags */ +#define QF_NEEDS_QUOTES (1<<0) /* Needs to be quoted */ +#define QF_NEEDS_ESCAPE (1<<1) /* Needs to be escaped */ + +/* + * Determine how much quote processing is needed. The details of the + * quoting rules are given at the top of this file. We return a set + * of flags, indicating what's needed. + */ +static uint32_t +csv_quote_flags (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED, + const char *value) +{ + static const char quoted[] = "\n\r\","; + static const char escaped[] = "\""; + + if (csv->c_flags & CF_NO_QUOTES) /* User doesn't want quotes */ + return 0; + + size_t len = strlen(value); + uint32_t rc = 0; + + if (strcspn(value, quoted) != len) + rc |= QF_NEEDS_QUOTES; + else if (isspace((int) value[0])) /* Leading whitespace */ + rc |= QF_NEEDS_QUOTES; + else if (isspace((int) value[len - 1])) /* Trailing whitespace */ + rc |= QF_NEEDS_QUOTES; + + if (strcspn(value, escaped) != len) + rc |= QF_NEEDS_ESCAPE; + + csv_dbg(xop, csv, "csv: quote flags [%s] -> %x (%zu/%zu)\n", + value, rc, len, strcspn(value, quoted)); + + return rc; +} + +/* + * Escape the string, following the rules in RFC4180 + */ +static void +csv_escape (xo_buffer_t *xbp, const char *value, size_t len) +{ + const char *cp, *ep, *np; + + for (cp = value, ep = value + len; cp && cp < ep; cp = np) { + np = strchr(cp, '"'); + if (np) { + np += 1; + xo_buf_append(xbp, cp, np - cp); + xo_buf_append(xbp, "\"", 1); + } else + xo_buf_append(xbp, cp, ep - cp); + } +} + +/* + * Append a newline to the buffer, following the settings of the "dos" + * flag. + */ +static void +csv_append_newline (xo_buffer_t *xbp, csv_private_t *csv) +{ + if (csv->c_flags & CF_DOS_NEWLINE) + xo_buf_append(xbp, "\r\n", 2); + else + xo_buf_append(xbp, "\n", 1); +} + +/* + * Create a 'record' of 'fields' from our recorded leaf values. If + * this is the first line and "no-header" isn't given, make a record + * containing the leaf names. + */ +static void +csv_emit_record (xo_handle_t *xop, csv_private_t *csv) +{ + csv_dbg(xop, csv, "csv: emit: ...\n"); + + ssize_t fnum; + uint32_t quote_flags; + leaf_t *lp; + + /* If we have no data, then don't bother */ + if (csv->c_leaf_depth == 0) + return; + + if (!(csv->c_flags & (CF_HEADER_DONE | CF_NO_HEADER))) { + csv->c_flags |= CF_HEADER_DONE; + + for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) { + lp = &csv->c_leaf[fnum]; + const char *name = xo_buf_data(&csv->c_name_buf, lp->f_name); + + if (fnum != 0) + xo_buf_append(&csv->c_data, ",", 1); + + xo_buf_append(&csv->c_data, name, strlen(name)); + } + + csv_append_newline(&csv->c_data, csv); + } + + for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) { + lp = &csv->c_leaf[fnum]; + const char *value; + + if (lp->f_flags & LF_HAS_VALUE) { + value = xo_buf_data(&csv->c_value_buf, lp->f_value); + } else { + value = ""; + } + + quote_flags = csv_quote_flags(xop, csv, value); + + if (fnum != 0) + xo_buf_append(&csv->c_data, ",", 1); + + if (quote_flags & QF_NEEDS_QUOTES) + xo_buf_append(&csv->c_data, "\"", 1); + + if (quote_flags & QF_NEEDS_ESCAPE) + csv_escape(&csv->c_data, value, strlen(value)); + else + xo_buf_append(&csv->c_data, value, strlen(value)); + + if (quote_flags & QF_NEEDS_QUOTES) + xo_buf_append(&csv->c_data, "\"", 1); + } + + csv_append_newline(&csv->c_data, csv); + + /* We flush if either flush flag is set */ + if (xo_get_flags(xop) & (XOF_FLUSH | XOF_FLUSH_LINE)) + xo_flush_h(xop); + + /* Clean out values from leafs */ + for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) { + lp = &csv->c_leaf[fnum]; + + lp->f_flags &= ~LF_HAS_VALUE; + lp->f_value = 0; + } + + xo_buf_reset(&csv->c_value_buf); + + /* + * Once we emit the first line, our set of leafs is locked and + * cannot be changed. + */ + csv->c_flags |= CF_LEAFS_DONE; +} + +/* + * Open a "level" of hierarchy, either a container or an instance. Look + * for a match in the path=x/y/z hierarchy, and ignore if not a match. + * If we're at the end of the path, start recording leaf values. + */ +static int +csv_open_level (xo_handle_t *xop UNUSED, csv_private_t *csv, + const char *name, int instance) +{ + /* An new "open" event means we stop recording */ + if (csv->c_flags & CF_RECORD_DATA) { + csv->c_flags &= ~CF_RECORD_DATA; + csv_emit_record(xop, csv); + return 0; + } + + const char *path_top = csv_path_top(csv, 0); + + /* If the top of the stack does not match the name, then ignore */ + if (path_top == NULL) { + if (instance && !(csv->c_flags & CF_HAS_PATH)) { + csv_dbg(xop, csv, "csv: recording (no-path) ...\n"); + csv->c_flags |= CF_RECORD_DATA; + } + + } else if (xo_streq(path_top, name)) { + csv->c_path_cur += 1; /* Advance to next path member */ + + csv_dbg(xop, csv, "csv: match: [%s] (%zd/%zd)\n", name, + csv->c_path_cur, csv->c_path_max); + + /* If we're all the way thru the path members, start recording */ + if (csv->c_path_cur == csv->c_path_max) { + csv_dbg(xop, csv, "csv: recording ...\n"); + csv->c_flags |= CF_RECORD_DATA; + } + } + + /* Push the name on the stack */ + csv_stack_push(csv, name); + + return 0; +} + +/* + * Close a "level", either a container or an instance. + */ +static int +csv_close_level (xo_handle_t *xop UNUSED, csv_private_t *csv, const char *name) +{ + /* If we're recording, a close triggers an emit */ + if (csv->c_flags & CF_RECORD_DATA) { + csv->c_flags &= ~CF_RECORD_DATA; + csv_emit_record(xop, csv); + } + + const char *path_top = csv_path_top(csv, -1); + csv_dbg(xop, csv, "csv: close: [%s] [%s] (%zd)\n", name, + path_top ?: "", csv->c_path_cur); + + /* If the top of the stack does not match the name, then ignore */ + if (path_top != NULL && xo_streq(path_top, name)) { + csv->c_path_cur -= 1; + return 0; + } + + /* Pop the name off the stack */ + csv_stack_pop(csv, name); + + return 0; +} + +/* + * Return the index of a given leaf in the c_leaf[] array, where we + * record leaf values. If the leaf is new and we haven't stopped recording + * leafs, then make a new slot for it and record the name. + */ +static int +csv_leaf_num (xo_handle_t *xop UNUSED, csv_private_t *csv, + const char *name, xo_xff_flags_t flags) +{ + ssize_t fnum; + leaf_t *lp; + xo_buffer_t *xbp = &csv->c_name_buf; + + for (fnum = 0; fnum < csv->c_leaf_depth; fnum++) { + lp = &csv->c_leaf[fnum]; + + const char *fname = xo_buf_data(xbp, lp->f_name); + if (xo_streq(fname, name)) + return fnum; + } + + /* If we're done with adding new leafs, then bail */ + if (csv->c_flags & CF_LEAFS_DONE) + return -1; + + /* This leaf does not exist yet, so we need to create it */ + /* Start by checking if there's enough room */ + if (csv->c_leaf_depth + 1 >= csv->c_leaf_max) { + /* Out of room; realloc it */ + ssize_t new_max = csv->c_leaf_max * 2; + if (new_max == 0) + new_max = C_LEAF_MAX; + + lp = xo_realloc(csv->c_leaf, new_max * sizeof(*lp)); + if (lp == NULL) + return -1; /* No luck; bail */ + + /* Zero out the new portion */ + bzero(&lp[csv->c_leaf_max], csv->c_leaf_max * sizeof(*lp)); + + /* Update csv data */ + csv->c_leaf = lp; + csv->c_leaf_max = new_max; + } + + lp = &csv->c_leaf[csv->c_leaf_depth++]; +#ifdef CSV_STACK_IS_NEEDED + lp->f_depth = csv->c_stack_depth; +#endif /* CSV_STACK_IS_NEEDED */ + + lp->f_name = xo_buf_offset(xbp); + + char *cp = xo_buf_cur(xbp); + xo_buf_append(xbp, name, strlen(name) + 1); + + if (flags & XFF_KEY) + lp->f_flags |= LF_KEY; + + csv_dbg(xop, csv, "csv: leaf: name: %zd [%s] [%s] %x\n", + fnum, name, cp, lp->f_flags); + + return fnum; +} + +/* + * Record a new value for a leaf + */ +static void +csv_leaf_set (xo_handle_t *xop UNUSED, csv_private_t *csv, leaf_t *lp, + const char *value) +{ + xo_buffer_t *xbp = &csv->c_value_buf; + + lp->f_value = xo_buf_offset(xbp); + lp->f_flags |= LF_HAS_VALUE; + + char *cp = xo_buf_cur(xbp); + xo_buf_append(xbp, value, strlen(value) + 1); + + csv_dbg(xop, csv, "csv: leaf: value: [%s] [%s] %x\n", + value, cp, lp->f_flags); +} + +/* + * Record the requested set of leaf names. The input should be a set + * of leaf names, separated by periods. + */ +static int +csv_record_leafs (xo_handle_t *xop, csv_private_t *csv, const char *leafs_raw) +{ + char *cp, *ep, *np; + ssize_t len = strlen(leafs_raw); + char *leafs_buf = alloca(len + 1); + + memcpy(leafs_buf, leafs_raw, len + 1); /* Make local copy */ + + for (cp = leafs_buf, ep = leafs_buf + len; cp && cp < ep; cp = np) { + np = strchr(cp, '.'); + if (np) + *np++ = '\0'; + + if (*cp == '\0') /* Skip empty names */ + continue; + + csv_dbg(xop, csv, "adding leaf: [%s]\n", cp); + csv_leaf_num(xop, csv, cp, 0); + } + + /* + * Since we've been told explicitly what leafs matter, ignore the rest + */ + csv->c_flags |= CF_LEAFS_DONE; + + return 0; +} + +/* + * Record the requested path elements. The input should be a set of + * container or instances names, separated by slashes. + */ +static int +csv_record_path (xo_handle_t *xop, csv_private_t *csv, const char *path_raw) +{ + int count; + char *cp, *ep, *np; + ssize_t len = strlen(path_raw); + char *path_buf = xo_realloc(NULL, len + 1); + + memcpy(path_buf, path_raw, len + 1); + + for (cp = path_buf, ep = path_buf + len, count = 2; + cp && cp < ep; cp = np) { + np = strchr(cp, '/'); + if (np) { + np += 1; + count += 1; + } + } + + path_frame_t *path = xo_realloc(NULL, sizeof(path[0]) * count); + if (path == NULL) { + xo_failure(xop, "allocation failure for path '%s'", path_buf); + return -1; + } + + bzero(path, sizeof(path[0]) * count); + + for (count = 0, cp = path_buf; cp && cp < ep; cp = np) { + path[count++].pf_name = cp; + + np = strchr(cp, '/'); + if (np) + *np++ = '\0'; + csv_dbg(xop, csv, "path: [%s]\n", cp); + } + + path[count].pf_name = NULL; + + if (csv->c_path) /* In case two paths are given */ + xo_free(csv->c_path); + if (csv->c_path_buf) /* In case two paths are given */ + xo_free(csv->c_path_buf); + + csv->c_path_buf = path_buf; + csv->c_path = path; + csv->c_path_max = count; + csv->c_path_cur = 0; + + return 0; +} + +/* + * Extract the option values. The format is: + * -libxo encoder=csv:kw=val:kw=val:kw=val,pretty + * -libxo encoder=csv+kw=val+kw=val+kw=val,pretty + */ +static int +csv_options (xo_handle_t *xop, csv_private_t *csv, + const char *raw_opts, char opts_char) +{ + ssize_t len = strlen(raw_opts); + char *options = alloca(len + 1); + memcpy(options, raw_opts, len); + options[len] = '\0'; + + char *cp, *ep, *np, *vp; + for (cp = options, ep = options + len + 1; cp && cp < ep; cp = np) { + np = strchr(cp, opts_char); + if (np) + *np++ = '\0'; + + vp = strchr(cp, '='); + if (vp) + *vp++ = '\0'; + + if (xo_streq(cp, "path")) { + /* Record the path */ + if (vp != NULL && csv_record_path(xop, csv, vp)) + return -1; + + csv->c_flags |= CF_HAS_PATH; /* Yup, we have an explicit path now */ + + } else if (xo_streq(cp, "leafs") + || xo_streq(cp, "leaf") + || xo_streq(cp, "leaves")) { + /* Record the leafs */ + if (vp != NULL && csv_record_leafs(xop, csv, vp)) + return -1; + + } else if (xo_streq(cp, "no-keys")) { + csv->c_flags |= CF_NO_KEYS; + } else if (xo_streq(cp, "no-header")) { + csv->c_flags |= CF_NO_HEADER; + } else if (xo_streq(cp, "value-only")) { + csv->c_flags |= CF_VALUE_ONLY; + } else if (xo_streq(cp, "dos")) { + csv->c_flags |= CF_DOS_NEWLINE; + } else if (xo_streq(cp, "no-quotes")) { + csv->c_flags |= CF_NO_QUOTES; + } else if (xo_streq(cp, "debug")) { + csv->c_flags |= CF_DEBUG; + } else { + xo_warn_hc(xop, -1, + "unknown encoder option value: '%s'", cp); + return -1; + } + } + + return 0; +} + +/* + * Handler for incoming data values. We just record each leaf name and + * value. The values are emittd when the instance is closed. + */ +static int +csv_data (xo_handle_t *xop UNUSED, csv_private_t *csv UNUSED, + const char *name, const char *value, + xo_xof_flags_t flags) +{ + csv_dbg(xop, csv, "data: [%s]=[%s] %llx\n", name, value, (unsigned long long) flags); + + if (!(csv->c_flags & CF_RECORD_DATA)) + return 0; + + /* Find the leaf number */ + int fnum = csv_leaf_num(xop, csv, name, flags); + if (fnum < 0) + return 0; /* Don't bother recording */ + + leaf_t *lp = &csv->c_leaf[fnum]; + csv_leaf_set(xop, csv, lp, value); + + return 0; +} + +/* + * The callback from libxo, passing us operations/events as they + * happen. + */ +static int +csv_handler (XO_ENCODER_HANDLER_ARGS) +{ + int rc = 0; + csv_private_t *csv = private; + xo_buffer_t *xbp = csv ? &csv->c_data : NULL; + + csv_dbg(xop, csv, "op %s: [%s] [%s]\n", xo_encoder_op_name(op), + name ?: "", value ?: ""); + fflush(stdout); + + /* If we don't have private data, we're sunk */ + if (csv == NULL && op != XO_OP_CREATE) + return -1; + + switch (op) { + case XO_OP_CREATE: /* Called when the handle is init'd */ + rc = csv_create(xop); + break; + + case XO_OP_OPTIONS: + rc = csv_options(xop, csv, value, ':'); + break; + + case XO_OP_OPTIONS_PLUS: + rc = csv_options(xop, csv, value, '+'); + break; + + case XO_OP_OPEN_LIST: + case XO_OP_CLOSE_LIST: + break; /* Ignore these ops */ + + case XO_OP_OPEN_CONTAINER: + case XO_OP_OPEN_LEAF_LIST: + rc = csv_open_level(xop, csv, name, 0); + break; + + case XO_OP_OPEN_INSTANCE: + rc = csv_open_level(xop, csv, name, 1); + break; + + case XO_OP_CLOSE_CONTAINER: + case XO_OP_CLOSE_LEAF_LIST: + case XO_OP_CLOSE_INSTANCE: + rc = csv_close_level(xop, csv, name); + break; + + case XO_OP_STRING: /* Quoted UTF-8 string */ + case XO_OP_CONTENT: /* Other content */ + rc = csv_data(xop, csv, name, value, flags); + break; + + case XO_OP_FINISH: /* Clean up function */ + break; + + case XO_OP_FLUSH: /* Clean up function */ + rc = write(1, xbp->xb_bufp, xbp->xb_curp - xbp->xb_bufp); + if (rc > 0) + rc = 0; + + xo_buf_reset(xbp); + break; + + case XO_OP_DESTROY: /* Clean up function */ + csv_destroy(xop, csv); + break; + + case XO_OP_ATTRIBUTE: /* Attribute name/value */ + break; + + case XO_OP_VERSION: /* Version string */ + break; + } + + return rc; +} + +/* + * Callback when our encoder is loaded. + */ +int +xo_encoder_library_init (XO_ENCODER_INIT_ARGS) +{ + arg->xei_handler = csv_handler; + arg->xei_version = XO_ENCODER_VERSION; + + return 0; +} diff --git a/contrib/libxo/encoder/test/enc_test.c b/contrib/libxo/encoder/test/enc_test.c index 1f1783ae6a8..7107ba733ae 100644 --- a/contrib/libxo/encoder/test/enc_test.c +++ b/contrib/libxo/encoder/test/enc_test.c @@ -15,7 +15,7 @@ static int test_handler (XO_ENCODER_HANDLER_ARGS) { printf("op %s: [%s] [%s] [%#llx]\n", xo_encoder_op_name(op), - name ?: "", value ?: "", flags); + name ?: "", value ?: "", (unsigned long long) flags); return 0; } diff --git a/contrib/libxo/libxo/Makefile.am b/contrib/libxo/libxo/Makefile.am index a4d94acae19..9f17527e68e 100644 --- a/contrib/libxo/libxo/Makefile.am +++ b/contrib/libxo/libxo/Makefile.am @@ -74,6 +74,7 @@ man5_files = \ xo_format.5 man7_files = \ + libxo-csv.7 \ xo_options.7 man_MANS = ${man3_files} ${man5_files} ${man7_files} diff --git a/contrib/libxo/libxo/add.man.in b/contrib/libxo/libxo/add.man.in index 4eae26566ae..051be8a65bd 100644 --- a/contrib/libxo/libxo/add.man.in +++ b/contrib/libxo/libxo/add.man.in @@ -5,7 +5,7 @@ uses version @LIBXO_VERSION@. Complete documentation can be found on github: .Bd -literal -offset indent -http://juniper.github.io/libxo/@LIBXO_VERSION@/libxo\-manual.html +https://juniper.github.io/libxo/@LIBXO_VERSION@/html/index.html .Ed .Pp .Nm libxo diff --git a/contrib/libxo/libxo/gen-wide.sh b/contrib/libxo/libxo/gen-wide.sh old mode 100755 new mode 100644 diff --git a/contrib/libxo/libxo/libxo-csv.7 b/contrib/libxo/libxo/libxo-csv.7 new file mode 100644 index 00000000000..6e043820a01 --- /dev/null +++ b/contrib/libxo/libxo/libxo-csv.7 @@ -0,0 +1,274 @@ +.\" # +.\" # Copyright (c) 2021, Juniper Networks, Inc. +.\" # All rights reserved. +.\" # This SOFTWARE is licensed under the LICENSE provided in the +.\" # ../Copyright file. By downloading, installing, copying, or +.\" # using the SOFTWARE, you agree to be bound by the terms of that +.\" # LICENSE. +.\" # Phil Shafer, May 2021 +.\" +.Dd May 13, 2021 +.Dt LIBXO-CSV 7 +.Os +.Sh NAME +.Nm --libxo encoder=csv[+options] +.Nd a CVS encoder for libxo\-based commands +.Sh DESCRIPTION +The +.Nm libxo +library supports a "pluggable" encoder mechanism, and ships with an +encoder for CSV (comma separated values) files. The encoder allows +paths and fields to be selected out of the output contents: +.Bd -literal -offset indent + % df --libxo @csv + name,total-blocks,used-blocks,available-blocks,used-percent,mounted-on + zroot/ROOT/default,3825984331,29376725,3796607605,1,/ + devfs,1,1,0,100,/dev + zroot/usr/home,3808301289,11693684,3796607605,0,/usr/home + zroot/var/audit,3796607806,201,3796607605,0,/var/audit + ... + % df --libxo @csv+leafs=name.used-percent + name,used-percent + zroot/ROOT/default,1 + devfs,100 + zroot/usr/home,0 + zroot/var/audit,0 + ... + % df --libxo @csv+leafs=available-blocks+no-header / + 3796607605 +.Ed + contains software to generate four "built-in" +formats: text, XML, JSON, and HTML. +These formats are common and useful, but there are other common and +useful formats that users will want, and including them all in the +libxo software would be difficult and cumbersome. +.Pp +To allow support for additional encodings, libxo includes a +"pluggable" extension mechanism for dynamically loading new encoders. +.Nm libxo -based +applications can automatically use any installed encoder. +.Pp +Use the "encoder=XXX" option to access encoders. The following +example uses the "cbor" encoder, saving the output into a file: +.Bd -literal -offset indent + df --libxo encoder=cbor > df-output.cbor +.Ed +.Pp +Encoders can support specific options that can be accessed by +following the encoder name with a colon (':') or a plus sign ('+') and +one of more options, separated by the same character: +.Bd -literal -offset indent + df --libxo encoder=csv+path=filesystem+leaf=name+no-header + df --libxo encoder=csv:path=filesystem:leaf=name:no-header +.Ed +.Pp +These examples instructs libxo to load the "csv" encoder and pass the +following options: +.Bd -literal -offset indent + path=filesystem + leaf=name + no-header +.Ed +.Pp +Each of these option is interpreted by the encoder, and all such +options names and semantics are specific to the particular encoder. +Refer to the intended encoder for documentation on its options. +.Pp +The string "@" can be used in place of the string "encoder=". +.Bd -literal -offset indent + df --libxo @csv:no-header +.Ed +.Sh The CSV (Comma Separated Values) Encoder +.Nm libxo +ships with a custom encoder for "CSV" files, a common format for +comma separated values. The output of the CSV encoder can be loaded +directly into spreadsheets or similar applications. +.Pp +A standard for CSV files is provided in RFC 4180, but since the +format predates that standard by decades, there are many minor +differences in CSV file consumers and their expectations. The CSV +encoder has a number of options to tailor output to those +expectations. +.Pp +Consider the following XML: +.Bd -literal -offset indent + % list-items --libxo xml,pretty + + + + GRO-000-415 + gum + 1412 + 54 + 10 + + + HRD-000-212 + rope + 85 + 4 + 2 + + + HRD-000-517 + ladder + 0 + 2 + 1 + + + +.Ed +.Pp +This output is a list of `instances` (named "item"), each containing a +set of `leafs` ("sku", "name", etc). +.Pp +The CSV encoder will emit the leaf values in this output as `fields` +inside a CSV `record`, which is a line containing a set of +comma-separated values: +.Bd -literal -offset indent + % list-items --libxo encoder=csv + sku,name,sold,in-stock,on-order + GRO-000-415,gum,1412,54,10 + HRD-000-212,rope,85,4,2 + HRD-000-517,ladder,0,2,1 +.Ed +.Pp +Be aware that since the CSV encoder looks for data instances, when +used with +.Nm xo , +the `--instance` option will be needed: +.Bd -literal -offset indent + % xo --libxo encoder=csv --instance foo 'The {:product} is {:status}\n' stereo "in route" + product,status + stereo,in route +.Ed +.Sh The "path" Option +By default, the CSV encoder will attempt to emit any list instance +generated by the application. +In some cases, this may be unacceptable, and a specific list may be +desired. +.Pp +Use the "path" option to limit the processing of output to a specific +hierarchy. The path should be one or more names of containers or +lists. +.Pp +For example, if the "list-items" application generates other lists, +the user can give "path=top/data/item" as a path: +.Bd -literal -offset indent + % list-items --libxo encoder=csv:path=top/data/item + sku,name,sold,in-stock,on-order + GRO-000-415,gum,1412,54,10 + HRD-000-212,rope,85,4,2 + HRD-000-517,ladder,0,2,1 +.Ed +.Pp +Paths are "relative", meaning they need not be a complete set +of names to the list. This means that "path=item" may be sufficient +for the above example. +.Sh The "leafs" Option +The CSV encoding requires that all lines of output have the same +number of fields with the same order. In contrast, XML and JSON allow +any order (though libxo forces key leafs to appear before other +leafs). +.Pp +To maintain a consistent set of fields inside the CSV file, the same +set of leafs must be selected from each list item. By default, the +CSV encoder records the set of leafs that appear in the first list +instance it processes, and extract only those leafs from future +instances. If the first instance is missing a leaf that is desired by +the consumer, the "leaf" option can be used to ensure that an empty +value is recorded for instances that lack a particular leaf. +.Pp +The "leafs" option can also be used to exclude leafs, limiting the +output to only those leafs provided. +.Pp +In addition, the order of the output fields follows the order in which +the leafs are listed. "leafs=one.two" and "leafs=two.one" give +distinct output. +.Pp +So the "leafs" option can be used to expand, limit, and order the set +of leafs. +.Pp +The value of the leafs option should be one or more leaf names, +separated by a period ("."): +.Bd -literal -offset indent + % list-items --libxo encoder=csv:leafs=sku.on-order + sku,on-order + GRO-000-415,10 + HRD-000-212,2 + HRD-000-517,1 + % list-items -libxo encoder=csv:leafs=on-order.sku + on-order,sku + 10,GRO-000-415 + 2,HRD-000-212 + 1,HRD-000-517 +.Ed +.Pp +Note that since libxo uses terminology from YANG (:RFC:`7950`), the +data modeling language for NETCONF (:RFC:`6241`), which uses "leafs" +as the plural form of "leaf". libxo follows that convention. +.Sh The "no-header" Option +CSV files typical begin with a line that defines the fields included +in that file, in an attempt to make the contents self-defining: +.Bd -literal -offset indent + sku,name,sold,in-stock,on-order + GRO-000-415,gum,1412,54,10 + HRD-000-212,rope,85,4,2 + HRD-000-517,ladder,0,2,1 +.Ed +.Pp +There is no reliable mechanism for determining whether this header +line is included, so the consumer must make an assumption. +.Pp +The csv encoder defaults to producing the header line, but the +"no-header" option can be included to avoid the header line. +.Sh The "no-quotes" Option +RFC 4180 specifies that fields containing spaces should be quoted, but +many CSV consumers do not handle quotes. The "no-quotes" option +instruct the CSV encoder to avoid the use of quotes. +.Sh The "dos" Option +RFC 4180 defines the end-of-line marker as a carriage return +followed by a newline. This "CRLF" convention dates from the distant +past, but its use was anchored in the 1980s by the `DOS` operating +system. +.Pp +The CSV encoder defaults to using the standard Unix end-of-line +marker, a simple newline. Use the "dos" option to use the `CRLF` +convention. +.Sh Option Handling +The handling of command-line options is complex, since there are three +hierarchies in use, but the rules are: +.Bl -bullet +.It +commas separate +.Nm libxo +options +.Bd -literal -ofset indent + \-\-libxo json,pretty,warn +.Ed +.It +pluses separate encoder options +.Bd -literal -ofset indent +\-\-libxo @csv+dos+no-header,warn +.Ed +.It +periods separate tag names +.Bd -literal -ofset indent +\-\-libxo @csv+leafs=name.used.free+dos,warn +.El +.Sh SEE ALSO +.Xr libxo 3 , +.Xr xo_options 7 +.Sh HISTORY +The +.Nm libxo +library first appeared in +.Fx 11.0 . +The CSV encoder first appeared in +.Fx 13.0 . +.Sh AUTHORS +.Nm libxo +was written by +.An Phil Shafer Aq Mt phil@freebsd.org . + diff --git a/contrib/libxo/libxo/libxo.3 b/contrib/libxo/libxo/libxo.3 index f07962036e0..95c0059865b 100644 --- a/contrib/libxo/libxo/libxo.3 +++ b/contrib/libxo/libxo/libxo.3 @@ -86,6 +86,95 @@ suited for terminal output and HTML is suited for display in a web browser (see .Xr xohtml 1 ). .Pp +.Nm libxo +uses command line options to trigger rendering behavior. +The following options are recognised: +.Pp +.Bl -tag -width "--libxo" +.It +\-\^\-libxo +.It +\-\^\-libxo= +.It +\-\^\-libxo: +.El +.Pp +Options is a comma-separated list of tokens that correspond to output +styles, flags, or features: +.Pp +.Bl -tag -width "12345678" +.It Sy "Token Action" +.It Dv dtrt +Enable "Do The Right Thing" mode +.It Dv html +Emit HTML output +.It Dv indent=xx +Set the indentation level +.It Dv info +Add info attributes (HTML) +.It Dv json +Emit JSON output +.It Dv keys +Emit the key attribute for keys (XML) +.It Dv log-gettext +Log (via stderr) each +.Xr gettext 3 +string lookup +.It Dv log-syslog +Log (via stderr) each syslog message (via +.Xr xo_syslog 3 ) +.It Dv no-humanize +Ignore the {h:} modifier (TEXT, HTML) +.It Dv no-locale +Do not initialize the locale setting +.It Dv no-retain +Prevent retaining formatting information +.It Dv no-top +Do not emit a top set of braces (JSON) +.It Dv not-first +Pretend the 1st output item was not 1st (JSON) +.It Dv pretty +Emit pretty-printed output +.It Dv retain +Force retaining formatting information +.It Dv text +Emit TEXT output +.It Dv underscores +Replace XML-friendly "-"s with JSON friendly "_"s e +.It Dv units +Add the 'units' (XML) or 'data-units (HTML) attribute +.It Dv warn +Emit warnings when libxo detects bad calls +.It Dv warn-xml +Emit warnings in XML +.It Dv xml +Emit XML output +.It Dv xpath +Add XPath expressions (HTML) +.El +.Pp +The +.Dq brief-options +are single letter commands, designed for those with +too little patience to use real tokens. +No comma separator is used. +.Bl -column "i" +.It Sy "Token Action" +.It "H " "Enable HTML output (XO_STYLE_HTML)" +.It "I " "Enable info output (XOF_INFO)" +.It "i " "Indent by " +.It "J " "Enable JSON output (XO_STYLE_JSON)" +.It "P " "Enable pretty-printed output (XOF_PRETTY)" +.It "T " "Enable text output (XO_STYLE_TEXT)" +.It "W " "Enable warnings (XOF_WARN)" +.It "X " "Enable XML output (XO_STYLE_XML)" +.It "x " "Enable XPath data (XOF_XPATH)" +.El +.Pp +Refer to +.Xr xo_options 7 +for additional option information. +.Pp The .Nm library allows an application to generate text, XML, JSON, @@ -291,6 +380,7 @@ Instructs to use an alternative set of low-level output functions. .El .Sh SEE ALSO +.Xr libxo-csv 7, .Xr xo 1 , .Xr xolint 1 , .Xr xo_attr 3 , @@ -303,6 +393,7 @@ to use an alternative set of low-level output functions. .Xr xo_no_setlocale 3 , .Xr xo_open_container 3 , .Xr xo_open_list 3 , +.Xr xo_options 7, .Xr xo_parse_args 3 , .Xr xo_set_allocator 3 , .Xr xo_set_flags 3 , diff --git a/contrib/libxo/libxo/libxo.c b/contrib/libxo/libxo/libxo.c index a70768814c1..916a111f5af 100644 --- a/contrib/libxo/libxo/libxo.c +++ b/contrib/libxo/libxo/libxo.c @@ -293,39 +293,6 @@ struct xo_handle_s { #define XOIF_INIT_IN_PROGRESS XOF_BIT(5) /* Init of handle is in progress */ #define XOIF_MADE_OUTPUT XOF_BIT(6) /* Have already made output */ -/* Flags for formatting functions */ -typedef unsigned long xo_xff_flags_t; -#define XFF_COLON (1<<0) /* Append a ":" */ -#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */ -#define XFF_WS (1<<2) /* Append a blank */ -#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding styles (XML, JSON) */ - -#define XFF_QUOTE (1<<4) /* Force quotes */ -#define XFF_NOQUOTE (1<<5) /* Force no quotes */ -#define XFF_DISPLAY_ONLY (1<<6) /* Only emit for display styles (text, html) */ -#define XFF_KEY (1<<7) /* Field is a key (for XPath) */ - -#define XFF_XML (1<<8) /* Force XML encoding style (for XPath) */ -#define XFF_ATTR (1<<9) /* Escape value using attribute rules (XML) */ -#define XFF_BLANK_LINE (1<<10) /* Emit a blank line */ -#define XFF_NO_OUTPUT (1<<11) /* Do not make any output */ - -#define XFF_TRIM_WS (1<<12) /* Trim whitespace off encoded values */ -#define XFF_LEAF_LIST (1<<13) /* A leaf-list (list of values) */ -#define XFF_UNESCAPE (1<<14) /* Need to printf-style unescape the value */ -#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */ - -#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */ -#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */ -#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */ -#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */ - -#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */ -#define XFF_ARGUMENT (1<<21) /* Content provided via argument */ - -/* Flags to turn off when we don't want i18n processing */ -#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL) - /* * Normal printf has width and precision, which for strings operate as * min and max number of columns. But this depends on the idea that @@ -435,9 +402,6 @@ xo_realloc_func_t xo_realloc = realloc; xo_free_func_t xo_free = free; /* Forward declarations */ -static void -xo_failure (xo_handle_t *xop, const char *fmt, ...); - static ssize_t xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name, xo_state_t new_state); @@ -660,13 +624,18 @@ xo_init_handle (xo_handle_t *xop) if (!xo_locale_inited) { xo_locale_inited = 1; /* Only do this once */ - const char *cp = getenv("LC_CTYPE"); +#ifdef __FreeBSD__ /* Who does The Right Thing */ + const char *cp = ""; +#else /* __FreeBSD__ */ + const char *cp = getenv("LC_ALL"); if (cp == NULL) - cp = getenv("LANG"); + cp = getenv("LC_CTYPE"); if (cp == NULL) - cp = getenv("LC_ALL"); + cp = getenv("LANG"); if (cp == NULL) cp = "C"; /* Default for C programs */ +#endif /* __FreeBSD__ */ + (void) setlocale(LC_CTYPE, cp); } @@ -1871,7 +1840,7 @@ xo_message (const char *fmt, ...) va_end(vap); } -static void +void xo_failure (xo_handle_t *xop, const char *fmt, ...) { if (!XOF_ISSET(xop, XOF_WARN)) @@ -2042,17 +2011,17 @@ xo_get_style (xo_handle_t *xop) static int xo_name_to_style (const char *name) { - if (strcmp(name, "xml") == 0) + if (xo_streq(name, "xml")) return XO_STYLE_XML; - else if (strcmp(name, "json") == 0) + else if (xo_streq(name, "json")) return XO_STYLE_JSON; - else if (strcmp(name, "encoder") == 0) + else if (xo_streq(name, "encoder")) return XO_STYLE_ENCODER; - else if (strcmp(name, "text") == 0) + else if (xo_streq(name, "text")) return XO_STYLE_TEXT; - else if (strcmp(name, "html") == 0) + else if (xo_streq(name, "html")) return XO_STYLE_HTML; - else if (strcmp(name, "sdparams") == 0) + else if (xo_streq(name, "sdparams")) return XO_STYLE_SDPARAMS; return -1; @@ -2230,7 +2199,7 @@ xo_set_color_map (xo_handle_t *xop, char *value) } /* If no color initialization happened, then we don't need the map */ - if (num > 0) + if (num > 1) XOF_SET(xop, XOF_COLOR_MAP); else XOF_CLEAR(xop, XOF_COLOR_MAP); @@ -2261,7 +2230,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input) if (vp) *vp++ = '\0'; - if (strcmp("colors", cp) == 0) { + if (xo_streq("colors", cp)) { xo_set_color_map(xop, vp); continue; } @@ -2269,7 +2238,7 @@ xo_set_options_simple (xo_handle_t *xop, const char *input) new_flag = xo_name_lookup(xo_xof_simple_names, cp, -1); if (new_flag != 0) { XOF_SET(xop, new_flag); - } else if (strcmp(cp, "no-color") == 0) { + } else if (xo_streq(cp, "no-color")) { XOF_CLEAR(xop, XOF_COLOR_ALLOWED); } else { xo_failure(xop, "unknown simple option: %s", cp); @@ -2402,11 +2371,30 @@ xo_set_options (xo_handle_t *xop, const char *input) if (np) *np++ = '\0'; + /* + * "@foo" is a shorthand for "encoder=foo". This is driven + * chiefly by a desire to make pluggable encoders not appear + * so distinct from built-in encoders. + */ + if (*cp == '@') { + vp = cp + 1; + + if (*vp == '\0') + xo_failure(xop, "missing value for encoder option"); + else { + rc = xo_encoder_init(xop, vp); + if (rc) + xo_warnx("error initializing encoder: %s", vp); + } + + continue; + } + vp = strchr(cp, '='); if (vp) *vp++ = '\0'; - if (strcmp("colors", cp) == 0) { + if (xo_streq("colors", cp)) { xo_set_color_map(xop, vp); continue; } @@ -2425,21 +2413,20 @@ xo_set_options (xo_handle_t *xop, const char *input) new_flag = xo_name_to_flag(cp); if (new_flag != 0) XOF_SET(xop, new_flag); - else if (strcmp(cp, "no-color") == 0) + else if (xo_streq(cp, "no-color")) XOF_CLEAR(xop, XOF_COLOR_ALLOWED); - else if (strcmp(cp, "indent") == 0) { + else if (xo_streq(cp, "indent")) { if (vp) xop->xo_indent_by = atoi(vp); else xo_failure(xop, "missing value for indent option"); - } else if (strcmp(cp, "encoder") == 0) { + } else if (xo_streq(cp, "encoder")) { if (vp == NULL) xo_failure(xop, "missing value for encoder option"); else { - if (xo_encoder_init(xop, vp)) { - xo_failure(xop, "encoder not found: %s", vp); - rc = -1; - } + rc = xo_encoder_init(xop, vp); + if (rc) + xo_warnx("error initializing encoder: %s", vp); } } else { @@ -3356,7 +3343,7 @@ xo_do_format_field (xo_handle_t *xop, xo_buffer_t *xbp, cp += 1; continue; - } if (cp + 1 < ep && cp[1] == '%') { + } else if (cp + 1 < ep && cp[1] == '%') { cp += 1; goto add_one; } @@ -4733,7 +4720,7 @@ xo_color_find (const char *str) int i; for (i = 0; xo_color_names[i]; i++) { - if (strcmp(xo_color_names[i], str) == 0) + if (xo_streq(xo_color_names[i], str)) return i; } @@ -4784,7 +4771,7 @@ xo_effect_find (const char *str) int i; for (i = 0; xo_effect_names[i]; i++) { - if (strcmp(xo_effect_names[i], str) == 0) + if (xo_streq(xo_effect_names[i], str)) return i; } @@ -5653,6 +5640,7 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED, xo_field_info_t *xfip; unsigned fnum, max_fields; uint64_t bits = 0; + const uint64_t one = 1; /* Avoid "1ULL" */ /* First make a list of add the explicitly used bits */ for (xfip = fields, fnum = 0; xfip->xfi_ftype; xfip++) { @@ -5669,7 +5657,7 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED, break; if (xfip->xfi_fnum) - bits |= 1 << xfip->xfi_fnum; + bits |= one << xfip->xfi_fnum; } max_fields = fnum; @@ -5687,14 +5675,14 @@ xo_gettext_finish_numbering_fields (xo_handle_t *xop UNUSED, continue; /* Find the next unassigned field */ - for (fnum++; bits & (1 << fnum); fnum++) + for (fnum++; bits & (one << fnum); fnum++) continue; if (fnum > max_fields) break; xfip->xfi_fnum = fnum; /* Mark the field number */ - bits |= 1 << fnum; /* Mark it used */ + bits |= one << fnum; /* Mark it used */ } } @@ -5709,6 +5697,7 @@ xo_parse_field_numbers (xo_handle_t *xop, const char *fmt, xo_field_info_t *xfip; unsigned field, fnum; uint64_t bits = 0; + const uint64_t one = 1; /* Avoid 1ULL */ for (xfip = fields, field = 0; field < num_fields; xfip++, field++) { /* Fields default to 1:1 with natural position */ @@ -5721,12 +5710,12 @@ xo_parse_field_numbers (xo_handle_t *xop, const char *fmt, fnum = xfip->xfi_fnum - 1; /* Move to zero origin */ if (fnum < 64) { /* Only test what fits */ - if (bits & (1 << fnum)) { + if (bits & (one << fnum)) { xo_failure(xop, "field number %u reused: '%s'", xfip->xfi_fnum, fmt); return -1; } - bits |= 1 << fnum; + bits |= one << fnum; } } @@ -5786,9 +5775,10 @@ xo_parse_fields (xo_handle_t *xop, xo_field_info_t *fields, xfip->xfi_len = sp - xfip->xfi_start + 1; /* Move along the string, but don't run off the end */ - if (*sp == '}' && sp[1] == '}') + if (*sp == '}' && sp[1] == '}') /* Paranoid; must be true */ sp += 2; - cp = *sp ? sp : sp; + + cp = sp; xfip->xfi_next = cp; continue; } @@ -6186,7 +6176,7 @@ xo_gettext_build_format (xo_handle_t *xop, goto bail2; const char *gtfmt = xo_dgettext(xop, xb.xb_bufp); - if (gtfmt == NULL || gtfmt == fmt || strcmp(gtfmt, fmt) == 0) + if (gtfmt == NULL || gtfmt == fmt || xo_streq(gtfmt, fmt)) goto bail2; char *new_fmt = xo_strndup(gtfmt, -1); @@ -6875,7 +6865,7 @@ xo_depth_change (xo_handle_t *xop, const char *name, xo_stack_t *xsp = &xop->xo_stack[xop->xo_depth]; if (XOF_ISSET(xop, XOF_WARN)) { const char *top = xsp->xs_name; - if (top != NULL && name != NULL && strcmp(name, top) != 0) { + if (top != NULL && name != NULL && !xo_streq(name, top)) { xo_failure(xop, "incorrect close: '%s' .vs. '%s'", name, top); return; @@ -6989,8 +6979,21 @@ xo_do_open_container (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + /* If we need underscores, make a local copy and doctor it */ + const char *new_name = name; + if (XOF_ISSET(xop, XOF_UNDERSCORES)) { + size_t len = strlen(name); + const char *old_name = name; + char *buf, *cp, *ep; + + buf = alloca(len + 1); + for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++) + *cp = (*old_name == '-') ? '_' : *old_name; + new_name = buf; + } + rc = xo_printf(xop, "%s%*s\"%s\": {%s", - pre_nl, xo_indent(xop), "", name, ppn); + pre_nl, xo_indent(xop), "", new_name, ppn); break; case XO_STYLE_SDPARAMS: @@ -7074,7 +7077,6 @@ xo_do_close_container (xo_handle_t *xop, const char *name) xo_stack_set_flags(xop); pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? "\n" : ""; - ppn = (xop->xo_depth <= 1) ? pre_nl : ""; ppn = ""; xo_depth_change(xop, name, -1, -1, XSS_CLOSE_CONTAINER, 0); @@ -7153,8 +7155,21 @@ xo_do_open_list (xo_handle_t *xop, xo_xof_flags_t flags, const char *name) pre_nl = XOF_ISSET(xop, XOF_PRETTY) ? ",\n" : ", "; xop->xo_stack[xop->xo_depth].xs_flags |= XSF_NOT_FIRST; + /* If we need underscores, make a local copy and doctor it */ + const char *new_name = name; + if (XOF_ISSET(xop, XOF_UNDERSCORES)) { + size_t len = strlen(name); + const char *old_name = name; + char *buf, *cp, *ep; + + buf = alloca(len + 1); + for (cp = buf, ep = buf + len + 1; cp < ep; cp++, old_name++) + *cp = (*old_name == '-') ? '_' : *old_name; + new_name = buf; + } + rc = xo_printf(xop, "%s%*s\"%s\": [%s", - pre_nl, xo_indent(xop), "", name, ppn); + pre_nl, xo_indent(xop), "", new_name, ppn); break; case XO_STYLE_ENCODER: @@ -7622,7 +7637,7 @@ xo_do_close (xo_handle_t *xop, const char *name, xo_state_t new_state) if (xsp->xs_state != need_state) continue; - if (name && xsp->xs_name && strcmp(name, xsp->xs_name) != 0) + if (name && xsp->xs_name && !xo_streq(name, xsp->xs_name)) continue; limit = xsp; @@ -7680,13 +7695,6 @@ xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name, break; case XSS_TRANSITION(XSS_OPEN_LIST, XSS_OPEN_CONTAINER): - if (on_marker) - goto marker_prevents_close; - rc = xo_do_close_list(xop, NULL); - if (rc >= 0) - goto open_container; - break; - case XSS_TRANSITION(XSS_OPEN_LEAF_LIST, XSS_OPEN_CONTAINER): if (on_marker) goto marker_prevents_close; @@ -7695,18 +7703,13 @@ xo_transition (xo_handle_t *xop, xo_xof_flags_t flags, const char *name, goto open_container; break; - /*close_container:*/ - case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER): - if (on_marker) - goto marker_prevents_close; - rc = xo_do_close(xop, name, new_state); - break; - case XSS_TRANSITION(XSS_INIT, XSS_CLOSE_CONTAINER): /* This is an exception for "xo --close" */ rc = xo_do_close_container(xop, name); break; + /*close_container:*/ + case XSS_TRANSITION(XSS_OPEN_CONTAINER, XSS_CLOSE_CONTAINER): case XSS_TRANSITION(XSS_OPEN_LIST, XSS_CLOSE_CONTAINER): case XSS_TRANSITION(XSS_OPEN_INSTANCE, XSS_CLOSE_CONTAINER): if (on_marker) @@ -8049,7 +8052,7 @@ xo_finish_atexit (void) * Generate an error message, such as would be displayed on stderr */ void -xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) +xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap) { xop = xo_default(xop); @@ -8057,13 +8060,15 @@ xo_error_hv (xo_handle_t *xop, const char *fmt, va_list vap) * If the format string doesn't end with a newline, we pop * one on ourselves. */ - ssize_t len = strlen(fmt); - if (len > 0 && fmt[len - 1] != '\n') { - char *newfmt = alloca(len + 2); - memcpy(newfmt, fmt, len); - newfmt[len] = '\n'; - newfmt[len] = '\0'; - fmt = newfmt; + if (need_newline) { + ssize_t len = strlen(fmt); + if (len > 0 && fmt[len - 1] != '\n') { + char *newfmt = alloca(len + 2); + memcpy(newfmt, fmt, len); + newfmt[len] = '\n'; + newfmt[len + 1] = '\0'; + fmt = newfmt; + } } switch (xo_style(xop)) { @@ -8111,7 +8116,7 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_error_hv(xop, fmt, vap); + xo_errorn_hv(xop, 0, fmt, vap); va_end(vap); } @@ -8124,7 +8129,30 @@ xo_error (const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_error_hv(NULL, fmt, vap); + xo_errorn_hv(NULL, 0, fmt, vap); + va_end(vap); +} + +void +xo_errorn_h (xo_handle_t *xop, const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_errorn_hv(xop, 1, fmt, vap); + va_end(vap); +} + +/* + * Generate an error message, such as would be displayed on stderr + */ +void +xo_errorn (const char *fmt, ...) +{ + va_list vap; + + va_start(vap, fmt); + xo_errorn_hv(NULL, 1, fmt, vap); va_end(vap); } @@ -8141,11 +8169,31 @@ xo_parse_args (int argc, char **argv) char *cp; int i, save; - /* Save our program name for xo_err and friends */ - xo_program = argv[0]; - cp = strrchr(xo_program, '/'); - if (cp) - xo_program = cp + 1; + /* + * If xo_set_program has always been called, we honor that value + */ + if (xo_program == NULL) { + /* Save our program name for xo_err and friends */ + xo_program = argv[0]; + cp = strrchr(xo_program, '/'); + if (cp) + xo_program = ++cp; + else + cp = argv[0]; /* Reset to front of string */ + + /* + * GNU libtool add an annoying ".test" as the program + * extension; we remove it. libtool also adds a "lt-" prefix + * that we cannot remove. + */ + size_t len = strlen(xo_program); + static const char gnu_ext[] = ".test"; + if (len >= sizeof(gnu_ext)) { + cp += len + 1 - sizeof(gnu_ext); + if (xo_streq(cp, gnu_ext)) + *cp = '\0'; + } + } xo_handle_t *xop = xo_default(NULL); @@ -8178,7 +8226,7 @@ xo_parse_args (int argc, char **argv) } else if (*cp == '-') { cp += 1; - if (strcmp(cp, "check") == 0) { + if (xo_streq(cp, "check")) { exit(XO_HAS_LIBXO); } else { @@ -8386,9 +8434,8 @@ xo_emit_err (int eval, const char *fmt, ...) int code = errno; va_list vap; va_start(vap, fmt); - xo_emit_err_v(0, code, fmt, vap); - va_end(vap); - exit(eval); + xo_emit_err_v(eval, code, fmt, vap); + /*NOTREACHED*/ } void @@ -8397,10 +8444,8 @@ xo_emit_errx (int eval, const char *fmt, ...) va_list vap; va_start(vap, fmt); - xo_emit_err_v(0, -1, fmt, vap); - va_end(vap); - xo_finish(); - exit(eval); + xo_emit_err_v(eval, -1, fmt, vap); /* This will exit */ + /*NOTREACHED*/ } void @@ -8409,10 +8454,8 @@ xo_emit_errc (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); - xo_finish(); - exit(eval); + xo_emit_err_v(eval, code, fmt, vap); /* This will exit */ + /*NOTREACHED*/ } /* diff --git a/contrib/libxo/libxo/xo.h b/contrib/libxo/libxo/xo.h index 8404c6cb93a..6a61a16c7ca 100644 --- a/contrib/libxo/libxo/xo.h +++ b/contrib/libxo/libxo/xo.h @@ -389,6 +389,15 @@ xo_error_h (xo_handle_t *xop, const char *fmt, ...); void xo_error (const char *fmt, ...); +void +xo_errorn_hv (xo_handle_t *xop, int need_newline, const char *fmt, va_list vap); + +void +xo_errorn_h (xo_handle_t *xop, const char *fmt, ...); + +void +xo_errorn (const char *fmt, ...); + xo_ssize_t xo_flush_h (xo_handle_t *xop); diff --git a/contrib/libxo/libxo/xo_buf.h b/contrib/libxo/libxo/xo_buf.h index e9468901c07..c97f722959c 100644 --- a/contrib/libxo/libxo/xo_buf.h +++ b/contrib/libxo/libxo/xo_buf.h @@ -72,14 +72,14 @@ xo_buf_is_empty (xo_buffer_t *xbp) /* * Return the current offset */ -static inline unsigned +static inline ssize_t 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) +xo_buf_data (xo_buffer_t *xbp, ssize_t offset) { if (xbp == NULL) return NULL; diff --git a/contrib/libxo/libxo/xo_create.3 b/contrib/libxo/libxo/xo_create.3 index 03d51764b8a..ea811c27e5c 100644 --- a/contrib/libxo/libxo/xo_create.3 +++ b/contrib/libxo/libxo/xo_create.3 @@ -33,7 +33,7 @@ function. Example: xo_handle_t *xop = xo_create(XO_STYLE_JSON, XOF_WARN); .... - xo_emit_h(xop, "testing\n"); + xo_emit_h(xop, "testing\\n"); .Ed .Pp By default, diff --git a/contrib/libxo/libxo/xo_emit.3 b/contrib/libxo/libxo/xo_emit.3 index 9e3ec85b676..cbf9d2b11eb 100644 --- a/contrib/libxo/libxo/xo_emit.3 +++ b/contrib/libxo/libxo/xo_emit.3 @@ -48,7 +48,7 @@ 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", + "{:characters/%7ju} {d:filename/%s}\\n", linect, wordct, charct, file); .Ed Output can then be generated in various style, using @@ -100,6 +100,8 @@ 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_emit_f 3 , +.Xo xo_emit_field 3 , .Xr xo_format 5 , .Xr libxo 3 .Sh HISTORY diff --git a/contrib/libxo/libxo/xo_emit_f.3 b/contrib/libxo/libxo/xo_emit_f.3 index 7c340175aef..f8ac013256a 100644 --- a/contrib/libxo/libxo/xo_emit_f.3 +++ b/contrib/libxo/libxo/xo_emit_f.3 @@ -84,14 +84,14 @@ clear this information; they are not generally needed. .Bd -literal -offset indent for (i = 0; i < 1000; i++) { xo_open_instance("item"); - xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\n", + xo_emit_f(XOEF_RETAIN, "{:name} {:count/%d}\\n", name[i], count[i]); } .Ed .Pp In this example, the caller desires to clear the retained information. .Bd -literal -offset indent - const char *fmt = "{:name} {:count/%d}\n"; + const char *fmt = "{:name} {:count/%d}\\n"; for (i = 0; i < 1000; i++) { xo_open_instance("item"); xo_emit_f(XOEF_RETAIN, fmt, name[i], count[i]); diff --git a/contrib/libxo/libxo/xo_emit_field.3 b/contrib/libxo/libxo/xo_emit_field.3 new file mode 100644 index 00000000000..4f9636cee8e --- /dev/null +++ b/contrib/libxo/libxo/xo_emit_field.3 @@ -0,0 +1,113 @@ +.\" # +.\" # Copyright (c) 2021, Juniper Networks, Inc. +.\" # All rights reserved. +.\" # This SOFTWARE is licensed under the LICENSE provided in the +.\" # ../Copyright file. By downloading, installing, copying, or +.\" # using the SOFTWARE, you agree to be bound by the terms of that +.\" # LICENSE. +.\" # Phil Shafer, July 2014 +.\" +.Dd December 4, 2014 +.Dt LIBXO 3 +.Os +.Sh NAME +.Nm xo_emit_field +.Nd emit formatted output based on format string and arguments +.Sh LIBRARY +.Lb libxo +.Sh SYNOPSIS +.In libxo/xo.h +.Ft xo_ssize_t +.Fn xo_emit_field "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "..." +.Ft xo_ssize_t +.Fn xo_emit_field_h "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" const char *efmt" "..." +.Ft xo_ssize_t +.Fn xo_emit_field_hv "xo_handle_t *xop" "const char *rolmod" "const char *content" "const char *fmt" "const char *efmt" "va_list vap" +.Sh DESCRIPTION +The +.Fn xo_emit_field +function emits formatted output similar to +.Xr xo_emit 3 +but where +.Fn xo_emit +uses a single string argument containing the description +for multiple fields, +.Fn xo_emit_field +emits a single field using multiple arguments to contain the +field description. +.Fn xo_emit_field_h +adds an explicit handle to use instead of the default +handle, while +.Fn xo_emit_field_hv +accepts a +.Fa va_list +for additional flexibility. +.Pp +The arguments +.Fa rolmod , +.Fa content , +.Fa fmt , +and +.Fa efmt +are detailed in +.Xr xo_format 5 . +Using distinct arguments allows callers to pass the field description +in pieces, rather than having to use something like +.Xr snprintf 3 +to build the format string required by +.Fn xo_emit . +The arguments are each NUL-terminated strings. The +.Fa rolmod +argument contains the "role" and "modifier" portions of +the field description, the +.Fa content +argument contains the "content" portion, and the +.Fa fmt +and +.Fa efmt +contain the "field-format" and "encoding-format" portions, respectively. +.Pp +As with xo_emit, the +.Fa fmt +and +.Fa efmt +values are both optional, since the field-format string +defaults to "%s", and the encoding-format's default value is +derived from the field-format +per +.Xr xo_format 5 . +However, care must be taken to avoid using a value directly as the +format, since characters like '{', '%', and '}' will be interpreted +as formatting directives, and may cause +.Nm +to dereference arbitrary values off the stack, leading to bugs, +core files, and gnashing of teeth. +.Sh EXAMPLES +In this example, a set of four values is emitted using the following +source code: +.Bd -literal -offset indent + xo_emit_field("T", title, NULL, NULL, NULL); + xo_emit_field("Vt", "max-chaos", NULL, NULL, " very "); + xo_emit_field("V", "min-chaos", "%02d", "%d", 42); + xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u", + "gum", 1412); +.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_format 5 , +.Xr libxo 3 +.Sh HISTORY +The +.Nm libxo +library first appeared in +.Fx 11.0 . +.Sh AUTHORS +.Nm libxo +was written by +.An Phil Shafer Aq Mt phil@freebsd.org . diff --git a/contrib/libxo/libxo/xo_encoder.c b/contrib/libxo/libxo/xo_encoder.c index a073e698b40..5d195e06a2a 100644 --- a/contrib/libxo/libxo/xo_encoder.c +++ b/contrib/libxo/libxo/xo_encoder.c @@ -199,13 +199,40 @@ xo_encoder_find (const char *name) xo_encoder_list_init(&xo_encoders); XO_ENCODER_LIST_FOREACH(xep, &xo_encoders) { - if (strcmp(xep->xe_name, name) == 0) + if (xo_streq(xep->xe_name, name)) return xep; } return NULL; } +/* + * Return the encoder function for a specific shared library. This is + * really just a means of keeping the annoying gcc verbiage out of the + * main code. And that's only need because gcc breaks dlfunc's + * promise that I can cast it's return value to a function: "The + * precise return type of dlfunc() is unspecified; applications must + * cast it to an appropriate function pointer type." + */ +static xo_encoder_init_func_t +xo_encoder_func (void *dlp) +{ + xo_encoder_init_func_t func; + +#if defined(HAVE_GCC) && __GNUC__ > 8 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcast-function-type" +#endif /* HAVE_GCC */ + + func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME); + +#if defined(HAVE_GCC) && __GNUC__ > 8 +#pragma GCC diagnostic pop /* Restore previous setting */ +#endif /* HAVE_GCC */ + + return func; +} + static xo_encoder_node_t * xo_encoder_discover (const char *name) { @@ -234,7 +261,7 @@ xo_encoder_discover (const char *name) */ xo_encoder_init_func_t func; - func = (xo_encoder_init_func_t) dlfunc(dlp, XO_ENCODER_INIT_NAME); + func = xo_encoder_func(dlp); if (func) { xo_encoder_init_args_t xei; @@ -290,9 +317,39 @@ xo_encoder_init (xo_handle_t *xop, const char *name) { xo_encoder_setup(); + char opts_char = '\0'; + const char *col_opts = strchr(name, ':'); + const char *plus_opts = strchr(name, '+'); + + /* + * Find the option-separating character (plus or colon) which + * appears first in the options string. + */ + const char *opts = (col_opts == NULL) ? plus_opts + : (plus_opts == NULL) ? col_opts + : (plus_opts < col_opts) ? plus_opts : col_opts; + + if (opts) { + opts_char = *opts; + + /* Make a writable copy of the name */ + size_t len = strlen(name); + char *copy = alloca(len + 1); + memcpy(copy, name, len); + copy[len] = '\0'; + + char *opts_copy = copy + (opts - name); /* Move to ':' */ + *opts_copy++ = '\0'; /* Trim it off */ + + opts = opts_copy; /* Use copy as options */ + name = copy; /* Use trimmed copy as name */ + } + /* Can't have names containing '/' or ':' */ - if (strchr(name, '/') != NULL || strchr(name, ':') != NULL) + if (strchr(name, '/') != NULL || strchr(name, ':') != NULL) { + xo_failure(xop, "invalid encoder name: %s", name); return -1; + } /* * First we look on the list of known (registered) encoders. @@ -302,13 +359,24 @@ xo_encoder_init (xo_handle_t *xop, const char *name) xo_encoder_node_t *xep = xo_encoder_find(name); if (xep == NULL) { xep = xo_encoder_discover(name); - if (xep == NULL) + if (xep == NULL) { + xo_failure(xop, "encoder not founde: %s", name); return -1; + } } xo_set_encoder(xop, xep->xe_handler); - return xo_encoder_handle(xop, XO_OP_CREATE, NULL, NULL, 0); + int rc = xo_encoder_handle(xop, XO_OP_CREATE, name, NULL, 0); + if (rc == 0 && opts != NULL) { + xo_encoder_op_t op; + + /* Encoder API is limited, so we're stuck with two different options */ + op = (opts_char == '+') ? XO_OP_OPTIONS_PLUS : XO_OP_OPTIONS; + rc = xo_encoder_handle(xop, op, name, opts, 0); + } + + return rc; } /* @@ -334,7 +402,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags) int xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op, - const char *name, const char *value, xo_xof_flags_t flags) + const char *name, const char *value, xo_xff_flags_t flags) { void *private = xo_get_private(xop); xo_encoder_func_t func = xo_get_encoder(xop); @@ -366,6 +434,7 @@ xo_encoder_op_name (xo_encoder_op_t op) /* 14 */ "destroy", /* 15 */ "attr", /* 16 */ "version", + /* 17 */ "options", }; if (op > sizeof(names) / sizeof(names[0])) diff --git a/contrib/libxo/libxo/xo_encoder.h b/contrib/libxo/libxo/xo_encoder.h index 0e20e72ac88..099248ae13a 100644 --- a/contrib/libxo/libxo/xo_encoder.h +++ b/contrib/libxo/libxo/xo_encoder.h @@ -18,12 +18,57 @@ #ifndef XO_ENCODER_H #define XO_ENCODER_H +#include + /* * Expose libxo's memory allocation functions */ extern xo_realloc_func_t xo_realloc; extern xo_free_func_t xo_free; +/* + * Simple string comparison function (without the temptation + * to forget the "== 0"). + */ +static inline int +xo_streq (const char *one, const char *two) +{ + return strcmp(one, two) == 0; +} + +/* Flags for formatting functions */ +typedef unsigned long xo_xff_flags_t; +#define XFF_COLON (1<<0) /* Append a ":" */ +#define XFF_COMMA (1<<1) /* Append a "," iff there's more output */ +#define XFF_WS (1<<2) /* Append a blank */ +#define XFF_ENCODE_ONLY (1<<3) /* Only emit for encoding styles (XML, JSON) */ + +#define XFF_QUOTE (1<<4) /* Force quotes */ +#define XFF_NOQUOTE (1<<5) /* Force no quotes */ +#define XFF_DISPLAY_ONLY (1<<6) /* Only emit for display styles (text, html) */ +#define XFF_KEY (1<<7) /* Field is a key (for XPath) */ + +#define XFF_XML (1<<8) /* Force XML encoding style (for XPath) */ +#define XFF_ATTR (1<<9) /* Escape value using attribute rules (XML) */ +#define XFF_BLANK_LINE (1<<10) /* Emit a blank line */ +#define XFF_NO_OUTPUT (1<<11) /* Do not make any output */ + +#define XFF_TRIM_WS (1<<12) /* Trim whitespace off encoded values */ +#define XFF_LEAF_LIST (1<<13) /* A leaf-list (list of values) */ +#define XFF_UNESCAPE (1<<14) /* Need to printf-style unescape the value */ +#define XFF_HUMANIZE (1<<15) /* Humanize the value (for display styles) */ + +#define XFF_HN_SPACE (1<<16) /* Humanize: put space before suffix */ +#define XFF_HN_DECIMAL (1<<17) /* Humanize: add one decimal place if <10 */ +#define XFF_HN_1000 (1<<18) /* Humanize: use 1000, not 1024 */ +#define XFF_GT_FIELD (1<<19) /* Call gettext() on a field */ + +#define XFF_GT_PLURAL (1<<20) /* Call dngettext to find plural form */ +#define XFF_ARGUMENT (1<<21) /* Content provided via argument */ + +/* Flags to turn off when we don't want i18n processing */ +#define XFF_GT_FLAGS (XFF_GT_FIELD | XFF_GT_PLURAL) + typedef unsigned xo_encoder_op_t; /* Encoder operations; names are in xo_encoder.c:xo_encoder_op_name() */ @@ -44,6 +89,8 @@ typedef unsigned xo_encoder_op_t; #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_OP_OPTIONS 17 /* Additional command line options */ +#define XO_OP_OPTIONS_PLUS 18 /* Additional command line options */ #define XO_ENCODER_HANDLER_ARGS \ xo_handle_t *xop __attribute__ ((__unused__)), \ @@ -51,7 +98,7 @@ typedef unsigned xo_encoder_op_t; const char *name __attribute__ ((__unused__)), \ const char *value __attribute__ ((__unused__)), \ void *private __attribute__ ((__unused__)), \ - xo_xof_flags_t flags __attribute__ ((__unused__)) + xo_xff_flags_t flags __attribute__ ((__unused__)) typedef int (*xo_encoder_func_t)(XO_ENCODER_HANDLER_ARGS); @@ -106,7 +153,7 @@ xo_encoder_create (const char *name, xo_xof_flags_t flags); int xo_encoder_handle (xo_handle_t *xop, xo_encoder_op_t op, - const char *name, const char *value, xo_xof_flags_t flags); + const char *name, const char *value, xo_xff_flags_t flags); void xo_encoders_clean (void); @@ -114,4 +161,10 @@ xo_encoders_clean (void); const char * xo_encoder_op_name (xo_encoder_op_t op); +/* + * xo_failure is used to announce internal failures, when "warn" is on + */ +void +xo_failure (xo_handle_t *xop, const char *fmt, ...); + #endif /* XO_ENCODER_H */ diff --git a/contrib/libxo/libxo/xo_format.5 b/contrib/libxo/libxo/xo_format.5 index 5265359866b..3c7ddc9dd1a 100644 --- a/contrib/libxo/libxo/xo_format.5 +++ b/contrib/libxo/libxo/xo_format.5 @@ -242,6 +242,13 @@ Labels are text that appears before a value. .Bd -literal -offset indent xo_emit("{Lwc:Cost}{:cost/%u}\\n", cost); .Ed +.Pp +If a label needs to include a slash, it must be escaped using two +backslashes, one for the C compiler and one for +.Nm libxo . +.Bd -literal -offset indent + xo_emit("{Lc:Low\\\\/warn level}{:level/%s}\\n", level); +.Ed .Ss "The Note Role ({N:})" Notes are text that appears after a value. .Bd -literal -offset indent diff --git a/contrib/libxo/libxo/xo_open_container.3 b/contrib/libxo/libxo/xo_open_container.3 index 7037974d2c4..303f3f06fd0 100644 --- a/contrib/libxo/libxo/xo_open_container.3 +++ b/contrib/libxo/libxo/xo_open_container.3 @@ -141,7 +141,7 @@ flag is set. .Bd -literal -offset indent -compact EXAMPLE: xo_open_container("system"); - xo_emit("The host name is {:host-name}\n", hn); + xo_emit("The host name is {:host-name}\\n", hn); xo_close_container("system"); XML: foo diff --git a/contrib/libxo/libxo/xo_open_list.3 b/contrib/libxo/libxo/xo_open_list.3 index f28c9b63ac3..e61e15939c8 100644 --- a/contrib/libxo/libxo/xo_open_list.3 +++ b/contrib/libxo/libxo/xo_open_list.3 @@ -77,7 +77,7 @@ close each instance of the list: for (ip = list; ip->i_title; ip++) { xo_open_instance("item"); - xo_emit("{L:Item} '{:name/%s}':\n", ip->i_title); + xo_emit("{L:Item} '{:name/%s}':\\n", ip->i_title); xo_close_instance("item"); } @@ -91,7 +91,7 @@ generation of XML and JSON data. 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", + 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"); @@ -138,7 +138,7 @@ To emit a leaf list, call the 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); + xo_emit("{Lwc:Item}{l:item}\\n", ip->i_title); } .Ed .Pp diff --git a/contrib/libxo/libxo/xo_parse_args.3 b/contrib/libxo/libxo/xo_parse_args.3 index b014e608a0d..e631af639e0 100644 --- a/contrib/libxo/libxo/xo_parse_args.3 +++ b/contrib/libxo/libxo/xo_parse_args.3 @@ -7,7 +7,7 @@ .\" # LICENSE. .\" # Phil Shafer, July 2014 .\" -.Dd December 4, 2014 +.Dd November 17, 2020 .Dt LIBXO 3 .Os .Sh NAME @@ -24,7 +24,9 @@ .Sh DESCRIPTION The .Fn xo_parse_args -function is used to process command-line arguments. +function is used to process command-line arguments, which are +described in +.Xr xo_options 7 . .Nm libxo specific options are processed and removed @@ -42,91 +44,6 @@ 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 -.It -\-\^\-libxo= -.It -\-\^\-libxo: -.El -.Pp -Options is a comma-separated list of tokens that correspond to output -styles, flags, or features: -.Pp -.Bl -tag -width "12345678" -.It Sy "Token Action" -.It Dv dtrt -Enable "Do The Right Thing" mode -.It Dv html -Emit HTML output -.It Dv indent=xx -Set the indentation level -.It Dv info -Add info attributes (HTML) -.It Dv json -Emit JSON output -.It Dv keys -Emit the key attribute for keys (XML) -.It Dv log-gettext -Log (via stderr) each -.Xr gettext 3 -string lookup -.It Dv log-syslog -Log (via stderr) each syslog message (via -.Xr xo_syslog 3 ) -.If Dv no-humanize -Ignore the {h:} modifier (TEXT, HTML) -.It Dv no-locale -Do not initialize the locale setting -.It Dv no-retain -Prevent retaining formatting information -.It Dv no-top -Do not emit a top set of braces (JSON) -.It Dv not-first -Pretend the 1st output item was not 1st (JSON) -.It Dv pretty -Emit pretty-printed output -.It Dv retain -Force retaining formatting information -.It Dv text -Emit TEXT output -.If Dv underscores -Replace XML-friendly "-"s with JSON friendly "_"s e -.It Dv units -Add the 'units' (XML) or 'data-units (HTML) attribute -.It Dv warn -Emit warnings when libxo detects bad calls -.It Dv warn-xml -Emit warnings in XML -.It Dv xml -Emit XML output -.It Dv xpath -Add XPath expressions (HTML) -.El -.Pp -The -.Dq brief-options -are single letter commands, designed for those with -too little patience to use real tokens. -No comma separator is used. -.Bl -column "i" -.It Sy "Token Action" -.It "H " "Enable HTML output (XO_STYLE_HTML)" -.It "I " "Enable info output (XOF_INFO)" -.It "i " "Indent by " -.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 @@ -149,6 +66,7 @@ must be maintained by the caller. .Pp .Sh SEE ALSO .Xr xo_emit 3 , +.Xr xo_options 7, .Xr libxo 3 .Sh HISTORY The diff --git a/contrib/libxo/tests/core/Makefile.am b/contrib/libxo/tests/core/Makefile.am index 7f19472b597..1e701071175 100644 --- a/contrib/libxo/tests/core/Makefile.am +++ b/contrib/libxo/tests/core/Makefile.am @@ -51,24 +51,32 @@ 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=.E.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.E.out}} \ ${addprefix saved/, ${TEST_CASES:.c=.H.err}} \ ${addprefix saved/, ${TEST_CASES:.c=.H.out}} \ ${addprefix saved/, ${TEST_CASES:.c=.HIPx.err}} \ ${addprefix saved/, ${TEST_CASES:.c=.HIPx.out}} \ - ${addprefix saved/, ${TEST_CASES:.c=.E.err}} \ - ${addprefix saved/, ${TEST_CASES:.c=.E.out}} + ${addprefix saved/, ${TEST_CASES:.c=.HP.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.HP.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.J.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.J.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.JP.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.JP.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.JPu.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.JPu.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.T.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.T.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.X.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.X.out}} \ + ${addprefix saved/, ${TEST_CASES:.c=.XP.err}} \ + ${addprefix saved/, ${TEST_CASES:.c=.XP.out}} \ + ${addprefix saved/, test_01.Ecsv1.out} \ + ${addprefix saved/, test_01.Ecsv1.err} \ + ${addprefix saved/, test_01.Ecsv2.out} \ + ${addprefix saved/, test_01.Ecsv2.err} \ + ${addprefix saved/, test_01.Ecsv3.out} \ + ${addprefix saved/, test_01.Ecsv3.err} S2O = | ${SED} '1,/@@/d' @@ -86,7 +94,12 @@ TEST_JIG = \ ${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.out out/$$base.$$fmt.out ${S2O} ; \ ${DIFF} -Nu ${srcdir}/saved/$$base.$$fmt.err out/$$base.$$fmt.err ${S2O} -TEST_FORMATS = T XP JP HP X J H HIPx +TEST_JIG2 = \ +echo "... $$test ... $$fmt ..."; \ +xoopts==warn,$$csv ; \ +${TEST_JIG}; true; + +TEST_FORMATS = T XP JP JPu HP X J H HIPx test tests: ${bin_PROGRAMS} @${MKDIR} -p out @@ -105,6 +118,15 @@ test tests: ${bin_PROGRAMS} true; \ done) \ done) + -@ (${TEST_TRACE} test=test_01.c; base=test_01; \ + ( fmt=Ecsv1; csv=encoder=csv ; \ + ${TEST_JIG2} ); \ + ( fmt=Ecsv2; csv=encoder=csv:path=top-level/data/item:no-header ; \ + ${TEST_JIG2} ); \ + ( fmt=Ecsv3; csv=@csv:path=item:leafs=sku.sold:no-quotes ; \ + ${TEST_JIG2} ); \ + ) + one: -@(test=${TEST_CASE}; data=${TEST_DATA}; ${TEST_ONE} ; true) @@ -112,12 +134,17 @@ one: accept: -@(for test in ${TEST_CASES} ; do \ base=`${BASENAME} $$test .c` ; \ - (for fmt in ${TEST_FORMATS} E; do \ + (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) + -@(test=test_01.c; base=test_01; for fmt in Ecsv1 Ecsv2 Ecsv3 ; 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) .c.test: $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -o $@ $< diff --git a/contrib/libxo/tests/core/saved/test_01.E.out b/contrib/libxo/tests/core/saved/test_01.E.out index 9eefca9e08d..506bfa83526 100644 --- a/contrib/libxo/tests/core/saved/test_01.E.out +++ b/contrib/libxo/tests/core/saved/test_01.E.out @@ -1,5 +1,5 @@ -op create: [] [] [0] -op open_container: [top] [] [0x810] +op create: [test] [] [0] +op open_container: [top-level] [] [0x810] op string: [type] [ethernet] [0] op content: [type] [bridge] [0] op content: [type] [18u] [0] @@ -21,6 +21,10 @@ op string: [label] [value] [0x200000] op string: [max-chaos] [very] [0x1000] op content: [min-chaos] [42] [0] op string: [some-chaos] [[42]] [0] +op attr: [test-attr] [attr-value] [0] +op open_leaf_list: [sku] [] [0] +op string: [sku] [gum-000-1412] [0x2010] +op close_leaf_list: [sku] [] [0] op string: [host] [my-box] [0] op string: [domain] [example.com] [0] op attr: [test] [value] [0] @@ -133,6 +137,55 @@ op attr: [test4] [value4] [0] op string: [item] [water] [0x2000] op close_list: [item] [] [0] op close_container: [data4] [] [0] +op attr: [test] [value] [0] +op open_container: [data] [] [0x810] +op open_list: [item] [] [0] +op attr: [test2] [value2] [0] +op open_instance: [item] [] [0x810] +op attr: [test3] [value3] [0] +op string: [sku] [GRO-000-415] [0x98] +op string: [name] [gum] [0x80] +op content: [sold] [1412] [0x20] +op content: [on-order] [10] [0] +op content: [in-stock] [54] [0] +op close_instance: [item] [] [0] +op open_instance: [item] [] [0x810] +op attr: [test3] [value3] [0] +op string: [sku] [HRD-000-212] [0x98] +op string: [name] [rope] [0x80] +op content: [sold] [85] [0x20] +op string: [extra] [special] [0] +op content: [on-order] [2] [0] +op content: [in-stock] [4] [0] +op close_instance: [item] [] [0] +op open_instance: [item] [] [0x810] +op attr: [test3] [value3] [0] +op string: [sku] [HRD-000-517] [0x98] +op string: [name] [ladder] [0x80] +op content: [sold] [0] [0x20] +op string: [extra] [special] [0] +op content: [on-order] [1] [0] +op content: [in-stock] [2] [0] +op close_instance: [item] [] [0] +op open_instance: [item] [] [0x810] +op attr: [test3] [value3] [0] +op string: [sku] [HRD-000-632] [0x98] +op string: [name] [bolt] [0x80] +op content: [sold] [4123] [0x20] +op content: [on-order] [42] [0] +op content: [in-stock] [144] [0] +op close_instance: [item] [] [0] +op open_instance: [item] [] [0x810] +op attr: [test3] [value3] [0] +op string: [sku] [GRO-000-2331] [0x98] +op string: [name] [water] [0x80] +op content: [sold] [17] [0x20] +op string: [extra] [special] [0] +op content: [on-order] [2] [0] +op content: [in-stock] [14] [0] +op close_instance: [item] [] [0] +op close_list: [item] [] [0] +op close_container: [data] [] [0] op content: [cost] [425] [0] op content: [cost] [455] [0] op string: [mode] [mode] [0x8] @@ -148,6 +201,6 @@ op content: [mode_octal] [640] [0x8] op content: [links] [1] [0x1000] op string: [user] [user] [0x1000] op string: [group] [group] [0x1000] -op close_container: [top] [] [0] +op close_container: [top-level] [] [0] op finish: [] [] [0] op flush: [] [] [0] diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv1.err b/contrib/libxo/tests/core/saved/test_01.Ecsv1.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv1.out b/contrib/libxo/tests/core/saved/test_01.Ecsv1.out new file mode 100644 index 00000000000..aa1d9db49f3 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_01.Ecsv1.out @@ -0,0 +1,17 @@ +sku,name,sold,in-stock,on-order +GRO-000-415,gum,1412,54,10 +HRD-000-212,rope,85,4,2 +HRD-000-517,ladder,0,2,1 +HRD-000-632,bolt,4123,144,42 +GRO-000-2331,water,17,14,2 +GRO-000-415,gum,1412.0,54,10 +HRD-000-212,rope,85.0,4,2 +HRD-000-517,ladder,0,2,1 +HRD-000-632,bolt,4123.0,144,42 +GRO-000-2331,water,17.0,14,2 +GRO-000-533,fish,1321.0,45,1 +GRO-000-415,gum,1412,54,10 +HRD-000-212,rope,85,4,2 +HRD-000-517,ladder,0,2,1 +HRD-000-632,bolt,4123,144,42 +GRO-000-2331,water,17,14,2 diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv2.err b/contrib/libxo/tests/core/saved/test_01.Ecsv2.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv2.out b/contrib/libxo/tests/core/saved/test_01.Ecsv2.out new file mode 100644 index 00000000000..b39499961d6 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_01.Ecsv2.out @@ -0,0 +1,10 @@ +GRO-000-415,gum,1412,54,10 +HRD-000-212,rope,85,4,2 +HRD-000-517,ladder,0,2,1 +HRD-000-632,bolt,4123,144,42 +GRO-000-2331,water,17,14,2 +GRO-000-415,gum,1412,54,10 +HRD-000-212,rope,85,4,2 +HRD-000-517,ladder,0,2,1 +HRD-000-632,bolt,4123,144,42 +GRO-000-2331,water,17,14,2 diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv3.err b/contrib/libxo/tests/core/saved/test_01.Ecsv3.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_01.Ecsv3.out b/contrib/libxo/tests/core/saved/test_01.Ecsv3.out new file mode 100644 index 00000000000..6f1da35193b --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_01.Ecsv3.out @@ -0,0 +1,17 @@ +sku,sold +GRO-000-415,1412 +HRD-000-212,85 +HRD-000-517,0 +HRD-000-632,4123 +GRO-000-2331,17 +GRO-000-415,1412.0 +HRD-000-212,85.0 +HRD-000-517,0 +HRD-000-632,4123.0 +GRO-000-2331,17.0 +GRO-000-533,1321.0 +GRO-000-415,1412 +HRD-000-212,85 +HRD-000-517,0 +HRD-000-632,4123 +GRO-000-2331,17 diff --git a/contrib/libxo/tests/core/saved/test_01.H.out b/contrib/libxo/tests/core/saved/test_01.H.out index d25779f46da..b58816d8617 100644 --- a/contrib/libxo/tests/core/saved/test_01.H.out +++ b/contrib/libxo/tests/core/saved/test_01.H.out @@ -1,2 +1,3 @@ -
static
ethernet
bridge
18u
24
anchor
0x0
..
1
anchor
0x0
..
1
anchor
0x0
..
1
df
12
%
testing argument modifier
my-box
.
example.com
...
testing argument modifier with encoding to
.
example.com
...
Label text
value
very
42
42 -
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
X
X
X
X
X
X
X
X
X
X
Cost
:
425
X
X
Cost
:
455
links
user
group
3
this
/some/file
1
user
group
\ No newline at end of file +
static
ethernet
bridge
18u
24
anchor
0x0
..
1
anchor
0x0
..
1
anchor
0x0
..
1
df
12
%
testing argument modifier
my-box
.
example.com
...
testing argument modifier with encoding to
.
example.com
...
Label text
value
My Title +
very
42
42 +
gum-1412
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
Item
Total Sold
In Stock
On Order
SKU
gum
1412
10
54
GRO-000-415
rope
85
Extra:
special
2
4
HRD-000-212
ladder
0
Extra:
special
1
2
HRD-000-517
bolt
4123
42
144
HRD-000-632
water
17
Extra:
special
2
14
GRO-000-2331
X
X
X
X
X
X
X
X
X
X
Cost
:
425
X
X
Cost
:
455
links
user
group
3
this
/some/file
1
user
group
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_01.HIPx.out b/contrib/libxo/tests/core/saved/test_01.HIPx.out index 6eea24d95fa..da30b72ab7e 100644 --- a/contrib/libxo/tests/core/saved/test_01.HIPx.out +++ b/contrib/libxo/tests/core/saved/test_01.HIPx.out @@ -1,64 +1,67 @@
static
-
ethernet
+
ethernet
-
bridge
+
bridge
-
18u
+
18u
-
24
+
24
anchor
-
0x0
+
0x0
..
-
1
+
1
anchor
-
0x0
+
0x0
..
-
1
+
1
anchor
-
0x0
+
0x0
..
-
1
+
1
df
-
12
+
12
%
testing argument modifier
-
my-box
+
my-box
.
-
example.com
+
example.com
...
testing argument modifier with encoding to
.
-
example.com
+
example.com
...
Label text
-
value
+
value
-
very
-
42
-
42 +
My Title
+
very
+
42
+
42 +
+
gum-1412
Connecting to
-
my-box
+
my-box
.
-
example.com
+
example.com
...
@@ -69,39 +72,39 @@
SKU
-
gum
-
1412
-
54
-
10
-
GRO-000-415
+
gum
+
1412
+
54
+
10
+
GRO-000-415
-
rope
-
85
-
4
-
2
-
HRD-000-212
+
rope
+
85
+
4
+
2
+
HRD-000-212
-
ladder
-
0
-
2
-
1
-
HRD-000-517
+
ladder
+
0
+
2
+
1
+
HRD-000-517
-
bolt
-
4123
-
144
-
42
-
HRD-000-632
+
bolt
+
4123
+
144
+
42
+
HRD-000-632
-
water
-
17
-
14
-
2
-
GRO-000-2331
+
water
+
17
+
14
+
2
+
GRO-000-2331
@@ -110,224 +113,276 @@
Item
'
-
gum
+
gum
':
Total sold
:
-
1412.0
+
1412.0
In stock
:
-
54
+
54
On order
:
-
10
+
10
SKU
:
-
GRO-000-415
+
GRO-000-415
Item
'
-
rope
+
rope
':
Total sold
:
-
85.0
+
85.0
In stock
:
-
4
+
4
On order
:
-
2
+
2
SKU
:
-
HRD-000-212
+
HRD-000-212
Item
'
-
ladder
+
ladder
':
Total sold
:
-
0
+
0
In stock
:
-
2
+
2
On order
:
-
1
+
1
SKU
:
-
HRD-000-517
+
HRD-000-517
Item
'
-
bolt
+
bolt
':
Total sold
:
-
4123.0
+
4123.0
In stock
:
-
144
+
144
On order
:
-
42
+
42
SKU
:
-
HRD-000-632
+
HRD-000-632
Item
'
-
water
+
water
':
Total sold
:
-
17.0
+
17.0
In stock
:
-
14
+
14
On order
:
-
2
+
2
SKU
:
-
GRO-000-2331
+
GRO-000-2331
Item
'
-
fish
+
fish
':
Total sold
:
-
1321.0
+
1321.0
In stock
:
-
45
+
45
On order
:
-
1
+
1
SKU
:
-
GRO-000-533
+
GRO-000-533
Item
:
-
gum
+
gum
Item
:
-
rope
+
rope
Item
:
-
ladder
+
ladder
Item
:
-
bolt
+
bolt
Item
:
-
water
+
water
+
+
+
Item
+
Total Sold
+
In Stock
+
On Order
+
SKU
+
+
+
gum
+
1412
+
10
+
54
+
GRO-000-415
+
+
+
rope
+
85
+
Extra:
+
special
+
2
+
4
+
HRD-000-212
+
+
+
ladder
+
0
+
Extra:
+
special
+
1
+
2
+
HRD-000-517
+
+
+
bolt
+
4123
+
42
+
144
+
HRD-000-632
+
+
+
water
+
17
+
Extra:
+
special
+
2
+
14
+
GRO-000-2331
+
+
+
+
X
@@ -346,7 +401,7 @@
Cost
:
-
425
+
425
X
@@ -355,28 +410,28 @@
Cost
:
-
455
+
455
-
links
+
links
-
user
+
user
-
group
+
group
-
3
-
this
+
3
+
this
-
/some/file
+
/some/file
-
1
+
1
-
user
+
user
-
group
+
group
diff --git a/contrib/libxo/tests/core/saved/test_01.HP.out b/contrib/libxo/tests/core/saved/test_01.HP.out index 864c7b00248..5a7aed05ac0 100644 --- a/contrib/libxo/tests/core/saved/test_01.HP.out +++ b/contrib/libxo/tests/core/saved/test_01.HP.out @@ -51,10 +51,13 @@
value
+
My Title +
very
42
42
+
gum-1412
Connecting to
my-box
.
@@ -329,6 +332,58 @@
water
+
+
Item
+
Total Sold
+
In Stock
+
On Order
+
SKU
+
+
+
gum
+
1412
+
10
+
54
+
GRO-000-415
+
+
+
rope
+
85
+
Extra:
+
special
+
2
+
4
+
HRD-000-212
+
+
+
ladder
+
0
+
Extra:
+
special
+
1
+
2
+
HRD-000-517
+
+
+
bolt
+
4123
+
42
+
144
+
HRD-000-632
+
+
+
water
+
17
+
Extra:
+
special
+
2
+
14
+
GRO-000-2331
+
+
+
+
+
X
X
diff --git a/contrib/libxo/tests/core/saved/test_01.J.out b/contrib/libxo/tests/core/saved/test_01.J.out index 05cc739934e..b8c78267791 100644 --- a/contrib/libxo/tests/core/saved/test_01.J.out +++ b/contrib/libxo/tests/core/saved/test_01.J.out @@ -1 +1 @@ -{"top": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]","host":"my-box","domain":"example.com", "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17,"in-stock":14,"on-order":2}]}, "data2": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412.0,"in-stock":54,"on-order":10}, {"sku":"HRD-000-212","name":"rope","sold":85.0,"in-stock":4,"on-order":2}, {"sku":"HRD-000-517","name":"ladder","sold":0,"in-stock":2,"on-order":1}, {"sku":"HRD-000-632","name":"bolt","sold":4123.0,"in-stock":144,"on-order":42}, {"sku":"GRO-000-2331","name":"water","sold":17.0,"in-stock":14,"on-order":2}]}, "data3": {"item": [{"sku":"GRO-000-533","name":"fish","sold":1321.0,"in-stock":45,"on-order":1}]}, "data4": {"item": ["gum","rope","ladder","bolt","water"]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}} +{"top-level": {"type":"ethernet","type":"bridge","type":"18u","type":24,"address":"0x0","port":1,"address":"0x0","port":1,"address":"0x0","port":1,"used-percent":12,"kve_start":"0xdeadbeef","kve_end":"0xcabb1e","host":"my-box","domain":"example.com","host":"my-box","domain":"example.com","label":"value","max-chaos":"very","min-chaos":42,"some-chaos":"[42]", "sku": ["gum-000-1412"],"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"]}, "data": {"item": [{"sku":"GRO-000-415","name":"gum","sold":1412,"on-order":10,"in-stock":54}, {"sku":"HRD-000-212","name":"rope","sold":85,"extra":"special","on-order":2,"in-stock":4}, {"sku":"HRD-000-517","name":"ladder","sold":0,"extra":"special","on-order":1,"in-stock":2}, {"sku":"HRD-000-632","name":"bolt","sold":4123,"on-order":42,"in-stock":144}, {"sku":"GRO-000-2331","name":"water","sold":17,"extra":"special","on-order":2,"in-stock":14}]},"cost":425,"cost":455,"mode":"mode","mode_octal":"octal","links":"links","user":"user","group":"group","pre":"that","links":3,"post":"this","mode":"/some/file","mode_octal":640,"links":1,"user":"user","group":"group"}} diff --git a/contrib/libxo/tests/core/saved/test_01.JP.out b/contrib/libxo/tests/core/saved/test_01.JP.out index ff42544b53f..71a77cea81d 100644 --- a/contrib/libxo/tests/core/saved/test_01.JP.out +++ b/contrib/libxo/tests/core/saved/test_01.JP.out @@ -1,5 +1,5 @@ { - "top": { + "top-level": { "type": "ethernet", "type": "bridge", "type": "18u", @@ -21,6 +21,9 @@ "max-chaos": "very", "min-chaos": 42, "some-chaos": "[42]", + "sku": [ + "gum-000-1412" + ], "host": "my-box", "domain": "example.com", "data": { @@ -121,6 +124,48 @@ "water" ] }, + "data": { + "item": [ + { + "sku": "GRO-000-415", + "name": "gum", + "sold": 1412, + "on-order": 10, + "in-stock": 54 + }, + { + "sku": "HRD-000-212", + "name": "rope", + "sold": 85, + "extra": "special", + "on-order": 2, + "in-stock": 4 + }, + { + "sku": "HRD-000-517", + "name": "ladder", + "sold": 0, + "extra": "special", + "on-order": 1, + "in-stock": 2 + }, + { + "sku": "HRD-000-632", + "name": "bolt", + "sold": 4123, + "on-order": 42, + "in-stock": 144 + }, + { + "sku": "GRO-000-2331", + "name": "water", + "sold": 17, + "extra": "special", + "on-order": 2, + "in-stock": 14 + } + ] + }, "cost": 425, "cost": 455, "mode": "mode", diff --git a/contrib/libxo/tests/core/saved/test_01.JPu.err b/contrib/libxo/tests/core/saved/test_01.JPu.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_01.JPu.out b/contrib/libxo/tests/core/saved/test_01.JPu.out new file mode 100644 index 00000000000..747db16f07a --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_01.JPu.out @@ -0,0 +1,185 @@ +{ + "top_level": { + "type": "ethernet", + "type": "bridge", + "type": "18u", + "type": 24, + "address": "0x0", + "port": 1, + "address": "0x0", + "port": 1, + "address": "0x0", + "port": 1, + "used_percent": 12, + "kve_start": "0xdeadbeef", + "kve_end": "0xcabb1e", + "host": "my-box", + "domain": "example.com", + "host": "my-box", + "domain": "example.com", + "label": "value", + "max_chaos": "very", + "min_chaos": 42, + "some_chaos": "[42]", + "sku": [ + "gum-000-1412" + ], + "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" + ] + }, + "data": { + "item": [ + { + "sku": "GRO-000-415", + "name": "gum", + "sold": 1412, + "on_order": 10, + "in_stock": 54 + }, + { + "sku": "HRD-000-212", + "name": "rope", + "sold": 85, + "extra": "special", + "on_order": 2, + "in_stock": 4 + }, + { + "sku": "HRD-000-517", + "name": "ladder", + "sold": 0, + "extra": "special", + "on_order": 1, + "in_stock": 2 + }, + { + "sku": "HRD-000-632", + "name": "bolt", + "sold": 4123, + "on_order": 42, + "in_stock": 144 + }, + { + "sku": "GRO-000-2331", + "name": "water", + "sold": 17, + "extra": "special", + "on_order": 2, + "in_stock": 14 + } + ] + }, + "cost": 425, + "cost": 455, + "mode": "mode", + "mode_octal": "octal", + "links": "links", + "user": "user", + "group": "group", + "pre": "that", + "links": 3, + "post": "this", + "mode": "/some/file", + "mode_octal": 640, + "links": 1, + "user": "user", + "group": "group" + } +} diff --git a/contrib/libxo/tests/core/saved/test_01.T.out b/contrib/libxo/tests/core/saved/test_01.T.out index f41350980b9..89d3157336e 100644 --- a/contrib/libxo/tests/core/saved/test_01.T.out +++ b/contrib/libxo/tests/core/saved/test_01.T.out @@ -5,8 +5,9 @@ df 12% testing argument modifier my-box.example.com... testing argument modifier with encoding to .example.com... Label text value +My Title very 4242 -Connecting to my-box.example.com... +gum-1412Connecting 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 @@ -50,6 +51,14 @@ Item: rope Item: ladder Item: bolt Item: water +Item Total Sold In Stock On Order SKU +gum 1412 10 54 GRO-000-415 +rope 85Extra: special 2 4 HRD-000-212 +ladder 0Extra: special 1 2 HRD-000-517 +bolt 4123 42 144 HRD-000-632 +water 17Extra: special 2 14 GRO-000-2331 + + XXXXXXXX X XCost: 425 X XCost: 455 diff --git a/contrib/libxo/tests/core/saved/test_01.X.out b/contrib/libxo/tests/core/saved/test_01.X.out index 4bcf1c9f995..2f1fa826170 100644 --- a/contrib/libxo/tests/core/saved/test_01.X.out +++ b/contrib/libxo/tests/core/saved/test_01.X.out @@ -1 +1 @@ -ethernetbridge18u24
0x0
1
0x0
1
0x0
1120xdeadbeef0xcabb1emy-boxexample.commy-boxexample.comvery42[42]my-boxexample.comGRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451gumropeladderboltwater425455modeoctallinksusergroup
that
3this/some/file6401usergroup
\ No newline at end of file +ethernetbridge18u24
0x0
1
0x0
1
0x0
1120xdeadbeef0xcabb1emy-boxexample.commy-boxexample.comvery42[42]gum-000-1412my-boxexample.comGRO-000-415gum14125410HRD-000-212rope8542HRD-000-517ladder021HRD-000-632bolt412314442GRO-000-2331water17142GRO-000-415gum1412.05410HRD-000-212rope85.042HRD-000-517ladder021HRD-000-632bolt4123.014442GRO-000-2331water17.0142GRO-000-533fish1321.0451gumropeladderboltwaterGRO-000-415gum14121054HRD-000-212rope85special24HRD-000-517ladder0special12HRD-000-632bolt412342144GRO-000-2331water17special214425455modeoctallinksusergroup
that
3this/some/file6401usergroup
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_01.XP.out b/contrib/libxo/tests/core/saved/test_01.XP.out index 27ff1af2e9e..afa79ada5f8 100644 --- a/contrib/libxo/tests/core/saved/test_01.XP.out +++ b/contrib/libxo/tests/core/saved/test_01.XP.out @@ -1,4 +1,4 @@ - + ethernet bridge 18u @@ -20,6 +20,7 @@ very 42 [42] + gum-000-1412 my-box example.com @@ -112,6 +113,46 @@ bolt water + + + GRO-000-415 + gum + 1412 + 10 + 54 + + + HRD-000-212 + rope + 85 + special + 2 + 4 + + + HRD-000-517 + ladder + 0 + special + 1 + 2 + + + HRD-000-632 + bolt + 4123 + 42 + 144 + + + GRO-000-2331 + water + 17 + special + 2 + 14 + + 425 455 mode @@ -127,4 +168,4 @@ 1 user group - + diff --git a/contrib/libxo/tests/core/saved/test_02.E.err b/contrib/libxo/tests/core/saved/test_02.E.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.E.err +++ b/contrib/libxo/tests/core/saved/test_02.E.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.E.out b/contrib/libxo/tests/core/saved/test_02.E.out index 499b5abc710..7550b680d09 100644 --- a/contrib/libxo/tests/core/saved/test_02.E.out +++ b/contrib/libxo/tests/core/saved/test_02.E.out @@ -1,4 +1,4 @@ -op create: [] [] [0] +op create: [test] [] [0] op open_container: [top] [] [0x40010] op open_container: [data] [] [0x40010] op string: [name] [em0] [0x1080] @@ -23,6 +23,7 @@ op content: [bytes] [2] [0x2004] op content: [bytes] [3] [0x2004] op content: [bytes] [4] [0x2004] op close_leaf_list: [bytes] [] [0] +op content: [granularity-lw] [155] [0] op content: [mbuf-current] [10] [0] op content: [mbuf-cache] [20] [0] op content: [mbuf-total] [30] [0] diff --git a/contrib/libxo/tests/core/saved/test_02.H.err b/contrib/libxo/tests/core/saved/test_02.H.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.H.err +++ b/contrib/libxo/tests/core/saved/test_02.H.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.H.out b/contrib/libxo/tests/core/saved/test_02.H.out index 66a15850276..03daf89ff0d 100644 --- a/contrib/libxo/tests/core/saved/test_02.H.out +++ b/contrib/libxo/tests/core/saved/test_02.H.out @@ -2,6 +2,9 @@
abcdef: Bad file descriptor
improper use of profanity; ten yard penalty; first down
length
abcdef
close
-1
returned
Bad file descriptor
good
close
-1
returned
Bad fi
good
improper use of profanity; ten yard penalty; first down -
20
30
40
file
0
bytes
1
byte
2
bytes
3
bytes
4
bytes
10
/
20
/
30
mbufs <&> in use (current/cache/total)
50
from
Boston
64
left out of
640
64
left out of
640
beforeworkingafter:
string
:
10
11
1010
packets here/there/everywhere
1010
packets here/there/everywhere
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
Humanize:
21
,
57 K
,
96M
,
44M
,
1.2G
one
two
three
(null)
1:
1000
2:
test5000
3:
ten-longx
4:
xtest
this is an error
two more errors
this is an warning
two more warnings
V1/V2 packets
:
10
0004
tries
improper use of profanity; ten yard penalty; first down +
20
30
40
file
0
bytes
1
byte
2
bytes
3
bytes
4
bytes
Low/warn granularity
:
155
10
/
20
/
30
mbufs <&> in use (current/cache/total)
50
from
Boston
64
left out of
640
64
left out of
640
beforeworkingafter:
string
:
10
11
1010
packets here/there/everywhere
1010
packets here/there/everywhere
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
(
15
/
20
/
125
)
Humanize:
21
,
57 K
,
96M
,
44M
,
1.2G
one
two
three
(null)
1:
1000
2:
test5000
3:
ten-longx
4:
xtest
this is an error
two more errors
this is an warning
two more warnings
V1/V2 packets
:
10
0004
tries
improper use of profanity; ten yard penalty; first down
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +
err message (1)
err message (2) +
err message (1) +
err message (2)
\ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_02.HIPx.err b/contrib/libxo/tests/core/saved/test_02.HIPx.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.HIPx.err +++ b/contrib/libxo/tests/core/saved/test_02.HIPx.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.HIPx.out b/contrib/libxo/tests/core/saved/test_02.HIPx.out index e2b51086d9b..6859660f2f0 100644 --- a/contrib/libxo/tests/core/saved/test_02.HIPx.out +++ b/contrib/libxo/tests/core/saved/test_02.HIPx.out @@ -78,6 +78,13 @@
bytes
+
+
Low/warn granularity
+
:
+
+
155
+
+
10
/
@@ -225,3 +232,18 @@
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<>
+
+
err message (1)
+
+
+
err message (2) +
+
+
+
err message (1) +
+
+
+
err message (2) +
+
diff --git a/contrib/libxo/tests/core/saved/test_02.HP.err b/contrib/libxo/tests/core/saved/test_02.HP.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.HP.err +++ b/contrib/libxo/tests/core/saved/test_02.HP.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.HP.out b/contrib/libxo/tests/core/saved/test_02.HP.out index 2a4b954c94e..6bf93277a3b 100644 --- a/contrib/libxo/tests/core/saved/test_02.HP.out +++ b/contrib/libxo/tests/core/saved/test_02.HP.out @@ -78,6 +78,13 @@
bytes
+
+
Low/warn granularity
+
:
+
+
155
+
+
10
/
@@ -225,3 +232,18 @@
Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<>
+
+
err message (1)
+
+
+
err message (2) +
+
+
+
err message (1) +
+
+
+
err message (2) +
+
diff --git a/contrib/libxo/tests/core/saved/test_02.J.err b/contrib/libxo/tests/core/saved/test_02.J.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.J.err +++ b/contrib/libxo/tests/core/saved/test_02.J.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.J.out b/contrib/libxo/tests/core/saved/test_02.J.out index d6d175339c7..5e01fa9a8bd 100644 --- a/contrib/libxo/tests/core/saved/test_02.J.out +++ b/contrib/libxo/tests/core/saved/test_02.J.out @@ -1 +1 @@ -{"top": {"data": {"name":"em0","flags":"0x8843","name":"em0","flags":"0x8843","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":125,"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"}}}} +{"top": {"data": {"name":"em0","flags":"0x8843","name":"em0","flags":"0x8843","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],"granularity-lw":155,"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":125,"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"}, "error": {"message":"err message (1)"}, "error": {"message":"err message (2)\n"}, "error": {"message":"err message (1)\n"}, "error": {"message":"err message (2)\n"}}}} diff --git a/contrib/libxo/tests/core/saved/test_02.JP.err b/contrib/libxo/tests/core/saved/test_02.JP.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.JP.err +++ b/contrib/libxo/tests/core/saved/test_02.JP.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.JP.out b/contrib/libxo/tests/core/saved/test_02.JP.out index cf211401be6..ef39233d006 100644 --- a/contrib/libxo/tests/core/saved/test_02.JP.out +++ b/contrib/libxo/tests/core/saved/test_02.JP.out @@ -23,6 +23,7 @@ 3, 4 ], + "granularity-lw": 155, "mbuf-current": 10, "mbuf-cache": 20, "mbuf-total": 30, @@ -80,6 +81,18 @@ "test": 4, "error": { "message": "Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n" + }, + "error": { + "message": "err message (1)" + }, + "error": { + "message": "err message (2)\n" + }, + "error": { + "message": "err message (1)\n" + }, + "error": { + "message": "err message (2)\n" } } } diff --git a/contrib/libxo/tests/core/saved/test_02.JPu.err b/contrib/libxo/tests/core/saved/test_02.JPu.err new file mode 100644 index 00000000000..cedb03e0da3 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_02.JPu.err @@ -0,0 +1 @@ +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.JPu.out b/contrib/libxo/tests/core/saved/test_02.JPu.out new file mode 100644 index 00000000000..d0b868a5f8e --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_02.JPu.out @@ -0,0 +1,99 @@ +{ + "top": { + "data": { + "name": "em0", + "flags": "0x8843", + "name": "em0", + "flags": "0x8843", + "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 + ], + "granularity_lw": 155, + "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": 125, + "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" + }, + "error": { + "message": "err message (1)" + }, + "error": { + "message": "err message (2)\n" + }, + "error": { + "message": "err message (1)\n" + }, + "error": { + "message": "err message (2)\n" + } + } + } +} diff --git a/contrib/libxo/tests/core/saved/test_02.T.err b/contrib/libxo/tests/core/saved/test_02.T.err index bae8367624f..debdac6a515 100644 --- a/contrib/libxo/tests/core/saved/test_02.T.err +++ b/contrib/libxo/tests/core/saved/test_02.T.err @@ -1,2 +1,5 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +err message (1)err message (2) +err message (1) +err message (2) diff --git a/contrib/libxo/tests/core/saved/test_02.T.out b/contrib/libxo/tests/core/saved/test_02.T.out index 5b22c1615bb..552e95393ab 100644 --- a/contrib/libxo/tests/core/saved/test_02.T.out +++ b/contrib/libxo/tests/core/saved/test_02.T.out @@ -12,6 +12,7 @@ improper use of profanity; ten yard penalty; first down 2 bytes 3 bytes 4 bytes +Low/warn granularity: 155 mAh 10/20/30 mbufs <&> in use (current/cache/total) 50 miles from Boston 64k left out of 640kb diff --git a/contrib/libxo/tests/core/saved/test_02.X.err b/contrib/libxo/tests/core/saved/test_02.X.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.X.err +++ b/contrib/libxo/tests/core/saved/test_02.X.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.X.out b/contrib/libxo/tests/core/saved/test_02.X.out index 2eb122d00c8..3c491c3ec81 100644 --- a/contrib/libxo/tests/core/saved/test_02.X.out +++ b/contrib/libxo/tests/core/saved/test_02.X.out @@ -2,6 +2,9 @@ abcdef: Bad file descriptor improper use of profanity; ten yard penalty; first down abcdef-1Bad file descriptorgood-1Bad figoodimproper use of profanity; ten yard penalty; first down -2030400123410203050Boston646406464010111010101015201251520125152012515201252158368100663296444702721342172800onetwothreenull1000test5000ten-longxxtest<__error>this is an error<__error>two more errors<__warning>this is an warning<__warning>two more warnings104improper use of profanity; ten yard penalty; first down +2030400123415510203050Boston646406464010111010101015201251520125152012515201252158368100663296444702721342172800onetwothreenull1000test5000ten-longxxtest<__error>this is an error<__error>two more errors<__warning>this is an warning<__warning>two more warnings104improper use of profanity; ten yard penalty; first down Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> +err message (1)err message (2) +err message (1) +err message (2) \ No newline at end of file diff --git a/contrib/libxo/tests/core/saved/test_02.XP.err b/contrib/libxo/tests/core/saved/test_02.XP.err index 4bd358b8813..cedb03e0da3 100644 --- a/contrib/libxo/tests/core/saved/test_02.XP.err +++ b/contrib/libxo/tests/core/saved/test_02.XP.err @@ -1 +1 @@ -test_02.test: key field emitted after normal value field: 'name' +test_02: key field emitted after normal value field: 'name' diff --git a/contrib/libxo/tests/core/saved/test_02.XP.out b/contrib/libxo/tests/core/saved/test_02.XP.out index 9c18c5edca4..c9e85cb46d5 100644 --- a/contrib/libxo/tests/core/saved/test_02.XP.out +++ b/contrib/libxo/tests/core/saved/test_02.XP.out @@ -28,6 +28,7 @@ 2 3 4 + 155 10 20 30 @@ -85,6 +86,21 @@ Shut 'er down, Clancey! She's a-pumpin' mud! <>!,"!<> + + + + err message (1) + + + err message (2) + + + + err message (1) + + + + err message (2) diff --git a/contrib/libxo/tests/core/saved/test_03.E.out b/contrib/libxo/tests/core/saved/test_03.E.out index 21bf7d2760a..7c27f2d4ed8 100644 --- a/contrib/libxo/tests/core/saved/test_03.E.out +++ b/contrib/libxo/tests/core/saved/test_03.E.out @@ -1,4 +1,4 @@ -op create: [] [] [0] +op create: [test] [] [0] op open_container: [employees] [] [0x10] op open_list: [employee] [] [0] op close_list: [employee] [] [0] diff --git a/contrib/libxo/tests/core/saved/test_03.JPu.err b/contrib/libxo/tests/core/saved/test_03.JPu.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_03.JPu.out b/contrib/libxo/tests/core/saved/test_03.JPu.out new file mode 100644 index 00000000000..d0c3ccf45b5 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_03.JPu.out @@ -0,0 +1,33 @@ +{ + "employees": { + "employee": [ + ], + "extra": "", + "memory": [ + { + "type": "name", + "in_use": 12345, + "memory_use": 54321, + "high_use": "-", + "requests": 32145 + } + ], + "employee": [ + { + "first_name": "Terry", + "last_name": "Jones", + "department": 660 + }, + { + "first_name": "Leslie", + "last_name": "Patterson", + "department": 341 + }, + { + "first_name": "Ashley", + "last_name": "Smith", + "department": 1440 + } + ] + } +} diff --git a/contrib/libxo/tests/core/saved/test_04.E.out b/contrib/libxo/tests/core/saved/test_04.E.out index cfb751d6b92..d5d53aedc48 100644 --- a/contrib/libxo/tests/core/saved/test_04.E.out +++ b/contrib/libxo/tests/core/saved/test_04.E.out @@ -1,4 +1,4 @@ -op create: [] [] [0] +op create: [test] [] [0] op open_container: [employees] [] [0x10] op open_list: [employee] [] [0] op open_instance: [employee] [] [0x10] diff --git a/contrib/libxo/tests/core/saved/test_04.JPu.err b/contrib/libxo/tests/core/saved/test_04.JPu.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_04.JPu.out b/contrib/libxo/tests/core/saved/test_04.JPu.out new file mode 100644 index 00000000000..b0f802dc03f --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_04.JPu.out @@ -0,0 +1,21 @@ +{ + "employees": { + "employee": [ + { + "first_name": "Terry", + "last_name": "Jones", + "department": 660 + }, + { + "first_name": "Leslie", + "last_name": "Patterson", + "department": 341 + }, + { + "first_name": "Ashley", + "last_name": "Smith", + "department": 1440 + } + ] + } +} diff --git a/contrib/libxo/tests/core/saved/test_05.E.out b/contrib/libxo/tests/core/saved/test_05.E.out index 8e8fcfe65c5..904a616ce7c 100644 --- a/contrib/libxo/tests/core/saved/test_05.E.out +++ b/contrib/libxo/tests/core/saved/test_05.E.out @@ -1,4 +1,4 @@ -op create: [] [] [0] +op create: [test] [] [0] op open_container: [indian-languages] [] [0x200010] op string: [gurmukhi] [ਲਹੌਰ ਪਾਕਿਸਤਾਨੀ ਪੰਜਾਬ ਦੀ ਰਾਜਧਾਨੀ ਹੈ । ਲੋਕ ਗਿਣਤੀ ਦੇ ਨਾਲ ਕਰਾਚੀ ਤੋਂ ਬਾਅਦ ਲਹੌਰ ਦੂਜਾ ਸਭ ਤੋਂ ਵੱਡਾ ਸ਼ਹਿਰ ਹੈ । ਲਹੌਰ ਪਾਕਿਸਤਾਨ ਦਾ ਸਿਆਸੀ, ਰਹਤਲੀ ਤੇ ਪੜ੍ਹਾਈ ਦਾ ਗੜ੍ਹ ਹੈ ਅਤੇ ਇਸ ਲਈ ਇਹਨੂੰ ਪਾਕਿਸਤਾਨ ਦਾ ਦਿਲ ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ । ਲਹੌਰ ਦਰਿਆ-ਏ-ਰਾਵੀ ਦੇ ਕੰਢੇ ਤੇ ਵਸਦਾ ਹੈ ਤੇ ਇਸਦੀ ਲੋਕ ਗਿਣਤੀ ਇੱਕ ਕਰੋੜ ਦੇ ਨੇੜੇ ਹੈ ।] [0] op string: [shahmukhi] [لہور پاکستانی پنجاب دا دارالحکومت اے۔ لوک گنتی دے نال کراچی توں بعد لہور دوجا سبھ توں وڈا شہر اے۔ لہور پاکستان دا سیاسی، رہتلی تے پڑھائی دا گڑھ اے تے اس لئی ایھنوں پاکستان دا دل وی کیھا جاندا اے۔ لہور دریاۓ راوی دے کنڈھے تے وسدا اے اسدی لوک گنتی اک کروڑ دے نیڑے اے ۔] [0] diff --git a/contrib/libxo/tests/core/saved/test_05.JPu.err b/contrib/libxo/tests/core/saved/test_05.JPu.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_05.JPu.out b/contrib/libxo/tests/core/saved/test_05.JPu.out new file mode 100644 index 00000000000..9bcbf69df91 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_05.JPu.out @@ -0,0 +1,91 @@ +{ + "indian_languages": { + "gurmukhi": "ਲਹੌਰ ਪਾਕਿਸਤਾਨੀ ਪੰਜਾਬ ਦੀ ਰਾਜਧਾਨੀ ਹੈ । ਲੋਕ ਗਿਣਤੀ ਦੇ ਨਾਲ ਕਰਾਚੀ ਤੋਂ ਬਾਅਦ ਲਹੌਰ ਦੂਜਾ ਸਭ ਤੋਂ ਵੱਡਾ ਸ਼ਹਿਰ ਹੈ । ਲਹੌਰ ਪਾਕਿਸਤਾਨ ਦਾ ਸਿਆਸੀ, ਰਹਤਲੀ ਤੇ ਪੜ੍ਹਾਈ ਦਾ ਗੜ੍ਹ ਹੈ ਅਤੇ ਇਸ ਲਈ ਇਹਨੂੰ ਪਾਕਿਸਤਾਨ ਦਾ ਦਿਲ ਵੀ ਕਿਹਾ ਜਾਂਦਾ ਹੈ । ਲਹੌਰ ਦਰਿਆ-ਏ-ਰਾਵੀ ਦੇ ਕੰਢੇ ਤੇ ਵਸਦਾ ਹੈ ਤੇ ਇਸਦੀ ਲੋਕ ਗਿਣਤੀ ਇੱਕ ਕਰੋੜ ਦੇ ਨੇੜੇ ਹੈ ।", + "shahmukhi": "لہور پاکستانی پنجاب دا دارالحکومت اے۔ لوک گنتی دے نال کراچی توں بعد لہور دوجا سبھ توں وڈا شہر اے۔ لہور پاکستان دا سیاسی، رہتلی تے پڑھائی دا گڑھ اے تے اس لئی ایھنوں پاکستان دا دل وی کیھا جاندا اے۔ لہور دریاۓ راوی دے کنڈھے تے وسدا اے اسدی لوک گنتی اک کروڑ دے نیڑے اے ۔", + "tranliteration": "lahor pākistān panjāb dā dārul hakūmat ē. lōk giṇtī dē nāḷ karācī tō᷈ bāad lahor dūjā sab tō᷈ vaḍḍā shahr ē. lahor pākistān dā siāsī, rahtalī tē paṛā̀ī dā gā́ṛ ē tē is laī ihnū᷈ pākistān dā dil vī kehā jāndā ē. lahor dariāē rāvī dē kanḍē tē vasdā ē. isdī lōk giṇtī ikk karōṛ dē nēṛē ē." + }, + "employees": { + "wc": [ + "෴ - 0xdf4 - 1", + "ණ - 0xdab - 1", + "් - 0xdca - 0", + "ණ - 0xdab - 1", + "្ - 0x17d2 - 0", + "෴ - 0xdf4 - 1", + "1 - 0x31 - 1", + "͏ - 0x34f - 0", + "2 - 0x32 - 1", + "⃝ - 0x20dd - 0" + ], + "fancy": "1͏2⃝", + "v1": "γιγνώσκειν", + "v2": "ὦ ἄνδρες ᾿Αθηναῖοι", + "v1": "ახლავე გაიაროთ რეგისტრაცია", + "v2": "Unicode-ის მეათე საერთაშორისო", + "width": 55, + "sinhala": "෴ණ්ණ෴", + "width": 4, + "sinhala": "෴", + "width": 1, + "sinhala": "෴ණ්ණ෴෴ණ්ණ෴", + "width": 8, + "not_sinhala": "123456", + "tag": "ර්‍ඝ", + "width": 2, + "employee": [ + { + "first_name": "Jim", + "nic_name": "\"რეგტ\"", + "last_name": "გთხოვთ ახ", + "department": 431, + "percent_time": 90, + "benefits": "full" + }, + { + "first_name": "Terry", + "nic_name": "\"1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-status [animal-status@42 animal="snake" state="loose"] The snake is loose}} diff --git a/contrib/libxo/tests/core/saved/test_11.JPu.err b/contrib/libxo/tests/core/saved/test_11.JPu.err new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contrib/libxo/tests/core/saved/test_11.JPu.out b/contrib/libxo/tests/core/saved/test_11.JPu.out new file mode 100644 index 00000000000..f82139be877 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_11.JPu.out @@ -0,0 +1,22 @@ +{{<14>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-status [animal-status@42 animal="snake" state="loose"] The snake is loose}} +{{test-program: }} +{{The snake is loose}} + +{{<22>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-consumed [animal-consumed@42 animal="snake" pet="hamster"] My snake ate your hamster}} +{{test-program: }} +{{My snake ate your hamster}} + +{{<29>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 animal-talk [animal-talk@42 count="1" animal="owl" quote="\"e=m\\c[2\]\""] 1 owl said "e=m\c[2]"}} +{{test-program: }} +{{1 owl said "e=m\c[2]"}} + +{{<165>1 2015-06-23T13:47:09.123-0500 worker-host test-program 222 ID47 [ID47@32473 iut="3" event-source="application" event-id="1011"] An application 1011 log entry}} +{{test-program: }} +{{An application 1011 log entry}} + +{ + "__version": "3.1.4", + "top": { + + } +} diff --git a/contrib/libxo/tests/core/saved/test_12.E.err b/contrib/libxo/tests/core/saved/test_12.E.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.E.err +++ b/contrib/libxo/tests/core/saved/test_12.E.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.E.out b/contrib/libxo/tests/core/saved/test_12.E.out index 2ce69f15196..414311499fe 100644 --- a/contrib/libxo/tests/core/saved/test_12.E.out +++ b/contrib/libxo/tests/core/saved/test_12.E.out @@ -1,4 +1,4 @@ -op create: [] [] [0] +op create: [test] [] [0] op open_container: [top] [] [0x4040010] op open_container: [data] [] [0x4040010] op string: [animal] [fish] [0] diff --git a/contrib/libxo/tests/core/saved/test_12.H.err b/contrib/libxo/tests/core/saved/test_12.H.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.H.err +++ b/contrib/libxo/tests/core/saved/test_12.H.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.HIPx.err b/contrib/libxo/tests/core/saved/test_12.HIPx.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.HIPx.err +++ b/contrib/libxo/tests/core/saved/test_12.HIPx.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.HP.err b/contrib/libxo/tests/core/saved/test_12.HP.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.HP.err +++ b/contrib/libxo/tests/core/saved/test_12.HP.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.J.err b/contrib/libxo/tests/core/saved/test_12.J.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.J.err +++ b/contrib/libxo/tests/core/saved/test_12.J.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.JP.err b/contrib/libxo/tests/core/saved/test_12.JP.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.JP.err +++ b/contrib/libxo/tests/core/saved/test_12.JP.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.JPu.err b/contrib/libxo/tests/core/saved/test_12.JPu.err new file mode 100644 index 00000000000..6e563c3c236 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_12.JPu.err @@ -0,0 +1,4 @@ +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.JPu.out b/contrib/libxo/tests/core/saved/test_12.JPu.out new file mode 100644 index 00000000000..0095d8dcc59 --- /dev/null +++ b/contrib/libxo/tests/core/saved/test_12.JPu.out @@ -0,0 +1,94 @@ +{ + "top": { + "data": { + "animal": "fish", + "animal": "fish", + "thing": [ + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45" + }, + { + "name": "thing", + "color": "green", + "time": "2:15", + "hand": "left", + "color": "blue", + "time": "3:45", + "2by4": { + "4x4": "truck", + "2morrow": "tomorrow" + } + } + ] + } + } +} diff --git a/contrib/libxo/tests/core/saved/test_12.T.err b/contrib/libxo/tests/core/saved/test_12.T.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.T.err +++ b/contrib/libxo/tests/core/saved/test_12.T.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.X.err b/contrib/libxo/tests/core/saved/test_12.X.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.X.err +++ b/contrib/libxo/tests/core/saved/test_12.X.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/saved/test_12.XP.err b/contrib/libxo/tests/core/saved/test_12.XP.err index 32a5e4d30db..6e563c3c236 100644 --- a/contrib/libxo/tests/core/saved/test_12.XP.err +++ b/contrib/libxo/tests/core/saved/test_12.XP.err @@ -1,4 +1,4 @@ -test_12.test: invalid XML tag name: '2by4' -test_12.test: invalid XML tag name: '4x4' -test_12.test: invalid XML tag name: '2morrow' -test_12.test: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '2by4' +test_12: invalid XML tag name: '4x4' +test_12: invalid XML tag name: '2morrow' +test_12: invalid XML tag name: '2by4' diff --git a/contrib/libxo/tests/core/test_01.c b/contrib/libxo/tests/core/test_01.c index 2957472464b..8311efbfc87 100644 --- a/contrib/libxo/tests/core/test_01.c +++ b/contrib/libxo/tests/core/test_01.c @@ -14,6 +14,7 @@ #include #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -49,27 +50,30 @@ main (int argc, char **argv) { "sold", "number", "Number of items sold" }, { XO_INFO_NULL }, }; + + char name[] = "test_01.test"; /* test trimming of xo_program */ + argv[0] = name; argc = xo_parse_args(argc, argv); if (argc < 0) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); - else if (strcmp(argv[argc], "error") == 0) { + else if (xo_streq(argv[argc], "error")) { close(-1); xo_err(1, "error detected"); } @@ -78,7 +82,7 @@ main (int argc, char **argv) xo_set_info(NULL, info, -1); xo_set_flags(NULL, XOF_KEYS); - xo_open_container_h(NULL, "top"); + xo_open_container_h(NULL, "top-level"); xo_emit("static {:type/ethernet} {:type/bridge} {:type/%4du} {:type/%3d}", 18, 24); @@ -100,10 +104,17 @@ main (int argc, char **argv) xo_emit("{La:} {a:}\n", "Label text", "label", "value"); + const char *title = "My Title"; + xo_emit_field("T", title, "%s\n", NULL, NULL); + xo_emit_field("Vt", "max-chaos", NULL, NULL, " very "); xo_emit_field("V", "min-chaos", "%d", NULL, 42); xo_emit_field("V", "some-chaos", "%d\n", "[%d]", 42); + xo_attr("test-attr", "attr-value"); + xo_emit_field_h(NULL, ",leaf-list,quotes", "sku", "%s-%u", "%s-000-%u", + "gum", 1412); + xo_emit("Connecting to {:host}.{:domain}...\n", "my-box", "example.com"); xo_attr("test", "value"); @@ -186,6 +197,44 @@ main (int argc, char **argv) xo_close_list("item"); xo_close_container("data4"); + xo_attr("test", "value"); + xo_open_container("data"); + xo_open_list("item"); + xo_attr("test2", "value2"); + + xo_emit("{T:Item/%-10s}{T:Total Sold/%12s}{T:In Stock/%12s}" + "{T:On Order/%12s}{T:SKU/%5s}\n"); + + for (ip = list; ip->i_title; ip++) { + xo_open_instance("item"); + xo_attr("test3", "value3"); + + xo_emit("{keq:sku/%s-%u/%s-000-%u}" + "{k:name/%-10s/%s}{n:sold/%12u/%u}", + ip->i_sku_base, ip->i_sku_num, + ip->i_title, ip->i_sold); + + if (ip->i_onorder < 5) + xo_emit("Extra: {:extra}", "special"); + + if (ip->i_instock & 1) + xo_emit("{:in-stock/%12u/%u}", ip->i_instock); + xo_emit("{:on-order/%12u/%u}", ip->i_onorder); + if (!(ip->i_instock & 1)) + xo_emit("{:in-stock/%12u/%u}", ip->i_instock); + + xo_emit("{qkd:sku/%5s-000-%u/%s-000-%u}\n", + ip->i_sku_base, ip->i_sku_num); + + xo_close_instance("item"); + } + + xo_close_list("item"); + xo_close_container("data"); + + xo_emit("\n\n"); + + xo_emit("X{P:}X", "epic fail"); xo_emit("X{T:}X", "epic fail"); xo_emit("X{N:}X", "epic fail"); @@ -206,7 +255,7 @@ main (int argc, char **argv) "/some/file", (int) 0640, 8, 1, 10, "user", 12, "group"); - xo_close_container_h(NULL, "top"); + xo_close_container_h(NULL, "top-level"); xo_finish(); diff --git a/contrib/libxo/tests/core/test_02.c b/contrib/libxo/tests/core/test_02.c index b3d5ca92e20..7591eb177f7 100644 --- a/contrib/libxo/tests/core/test_02.c +++ b/contrib/libxo/tests/core/test_02.c @@ -14,30 +14,33 @@ #include #include "xo.h" +#include "xo_encoder.h" #include "xo_humanize.h" int main (int argc, char **argv) { + xo_set_program("test_02"); + argc = xo_parse_args(argc, argv); if (argc < 0) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); } @@ -82,6 +85,8 @@ main (int argc, char **argv) for (i = 0; i < 5; i++) xo_emit("{lw:bytes/%d}{Np:byte,bytes}\n", i); + xo_emit("{Lc:Low\\/warn granularity}{P:\t}{:granularity-lw/%d}{Uw:/%sh}\n", + 155, "mA"); xo_emit("{:mbuf-current/%u}/{:mbuf-cache/%u}/{:mbuf-total/%u} " "{N:mbufs <&> in use (current\\/cache\\/total)}\n", @@ -143,6 +148,10 @@ main (int argc, char **argv) "ten yard penalty", "first down"); xo_error("Shut 'er down, Clancey! She's a-pumpin' mud! <>!,\"!<>\n"); + xo_error("err message (%d)", 1); + xo_error("err message (%d)\n", 2); + xo_errorn("err message (%d)", 1); + xo_errorn("err message (%d)\n", 2); xo_close_container("data"); diff --git a/contrib/libxo/tests/core/test_03.c b/contrib/libxo/tests/core/test_03.c index af65ddd98d8..67d7be3dfce 100644 --- a/contrib/libxo/tests/core/test_03.c +++ b/contrib/libxo/tests/core/test_03.c @@ -13,6 +13,7 @@ #include #include "xo.h" +#include "xo_encoder.h" xo_info_t info[] = { { "employee", "object", "Employee data" }, @@ -44,10 +45,10 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "count") == 0) { + if (xo_streq(argv[argc], "count")) { if (argv[argc + 1]) opt_count = atoi(argv[++argc]); - } else if (strcmp(argv[argc], "extra") == 0) { + } else if (xo_streq(argv[argc], "extra")) { if (argv[argc + 1]) opt_extra = atoi(argv[++argc]); } diff --git a/contrib/libxo/tests/core/test_08.c b/contrib/libxo/tests/core/test_08.c index 7e19ebeb4c1..b82a7c1dfcb 100644 --- a/contrib/libxo/tests/core/test_08.c +++ b/contrib/libxo/tests/core/test_08.c @@ -15,6 +15,7 @@ #include #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -39,21 +40,21 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); - else if (strcmp(argv[argc], "error") == 0) { + else if (xo_streq(argv[argc], "error")) { close(-1); xo_err(1, "error detected"); } @@ -114,11 +115,11 @@ main (int argc, char **argv) ip->i_title, ip->i_count); } - xo_close_container("data3"); /* Should be a noop */ + xo_close_container("data3"); /* warn: fails at marker 'm1' */ xo_emit("{:test}", "one"); xo_close_marker("m1"); - xo_close_container("data3"); /* Should be a noop */ + xo_close_container("data3"); /* this one works, post-marker */ xo_emit("\n\n"); @@ -138,13 +139,13 @@ main (int argc, char **argv) for (i = 0; i < 3; i++) { xo_open_instance("sub"); xo_emit("{Lwc:/Name}{:name/%d} + 1 = {:next/%d}\n", i, i + 1); - xo_close_container("data4"); + xo_close_container("data4"); /* warn: fails at marker 'm2' */ } xo_close_marker("m2"); xo_emit("{Lwc:/Last}{:last/%d}\n", i); } - xo_close_container("data4"); /* Should be a noop */ + xo_close_container("data4"); /* warn: fails at marker 'm1' */ xo_emit("{:test}", "one"); xo_emit("\n\n"); diff --git a/contrib/libxo/tests/core/test_09.c b/contrib/libxo/tests/core/test_09.c index a612a647d7f..f564d6e7291 100644 --- a/contrib/libxo/tests/core/test_09.c +++ b/contrib/libxo/tests/core/test_09.c @@ -15,6 +15,7 @@ #include #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -39,21 +40,21 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); - else if (strcmp(argv[argc], "error") == 0) { + else if (xo_streq(argv[argc], "error")) { close(-1); xo_err(1, "error detected"); } diff --git a/contrib/libxo/tests/core/test_10.c b/contrib/libxo/tests/core/test_10.c index 223ec55d47f..a53ddecdf74 100644 --- a/contrib/libxo/tests/core/test_10.c +++ b/contrib/libxo/tests/core/test_10.c @@ -16,6 +16,7 @@ #include #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -58,21 +59,21 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); - else if (strcmp(argv[argc], "error") == 0) { + else if (xo_streq(argv[argc], "error")) { close(-1); xo_err(1, "error detected"); } diff --git a/contrib/libxo/tests/core/test_11.c b/contrib/libxo/tests/core/test_11.c index 60851dfffa5..c4a76beb873 100644 --- a/contrib/libxo/tests/core/test_11.c +++ b/contrib/libxo/tests/core/test_11.c @@ -18,6 +18,7 @@ #include #include "xo.h" +#include "xo_encoder.h" void test_syslog_open (void) @@ -50,11 +51,11 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "full") == 0) + if (xo_streq(argv[argc], "full")) unit_test = 0; - else if (strcmp(argv[argc], "fire") == 0) + else if (xo_streq(argv[argc], "fire")) fire = 1; - else if (strcmp(argv[argc], "tz") == 0) + else if (xo_streq(argv[argc], "tz")) tzone = argv[++argc]; } diff --git a/contrib/libxo/tests/core/test_12.c b/contrib/libxo/tests/core/test_12.c index 6a974b5268d..32af2d21185 100644 --- a/contrib/libxo/tests/core/test_12.c +++ b/contrib/libxo/tests/core/test_12.c @@ -15,6 +15,7 @@ #include "xo_config.h" #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -24,30 +25,32 @@ main (int argc, char **argv) xo_emit_flags_t flags = XOEF_RETAIN; int opt_color = 1; + xo_set_program("test_12"); + argc = xo_parse_args(argc, argv); if (argc < 0) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "xml") == 0) + if (xo_streq(argv[argc], "xml")) xo_set_style(NULL, XO_STYLE_XML); - else if (strcmp(argv[argc], "json") == 0) + else if (xo_streq(argv[argc], "json")) xo_set_style(NULL, XO_STYLE_JSON); - else if (strcmp(argv[argc], "text") == 0) + else if (xo_streq(argv[argc], "text")) xo_set_style(NULL, XO_STYLE_TEXT); - else if (strcmp(argv[argc], "html") == 0) + else if (xo_streq(argv[argc], "html")) xo_set_style(NULL, XO_STYLE_HTML); - else if (strcmp(argv[argc], "no-color") == 0) + else if (xo_streq(argv[argc], "no-color")) opt_color = 0; - else if (strcmp(argv[argc], "pretty") == 0) + else if (xo_streq(argv[argc], "pretty")) xo_set_flags(NULL, XOF_PRETTY); - else if (strcmp(argv[argc], "xpath") == 0) + else if (xo_streq(argv[argc], "xpath")) xo_set_flags(NULL, XOF_XPATH); - else if (strcmp(argv[argc], "info") == 0) + else if (xo_streq(argv[argc], "info")) xo_set_flags(NULL, XOF_INFO); - else if (strcmp(argv[argc], "no-retain") == 0) + else if (xo_streq(argv[argc], "no-retain")) flags &= ~XOEF_RETAIN; - else if (strcmp(argv[argc], "big") == 0) { + else if (xo_streq(argv[argc], "big")) { if (argv[argc + 1]) count = atoi(argv[++argc]); } diff --git a/contrib/libxo/tests/gettext/gt_01.c b/contrib/libxo/tests/gettext/gt_01.c index d63674745d6..2a06a306fc8 100644 --- a/contrib/libxo/tests/gettext/gt_01.c +++ b/contrib/libxo/tests/gettext/gt_01.c @@ -21,6 +21,7 @@ #include #include "xo.h" +#include "xo_encoder.h" int main (int argc, char **argv) @@ -35,11 +36,11 @@ main (int argc, char **argv) return 1; for (argc = 1; argv[argc]; argc++) { - if (strcmp(argv[argc], "tz") == 0) + if (xo_streq(argv[argc], "tz")) tzone = argv[++argc]; - else if (strcmp(argv[argc], "lang") == 0) + else if (xo_streq(argv[argc], "lang")) lang = argv[++argc]; - else if (strcmp(argv[argc], "po") == 0) + else if (xo_streq(argv[argc], "po")) strlcpy(path, argv[++argc], sizeof(path)); } diff --git a/contrib/libxo/tests/gettext/saved/gt_01.H.out b/contrib/libxo/tests/gettext/saved/gt_01.H.out index 13606bf7fb1..76122633673 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.H.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.H.out @@ -1 +1 @@ -
Ouryay
ordsway
amingflay
isyay
ymay
ouchcay
bubbly-bubbly
urningbay
Ethay
ordsway
asway '
ymay
amingflay
ouchcay
'
urningbay
0
yebay
1
yesbay
2
yezbay
3
yezbay
4
yezbay
otaltay
1234
Eceivedray
1234
ldb2
omfray
foop
#
4321
inyay
32
msyay
Received
1234
yezbay
from
foop
#
4321
in
32
ms
Eceivedray
1234
ldb2
omfray
foop
#
4321
inyay
32
msyay
Onlyay
3
arzlevanezmay
areyay unctioningfay orrectlycay
Ersionvay
Tue Jun 23 18:47:09 UTC 2015
1.2.3
gt_01.test
:
Nableuay otay
ectulatobjay
orwardfay elocipingvay
:
Ermissionpay eniedday
gt_01.test
:
automaticyay
ynchronizationsay ofyay
ardinalyay
ammetersgray
ailedfay
:
Ermissionpay eniedday
ydrocoptichay arzlevanesmay
:
6
Dude,
Indingsway
:
otuslay-oyay-eltayay
\ No newline at end of file +
Ouryay
ordsway
amingflay
isyay
ymay
ouchcay
bubbly-bubbly
urningbay
Ethay
ordsway
asway '
ymay
amingflay
ouchcay
'
urningbay
0
yebay
1
yesbay
2
yezbay
3
yezbay
4
yezbay
otaltay
1234
Eceivedray
1234
ldb2
omfray
foop
#
4321
inyay
32
msyay
Received
1234
yezbay
from
foop
#
4321
in
32
ms
Eceivedray
1234
ldb2
omfray
foop
#
4321
inyay
32
msyay
Onlyay
3
arzlevanezmay
areyay unctioningfay orrectlycay
Ersionvay
Tue Jun 23 18:47:09 UTC 2015
1.2.3
gt_01
:
Nableuay otay
ectulatobjay
orwardfay elocipingvay
:
Ermissionpay eniedday
gt_01
:
automaticyay
ynchronizationsay ofyay
ardinalyay
ammetersgray
ailedfay
:
Ermissionpay eniedday
ydrocoptichay arzlevanesmay
:
6
Dude,
Indingsway
:
otuslay-oyay-eltayay
\ No newline at end of file diff --git a/contrib/libxo/tests/gettext/saved/gt_01.HIPx.out b/contrib/libxo/tests/gettext/saved/gt_01.HIPx.out index 06b6a3c3858..597bd1e7f8a 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.HIPx.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.HIPx.out @@ -102,7 +102,7 @@
1.2.3
-
gt_01.test
+
gt_01
:
Nableuay otay
@@ -112,7 +112,7 @@
Ermissionpay eniedday
-
gt_01.test
+
gt_01
:
automaticyay
diff --git a/contrib/libxo/tests/gettext/saved/gt_01.HP.out b/contrib/libxo/tests/gettext/saved/gt_01.HP.out index 573d7b38ad9..de711f00b59 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.HP.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.HP.out @@ -102,7 +102,7 @@
1.2.3
-
gt_01.test
+
gt_01
:
Nableuay otay
@@ -112,7 +112,7 @@
Ermissionpay eniedday
-
gt_01.test
+
gt_01
:
automaticyay
diff --git a/contrib/libxo/tests/gettext/saved/gt_01.J.out b/contrib/libxo/tests/gettext/saved/gt_01.J.out index 2d0e7cc63ba..5a258a8b4cb 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.J.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.J.out @@ -1 +1 @@ -{"top": {"adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay","adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay", "bytes": [0,1,2,3,4],"total":1234,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"marzlevanes":3,"version":"1.2.3","date":"Tue Jun 23 18:47:09 UTC 2015", "__warning": {"program":"gt_01.test","message":"Nableuay otay ectulatobjay orwardfay elocipingvay","verb":"ectulatobjay","error":"Ermissionpay eniedday"}, "__warning": {"program":"gt_01.test","message":"automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay","style":"automaticyay","type":"ardinalyay","target":"ammetersgray","error":"Ermissionpay eniedday"},"marzlevanes":6,"windings":"otuslay-oyay-eltayay"}} +{"top": {"adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay","adjective":"amingflay","noun":"ordsway","verb":"urningbay","owner":"ymay","target":"ouchcay", "bytes": [0,1,2,3,4],"total":1234,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"received":1234,"from":"foop","port":4321,"time":32,"marzlevanes":3,"version":"1.2.3","date":"Tue Jun 23 18:47:09 UTC 2015", "__warning": {"program":"gt_01","message":"Nableuay otay ectulatobjay orwardfay elocipingvay","verb":"ectulatobjay","error":"Ermissionpay eniedday"}, "__warning": {"program":"gt_01","message":"automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay","style":"automaticyay","type":"ardinalyay","target":"ammetersgray","error":"Ermissionpay eniedday"},"marzlevanes":6,"windings":"otuslay-oyay-eltayay"}} diff --git a/contrib/libxo/tests/gettext/saved/gt_01.JP.out b/contrib/libxo/tests/gettext/saved/gt_01.JP.out index 939526f8b58..0717af5b4a6 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.JP.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.JP.out @@ -34,13 +34,13 @@ "version": "1.2.3", "date": "Tue Jun 23 18:47:09 UTC 2015", "__warning": { - "program": "gt_01.test", + "program": "gt_01", "message": "Nableuay otay ectulatobjay orwardfay elocipingvay", "verb": "ectulatobjay", "error": "Ermissionpay eniedday" }, "__warning": { - "program": "gt_01.test", + "program": "gt_01", "message": "automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay", "style": "automaticyay", "type": "ardinalyay", diff --git a/contrib/libxo/tests/gettext/saved/gt_01.T.out b/contrib/libxo/tests/gettext/saved/gt_01.T.out index 440d9a5bc9a..c8d9763616c 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.T.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.T.out @@ -11,7 +11,7 @@ Received 1234 yezbay from foop#4321 in 32 ms Eceivedray 1234 ldb2 omfray foop#4321 inyay 32 msyay Onlyay 3 arzlevanezmay areyay unctioningfay orrectlycay Ersionvay Tue Jun 23 18:47:09 UTC 2015 1.2.3 -gt_01.test: Nableuay otay ectulatobjay orwardfay elocipingvay: Ermissionpay eniedday -gt_01.test: automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay: Ermissionpay eniedday +gt_01: Nableuay otay ectulatobjay orwardfay elocipingvay: Ermissionpay eniedday +gt_01: automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay: Ermissionpay eniedday ydrocoptichay arzlevanesmay: 6 Dude, Indingsway: otuslay-oyay-eltayay diff --git a/contrib/libxo/tests/gettext/saved/gt_01.X.out b/contrib/libxo/tests/gettext/saved/gt_01.X.out index 4eb46223c72..803aca9f857 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.X.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.X.out @@ -1 +1 @@ -amingflayordswayurningbayymayouchcayamingflayordswayurningbayymayouchcay0123412341234foop43211234foop43211234foop432131.2.3Tue Jun 23 18:47:09 UTC 2015<__warning>gt_01.testNableuay otay ectulatobjay orwardfay elocipingvayectulatobjayErmissionpay eniedday<__warning>gt_01.testautomaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfayardinalyayammetersgrayErmissionpay eniedday6otuslay-oyay-eltayay \ No newline at end of file +amingflayordswayurningbayymayouchcayamingflayordswayurningbayymayouchcay0123412341234foop43211234foop43211234foop432131.2.3Tue Jun 23 18:47:09 UTC 2015<__warning>gt_01Nableuay otay ectulatobjay orwardfay elocipingvayectulatobjayErmissionpay eniedday<__warning>gt_01automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfayardinalyayammetersgrayErmissionpay eniedday6otuslay-oyay-eltayay \ No newline at end of file diff --git a/contrib/libxo/tests/gettext/saved/gt_01.XP.out b/contrib/libxo/tests/gettext/saved/gt_01.XP.out index eac42845ad5..456536db774 100644 --- a/contrib/libxo/tests/gettext/saved/gt_01.XP.out +++ b/contrib/libxo/tests/gettext/saved/gt_01.XP.out @@ -31,13 +31,13 @@ 1.2.3 Tue Jun 23 18:47:09 UTC 2015 <__warning> - gt_01.test + gt_01 Nableuay otay ectulatobjay orwardfay elocipingvay ectulatobjay Ermissionpay eniedday <__warning> - gt_01.test + gt_01 automaticyay ynchronizationsay ofyay ardinalyay ammetersgray ailedfay ardinalyay diff --git a/contrib/libxo/tests/xo/saved/xo_02.H.err b/contrib/libxo/tests/xo/saved/xo_02.H.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.H.err +++ b/contrib/libxo/tests/xo/saved/xo_02.H.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.HIPx.err b/contrib/libxo/tests/xo/saved/xo_02.HIPx.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.HIPx.err +++ b/contrib/libxo/tests/xo/saved/xo_02.HIPx.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.HP.err b/contrib/libxo/tests/xo/saved/xo_02.HP.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.HP.err +++ b/contrib/libxo/tests/xo/saved/xo_02.HP.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.J.err b/contrib/libxo/tests/xo/saved/xo_02.J.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.J.err +++ b/contrib/libxo/tests/xo/saved/xo_02.J.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.JP.err b/contrib/libxo/tests/xo/saved/xo_02.JP.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.JP.err +++ b/contrib/libxo/tests/xo/saved/xo_02.JP.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.T.err b/contrib/libxo/tests/xo/saved/xo_02.T.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.T.err +++ b/contrib/libxo/tests/xo/saved/xo_02.T.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.X.err b/contrib/libxo/tests/xo/saved/xo_02.X.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.X.err +++ b/contrib/libxo/tests/xo/saved/xo_02.X.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/saved/xo_02.XP.err b/contrib/libxo/tests/xo/saved/xo_02.XP.err index 0c348c73489..1a570eea55a 100644 --- a/contrib/libxo/tests/xo/saved/xo_02.XP.err +++ b/contrib/libxo/tests/xo/saved/xo_02.XP.err @@ -6,6 +6,7 @@ Usage: xo [options] format [fields] --depth Set the depth for pretty printing --help Display this help text --html OR -H Generate HTML output + --instance OR -I Wrap in an instance of the given name --json OR -J Generate JSON output --leading-xpath OR -l Add a prefix to generated XPaths (HTML) --not-first Indicate this object is not the first (JSON) diff --git a/contrib/libxo/tests/xo/xo_01.sh b/contrib/libxo/tests/xo/xo_01.sh old mode 100755 new mode 100644 diff --git a/contrib/libxo/tests/xo/xo_02.sh b/contrib/libxo/tests/xo/xo_02.sh old mode 100755 new mode 100644 diff --git a/contrib/libxo/xo/xo.1 b/contrib/libxo/xo/xo.1 index cd885b3d193..c3d062f750f 100644 --- a/contrib/libxo/xo/xo.1 +++ b/contrib/libxo/xo/xo.1 @@ -179,7 +179,7 @@ prepend data to the XPath values used for HTML output style. .Bd -literal -offset indent #!/bin/sh xo --open top/data - xo --depth 2 '{tag}' value + xo --depth 2 '{:tag}' value xo --close top/data .Pp XML: diff --git a/contrib/libxo/xo/xo.c b/contrib/libxo/xo/xo.c index d17c738cb54..6d45c9ce5ba 100644 --- a/contrib/libxo/xo/xo.c +++ b/contrib/libxo/xo/xo.c @@ -201,6 +201,7 @@ print_help (void) " --depth Set the depth for pretty printing\n" " --help Display this help text\n" " --html OR -H Generate HTML output\n" +" --instance OR -I Wrap in an instance of the given name\n" " --json OR -J Generate JSON output\n" " --leading-xpath OR -l " "Add a prefix to generated XPaths (HTML)\n" @@ -245,6 +246,7 @@ static struct option long_opts[] = { { "depth", required_argument, &opts.o_depth, 1 }, { "help", no_argument, &opts.o_help, 1 }, { "html", no_argument, NULL, 'H' }, + { "instance", required_argument, NULL, 'I' }, { "json", no_argument, NULL, 'J' }, { "leading-xpath", required_argument, NULL, 'l' }, { "not-first", no_argument, &opts.o_not_first, 1 }, @@ -271,6 +273,7 @@ main (int argc UNUSED, char **argv) char *fmt = NULL, *cp, *np; char *opt_opener = NULL, *opt_closer = NULL, *opt_wrapper = NULL; char *opt_options = NULL; + char *opt_instance = NULL; char *opt_name = NULL; xo_state_t new_state = 0; int opt_depth = 0; @@ -298,6 +301,10 @@ main (int argc UNUSED, char **argv) xo_set_style(NULL, XO_STYLE_HTML); break; + case 'I': + opt_instance = optarg; + break; + case 'J': xo_set_style(NULL, XO_STYLE_JSON); break; @@ -496,12 +503,18 @@ main (int argc UNUSED, char **argv) } } + if (opt_instance) + xo_open_instance(opt_instance); + /* If there's a format string, call xo_emit to emit the contents */ if (fmt && *fmt) { save_argv = argv; prep_arg(fmt); xo_emit(fmt); /* This call does the real formatting */ } + + if (opt_instance) + xo_close_instance(opt_instance); /* If there's an wrapper hierarchy, close each element's container */ while (opt_wrapper) { diff --git a/contrib/libxo/xolint/xolint.pl b/contrib/libxo/xolint/xolint.pl old mode 100755 new mode 100644 index eb72511aa49..0d2be938418 --- a/contrib/libxo/xolint/xolint.pl +++ b/contrib/libxo/xolint/xolint.pl @@ -98,16 +98,18 @@ sub extract_docs { $need_nl = 0; } - print "*** '$_'\n\n"; - print "The message \"$_\" can be caused by code like:\n\n"; + $under = "+" x (length($_) + 2); + + print "'$_'\n$under\n\n"; + print "The message \"$_\" can be caused by code like:\n"; $new = 0; } elsif (/xo_emit\s*\(/) { s/^\s+//; - print " $_\n\n"; + print "\n::\n\n $_\n\n"; } elsif (/^Should be/i) { - print "This code should be replaced with code like:\n\n"; + print "This code should be replaced with code like:\n"; } else { print "$_\n";