diff options
author | marcel <marcel@FreeBSD.org> | 2014-10-23 22:30:14 +0000 |
---|---|---|
committer | marcel <marcel@FreeBSD.org> | 2014-10-23 22:30:14 +0000 |
commit | fefcd296e4716886912a74acd38abba4c94bc340 (patch) | |
tree | ce8b178967e5d33cbba89d0b2f3d2c2ea45616cb /contrib/libxo/xo | |
parent | bc4f095bf4554f6047f55bd8d28df41679cade6b (diff) | |
download | FreeBSD-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.am | 35 | ||||
-rw-r--r-- | contrib/libxo/xo/xo.1 | 190 | ||||
-rw-r--r-- | contrib/libxo/xo/xo.c | 440 |
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; +} |