summaryrefslogtreecommitdiffstats
path: root/contrib/libxo/xo
diff options
context:
space:
mode:
authormarcel <marcel@FreeBSD.org>2014-10-23 22:30:14 +0000
committermarcel <marcel@FreeBSD.org>2014-10-23 22:30:14 +0000
commitfefcd296e4716886912a74acd38abba4c94bc340 (patch)
treece8b178967e5d33cbba89d0b2f3d2c2ea45616cb /contrib/libxo/xo
parentbc4f095bf4554f6047f55bd8d28df41679cade6b (diff)
downloadFreeBSD-src-fefcd296e4716886912a74acd38abba4c94bc340.zip
FreeBSD-src-fefcd296e4716886912a74acd38abba4c94bc340.tar.gz
Import libxo 0.1.4
Obtained from: https://github.com/Juniper/libxo Sponsored by: Juniper Networks, Inc.
Diffstat (limited to 'contrib/libxo/xo')
-rw-r--r--contrib/libxo/xo/Makefile.am35
-rw-r--r--contrib/libxo/xo/xo.1190
-rw-r--r--contrib/libxo/xo/xo.c440
3 files changed, 665 insertions, 0 deletions
diff --git a/contrib/libxo/xo/Makefile.am b/contrib/libxo/xo/Makefile.am
new file mode 100644
index 0000000..247ef3b
--- /dev/null
+++ b/contrib/libxo/xo/Makefile.am
@@ -0,0 +1,35 @@
+#
+# Copyright 2014, Juniper Networks, Inc.
+# All rights reserved.
+# This SOFTWARE is licensed under the LICENSE provided in the
+# ../Copyright file. By downloading, installing, copying, or otherwise
+# using the SOFTWARE, you agree to be bound by the terms of that
+# LICENSE.
+
+if LIBXO_WARNINGS_HIGH
+LIBXO_WARNINGS = HIGH
+endif
+include ${top_srcdir}/warnings.mk
+
+AM_CFLAGS = \
+ -DLIBXO_XMLSOFT_NEED_PRIVATE \
+ -I${top_builddir} \
+ -I${top_srcdir} \
+ -I${top_srcdir}/libxo \
+ ${WARNINGS}
+
+LIBS = \
+ ${LIBXO_LIBS}
+
+bin_PROGRAMS = xo
+
+xo_SOURCES = xo.c
+#xo_LDADD = ../libxo/libxo.la
+#xo_LDFLAGS = -static
+
+LDADD = \
+ ${top_builddir}/libxo/libxo.la
+
+man_MANS = xo.1
+
+EXTRA_DIST = xo.1
diff --git a/contrib/libxo/xo/xo.1 b/contrib/libxo/xo/xo.1
new file mode 100644
index 0000000..1833b0a
--- /dev/null
+++ b/contrib/libxo/xo/xo.1
@@ -0,0 +1,190 @@
+.\" #
+.\" # Copyright (c) 2014, Juniper Networks, Inc.
+.\" # All rights reserved.
+.\" # This SOFTWARE is licensed under the LICENSE provided in the
+.\" # ../Copyright file. By downloading, installing, copying, or
+.\" # using the SOFTWARE, you agree to be bound by the terms of that
+.\" # LICENSE.
+.\" # Phil Shafer, July 2014
+.\"
+.Dd July, 2014
+.Dt LIBXO 3
+.Os
+.Sh NAME
+.Nm xo
+.Nd emit formatted output based on format string and arguments
+.Sh SYNOPSIS
+.Nm xo
+.Op Fl options
+.Op Ar argument...
+.Sh DESCRIPTION
+The
+.Nm xo
+utility allows command line access to the functionality of
+the
+.Em libxo
+library. Using
+.Nm xo ,
+shell scripts can emit
+.Em XML ,
+.Em JSON , or
+.Em HTML
+using the same commands that emit text output.
+.Pp
+.Bl -tag -width "12345678901234567"
+.It Fl "-close <path>"
+Close tags for the given path
+.It Fl "-depth <num>"
+Set the depth for pretty printing
+.It Fl "-help"
+Display this help text
+.It Fl "-html OR -H"
+Generate HTML output
+.It Fl "-json OR -J"
+Generate JSON output
+.It Fl "-leading-xpath <path>"
+Add a prefix to generated XPaths (HTML)
+.It Fl "-open <path>"
+Open tags for the given path
+.It Fl "-pretty OR -p"
+Make 'pretty' output (add indent, newlines)
+.It Fl "-style <style>"
+Generate given style (xml, json, text, html)
+.It Fl "-text OR -T"
+Generate text output (the default style)
+.It Fl "-version"
+Display version information
+.It Fl "-warn OR -W"
+Display warnings in text on stderr
+.It Fl "-warn-xml"
+Display warnings in xml on stdout
+.It Fl "-wrap <path>"
+Wrap output in a set of containers
+.It Fl "-xml OR -X"
+Generate XML output
+.It Fl "-xpath"
+Add XPath data to HTML output);
+.El
+.Pp
+The
+.Nm xo
+utility accepts a format string suitable for
+.Xr xo_emit 3
+and a set of zero or more arguments used to supply data for that string.
+.Bd -literal -offset indent
+ xo "The {k:name} weighs {:weight/%d} pounds.\n" fish 6
+
+ TEXT:
+ The fish weighs 6 pounds.
+ XML:
+ <name>fish</name>
+ <weight>6</weight>
+ JSON:
+ "name": "fish",
+ "weight": 6
+ HTML:
+ <div class="line">
+ <div class="text">The </div>
+ <div class="data" data-tag="name">fish</div>
+ <div class="text"> weighs </div>
+ <div class="data" data-tag="weight">6</div>
+ <div class="text"> pounds.</div>
+ </div>
+.Ed
+.Pp
+The
+.Fl "-wrap <path>"
+option can be used to wrap emitted content in a
+specific hierarchy. The path is a set of hierarchical names separated
+by the '/' character.
+.Bd -literal -offset indent
+ xo --wrap top/a/b/c '{:tag}' value
+
+ XML:
+ <top>
+ <a>
+ <b>
+ <c>
+ <tag>value</tag>
+ </c>
+ </b>
+ </a>
+ </top>
+ JSON:
+ "top": {
+ "a": {
+ "b": {
+ "c": {
+ "tag": "value"
+ }
+ }
+ }
+ }
+.Ed
+.Pp
+The
+.Fl "\-open <path>"
+and
+.Fl "\-close <path>"
+can be used to emit
+hierarchical information without the matching close and open
+tag. This allows a shell script to emit open tags, data, and
+then close tags. The
+.Fl \-depth
+option may be used to set the
+depth for indentation. The
+.Fl "\-leading-xpath"
+may be used to
+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 --close top/data
+ XML:
+ <top>
+ <data>
+ <tag>value</tag>
+ </data>
+ </top>
+ JSON:
+ "top": {
+ "data": {
+ "tag": "value"
+ }
+ }
+.Ed
+.Pp
+.Sh EXAMPLE
+.Bd -literal -offset indent
+ % xo 'The {:product} is {:status}\n' stereo "in route"
+ The stereo is in route
+ % xo -p -X 'The {:product} is {:status}\n' stereo "in route"
+ <product>stereo</product>
+ <status>in route</status>
+.Ed
+.Pp
+.Sh ADDITIONAL DOCUMENTATION
+.Pp
+Complete documentation can be found on github:
+.Bd -literal -offset indent
+http://juniper.github.io/libxo/libxo-manual.html
+.Ed
+.Pp
+libxo lives on github as:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo
+.Ed
+.Pp
+The latest release of libxo is available at:
+.Bd -literal -offset indent
+https://github.com/Juniper/libxo/releases
+.Ed
+.Sh SEE ALSO
+.Xr xo_emit 3
+.Sh HISTORY
+The
+.Fa libxo
+library was added in FreeBSD 11.0.
+.Sh AUTHOR
+Phil Shafer
diff --git a/contrib/libxo/xo/xo.c b/contrib/libxo/xo/xo.c
new file mode 100644
index 0000000..698d9d6
--- /dev/null
+++ b/contrib/libxo/xo/xo.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2014, Juniper Networks, Inc.
+ * All rights reserved.
+ * This SOFTWARE is licensed under the LICENSE provided in the
+ * ../Copyright file. By downloading, installing, copying, or otherwise
+ * using the SOFTWARE, you agree to be bound by the terms of that
+ * LICENSE.
+ * Phil Shafer, July 2014
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "xoconfig.h"
+#include "xo.h"
+#include "xoversion.h"
+
+#include <getopt.h> /* Include after xo.h for testing */
+
+#ifndef UNUSED
+#define UNUSED __attribute__ ((__unused__))
+#endif /* UNUSED */
+
+static int opt_warn; /* Enable warnings */
+
+static char **save_argv;
+static char **checkpoint_argv;
+
+static char *
+next_arg (void)
+{
+ char *cp = *save_argv;
+
+ if (cp == NULL)
+ xo_errx(1, "missing argument");
+
+ save_argv += 1;
+ return cp;
+}
+
+static void
+prep_arg (char *fmt)
+{
+ char *cp, *fp;
+
+ for (cp = fp = fmt; *cp; cp++, fp++) {
+ if (*cp != '\\') {
+ if (cp != fp)
+ *fp = *cp;
+ continue;
+ }
+
+ switch (*++cp) {
+ case 'n':
+ *fp = '\n';
+ break;
+
+ case 'r':
+ *fp = '\r';
+ break;
+
+ case 'b':
+ *fp = '\b';
+ break;
+
+ case 'e':
+ *fp = '\e';
+ break;
+
+ default:
+ *fp = *cp;
+ }
+ }
+
+ *fp = '\0';
+}
+
+static void
+checkpoint (xo_handle_t *xop UNUSED, va_list vap UNUSED, int restore)
+{
+ if (restore)
+ save_argv = checkpoint_argv;
+ else
+ checkpoint_argv = save_argv;
+}
+
+/*
+ * Our custom formatter is responsible for combining format string pieces
+ * with our command line arguments to build strings. This involves faking
+ * some printf-style logic.
+ */
+static int
+formatter (xo_handle_t *xop, char *buf, int bufsiz,
+ const char *fmt, va_list vap UNUSED)
+{
+ int lflag = 0, hflag = 0, jflag = 0, tflag = 0,
+ zflag = 0, qflag = 0, star1 = 0, star2 = 0;
+ int rc = 0;
+ int w1 = 0, w2 = 0;
+ const char *cp;
+
+ for (cp = fmt + 1; *cp; cp++) {
+ if (*cp == 'l')
+ lflag += 1;
+ else if (*cp == 'h')
+ hflag += 1;
+ else if (*cp == 'j')
+ jflag += 1;
+ else if (*cp == 't')
+ tflag += 1;
+ else if (*cp == 'z')
+ zflag += 1;
+ else if (*cp == 'q')
+ qflag += 1;
+ else if (*cp == '*') {
+ if (star1 == 0)
+ star1 = 1;
+ else
+ star2 = 1;
+ } else if (strchr("diouxXDOUeEfFgGaAcCsSp", *cp) != NULL)
+ break;
+ else if (*cp == 'n' || *cp == 'v') {
+ if (opt_warn)
+ xo_error_h(xop, "unsupported format: '%s'", fmt);
+ return -1;
+ }
+ }
+
+ char fc = *cp;
+
+ /* Handle "%*.*s" */
+ if (star1)
+ w1 = strtol(next_arg(), NULL, 0);
+ if (star2 > 1)
+ w2 = strtol(next_arg(), NULL, 0);
+
+ if (fc == 'D' || fc == 'O' || fc == 'U')
+ lflag = 1;
+
+ if (strchr("diD", fc) != NULL) {
+ long long value = strtoll(next_arg(), NULL, 0);
+ if (star1 && star2)
+ rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
+ else if (star1)
+ rc = snprintf(buf, bufsiz, fmt, w1, value);
+ else
+ rc = snprintf(buf, bufsiz, fmt, value);
+
+ } else if (strchr("ouxXOUp", fc) != NULL) {
+ unsigned long long value = strtoull(next_arg(), NULL, 0);
+ if (star1 && star2)
+ rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
+ else if (star1)
+ rc = snprintf(buf, bufsiz, fmt, w1, value);
+ else
+ rc = snprintf(buf, bufsiz, fmt, value);
+
+ } else if (strchr("eEfFgGaA", fc) != NULL) {
+ double value = strtold(next_arg(), NULL);
+ if (star1 && star2)
+ rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
+ else if (star1)
+ rc = snprintf(buf, bufsiz, fmt, w1, value);
+ else
+ rc = snprintf(buf, bufsiz, fmt, value);
+
+ } else if (fc == 'C' || fc == 'c' || fc == 'S' || fc == 's') {
+ char *value = next_arg();
+ if (star1 && star2)
+ rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
+ else if (star1)
+ rc = snprintf(buf, bufsiz, fmt, w1, value);
+ else
+ rc = snprintf(buf, bufsiz, fmt, value);
+ }
+
+ return rc;
+}
+
+static void
+print_version (void)
+{
+ fprintf(stderr, "libxo version %s%s\n",
+ xo_version, xo_version_extra);
+ fprintf(stderr, "xo version %s%s\n",
+ LIBXO_VERSION, LIBXO_VERSION_EXTRA);
+}
+
+static void
+print_help (void)
+{
+ fprintf(stderr,
+"Usage: xo [options] format [fields]\n"
+" --close <path> Close tags for the given path\n"
+" --depth <num> Set the depth for pretty printing\n"
+" --help Display this help text\n"
+" --html OR -H Generate HTML output\n"
+" --json OR -J Generate JSON output\n"
+" --leading-xpath <path> OR -l <path> "
+ "Add a prefix to generated XPaths (HTML)\n"
+" --open <path> Open tags for the given path\n"
+" --pretty OR -p Make 'pretty' output (add indent, newlines)\n"
+" --style <style> OR -s <style> "
+ "Generate given style (xml, json, text, html)\n"
+" --text OR -T Generate text output (the default style)\n"
+" --version Display version information\n"
+" --warn OR -W Display warnings in text on stderr\n"
+" --warn-xml Display warnings in xml on stdout\n"
+" --wrap <path> Wrap output in a set of containers\n"
+" --xml OR -X Generate XML output\n"
+" --xpath Add XPath data to HTML output\n");
+}
+
+static struct opts {
+ int o_depth;
+ int o_help;
+ int o_not_first;
+ int o_xpath;
+ int o_version;
+ int o_warn_xml;
+ int o_wrap;
+} opts;
+
+static struct option long_opts[] = {
+ { "close", required_argument, NULL, 'c' },
+ { "depth", required_argument, &opts.o_depth, 1 },
+ { "help", no_argument, &opts.o_help, 1 },
+ { "html", no_argument, NULL, 'H' },
+ { "json", no_argument, NULL, 'J' },
+ { "leading-xpath", required_argument, NULL, 'l' },
+ { "not-first", no_argument, &opts.o_not_first, 1 },
+ { "open", required_argument, NULL, 'o' },
+ { "option", required_argument, NULL, 'O' },
+ { "pretty", no_argument, NULL, 'p' },
+ { "style", required_argument, NULL, 's' },
+ { "text", no_argument, NULL, 'T' },
+ { "xml", no_argument, NULL, 'X' },
+ { "xpath", no_argument, &opts.o_xpath, 1 },
+ { "version", no_argument, &opts.o_version, 1 },
+ { "warn", no_argument, NULL, 'W' },
+ { "warn-xml", no_argument, &opts.o_warn_xml, 1 },
+ { "wrap", required_argument, &opts.o_wrap, 1 },
+ { NULL, 0, NULL, 0 }
+};
+
+int
+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;
+ int opt_depth = 0;
+ int opt_not_first = 0;
+ int rc;
+
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0)
+ return 1;
+
+ while ((rc = getopt_long(argc, argv, "c:HJl:ps:TXW",
+ long_opts, NULL)) != -1) {
+ switch (rc) {
+ case 'c':
+ opt_closer = optarg;
+ xo_set_flags(NULL, XOF_IGNORE_CLOSE);
+ break;
+
+ case 'H':
+ xo_set_style(NULL, XO_STYLE_HTML);
+ break;
+
+ case 'J':
+ xo_set_style(NULL, XO_STYLE_JSON);
+ break;
+
+ case 'l':
+ xo_set_leading_xpath(NULL, optarg);
+ break;
+
+ case 'O':
+ opt_options = optarg;
+ break;
+
+ case 'o':
+ opt_opener = optarg;
+ break;
+
+ case 'p':
+ xo_set_flags(NULL, XOF_PRETTY);
+ break;
+
+ case 's':
+ if (xo_set_style_name(NULL, optarg) < 0)
+ xo_errx(1, "unknown style: %s", optarg);
+ break;
+
+ case 'T':
+ xo_set_style(NULL, XO_STYLE_TEXT);
+ break;
+
+ case 'X':
+ xo_set_style(NULL, XO_STYLE_XML);
+ break;
+
+ case 'W':
+ opt_warn = 1;
+ xo_set_flags(NULL, XOF_WARN);
+ break;
+
+ case ':':
+ xo_errx(1, "missing argument");
+ break;
+
+ case 0:
+ if (opts.o_depth) {
+ opt_depth = atoi(optarg);
+
+ } else if (opts.o_help) {
+ print_help();
+ return 1;
+
+ } else if (opts.o_not_first) {
+ opt_not_first = 1;
+
+ } else if (opts.o_xpath) {
+ xo_set_flags(NULL, XOF_XPATH);
+
+ } else if (opts.o_version) {
+ print_version();
+ return 0;
+
+ } else if (opts.o_warn_xml) {
+ opt_warn = 1;
+ xo_set_flags(NULL, XOF_WARN | XOF_WARN_XML);
+
+ } else if (opts.o_wrap) {
+ opt_wrapper = optarg;
+
+ } else {
+ print_help();
+ return 1;
+ }
+
+ bzero(&opts, sizeof(opts)); /* Reset all the options */
+ break;
+
+ default:
+ print_help();
+ return 1;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (opt_options) {
+ rc = xo_set_options(NULL, opt_options);
+ if (rc < 0)
+ xo_errx(1, "invalid options: %s", opt_options);
+ }
+
+ xo_set_formatter(NULL, formatter, checkpoint);
+ xo_set_flags(NULL, XOF_NO_VA_ARG);
+ xo_set_flags(NULL, XOF_NO_TOP);
+
+ fmt = *argv++;
+ if (opt_opener == NULL && opt_closer == NULL && fmt == NULL) {
+ print_help();
+ return 1;
+ }
+
+ if (opt_not_first)
+ xo_set_flags(NULL, XOF_NOT_FIRST);
+
+ if (opt_closer) {
+ opt_depth += 1;
+ for (cp = opt_closer; cp && *cp; cp = np) {
+ np = strchr(cp, '/');
+ if (np == NULL)
+ break;
+ np += 1;
+ opt_depth += 1;
+ }
+ }
+
+ if (opt_depth > 0)
+ xo_set_depth(NULL, opt_depth);
+
+ if (opt_opener) {
+ for (cp = opt_opener; cp && *cp; cp = np) {
+ np = strchr(cp, '/');
+ if (np)
+ *np = '\0';
+ xo_open_container(cp);
+ if (np)
+ *np++ = '/';
+ }
+ }
+
+ if (opt_wrapper) {
+ for (cp = opt_wrapper; cp && *cp; cp = np) {
+ np = strchr(cp, '/');
+ if (np)
+ *np = '\0';
+ xo_open_container(cp);
+ if (np)
+ *np++ = '/';
+ }
+ }
+
+ if (fmt && *fmt) {
+ save_argv = argv;
+ prep_arg(fmt);
+ xo_emit(fmt);
+ }
+
+ while (opt_wrapper) {
+ np = strrchr(opt_wrapper, '/');
+ xo_close_container(np ? np + 1 : opt_wrapper);
+ if (np)
+ *np = '\0';
+ else
+ opt_wrapper = NULL;
+ }
+
+ while (opt_closer) {
+ np = strrchr(opt_closer, '/');
+ xo_close_container(np ? np + 1 : opt_closer);
+ if (np)
+ *np = '\0';
+ else
+ opt_closer = NULL;
+ }
+
+ xo_finish();
+
+ return 0;
+}
OpenPOWER on IntegriCloud