131337658SMarcel Moolenaar /*
231337658SMarcel Moolenaar * Copyright (c) 2014-2019, Juniper Networks, Inc.
331337658SMarcel Moolenaar * All rights reserved.
431337658SMarcel Moolenaar * This SOFTWARE is licensed under the LICENSE provided in the
531337658SMarcel Moolenaar * ../Copyright file. By downloading, installing, copying, or otherwise
631337658SMarcel Moolenaar * using the SOFTWARE, you agree to be bound by the terms of that
731337658SMarcel Moolenaar * LICENSE.
831337658SMarcel Moolenaar * Phil Shafer, July 2014
931337658SMarcel Moolenaar */
1031337658SMarcel Moolenaar
1131337658SMarcel Moolenaar #include <stdio.h>
1231337658SMarcel Moolenaar #include <stdlib.h>
1331337658SMarcel Moolenaar #include <stdarg.h>
1431337658SMarcel Moolenaar #include <string.h>
1531337658SMarcel Moolenaar
16d1a0d267SMarcel Moolenaar #include "xo_config.h"
1731337658SMarcel Moolenaar #include "xo.h"
1831337658SMarcel Moolenaar #include "xo_explicit.h"
1931337658SMarcel Moolenaar
2031337658SMarcel Moolenaar #include <getopt.h> /* Include after xo.h for testing */
2131337658SMarcel Moolenaar
2231337658SMarcel Moolenaar #ifndef UNUSED
2331337658SMarcel Moolenaar #define UNUSED __attribute__ ((__unused__))
2431337658SMarcel Moolenaar #endif /* UNUSED */
2531337658SMarcel Moolenaar
2631337658SMarcel Moolenaar static int opt_warn; /* Enable warnings */
2731337658SMarcel Moolenaar
2831337658SMarcel Moolenaar static char **save_argv;
2931337658SMarcel Moolenaar static char **checkpoint_argv;
3031337658SMarcel Moolenaar
3131337658SMarcel Moolenaar static char *
next_arg(void)3231337658SMarcel Moolenaar next_arg (void)
3331337658SMarcel Moolenaar {
3431337658SMarcel Moolenaar char *cp = *save_argv;
3531337658SMarcel Moolenaar
3631337658SMarcel Moolenaar if (cp == NULL)
3731337658SMarcel Moolenaar xo_errx(1, "missing argument");
3831337658SMarcel Moolenaar
3931337658SMarcel Moolenaar save_argv += 1;
4031337658SMarcel Moolenaar return cp;
4131337658SMarcel Moolenaar }
4231337658SMarcel Moolenaar
4331337658SMarcel Moolenaar static void
prep_arg(char * fmt)4431337658SMarcel Moolenaar prep_arg (char *fmt)
4531337658SMarcel Moolenaar {
4631337658SMarcel Moolenaar char *cp, *fp;
4731337658SMarcel Moolenaar
4831337658SMarcel Moolenaar for (cp = fp = fmt; *cp; cp++, fp++) {
4931337658SMarcel Moolenaar if (*cp != '\\') {
5031337658SMarcel Moolenaar if (cp != fp)
5131337658SMarcel Moolenaar *fp = *cp;
5231337658SMarcel Moolenaar continue;
5331337658SMarcel Moolenaar }
5431337658SMarcel Moolenaar
5531337658SMarcel Moolenaar switch (*++cp) {
5631337658SMarcel Moolenaar case 'n':
5731337658SMarcel Moolenaar *fp = '\n';
5831337658SMarcel Moolenaar break;
5931337658SMarcel Moolenaar
6031337658SMarcel Moolenaar case 'r':
6131337658SMarcel Moolenaar *fp = '\r';
6231337658SMarcel Moolenaar break;
6331337658SMarcel Moolenaar
6431337658SMarcel Moolenaar case 'b':
6531337658SMarcel Moolenaar *fp = '\b';
6631337658SMarcel Moolenaar break;
6731337658SMarcel Moolenaar
6831337658SMarcel Moolenaar case 'e':
6931337658SMarcel Moolenaar *fp = '\e';
7031337658SMarcel Moolenaar break;
7131337658SMarcel Moolenaar
7231337658SMarcel Moolenaar default:
7331337658SMarcel Moolenaar *fp = *cp;
7431337658SMarcel Moolenaar }
7531337658SMarcel Moolenaar }
7631337658SMarcel Moolenaar
7731337658SMarcel Moolenaar *fp = '\0';
7831337658SMarcel Moolenaar }
7931337658SMarcel Moolenaar
8031337658SMarcel Moolenaar static void
checkpoint(xo_handle_t * xop UNUSED,va_list vap UNUSED,int restore)8131337658SMarcel Moolenaar checkpoint (xo_handle_t *xop UNUSED, va_list vap UNUSED, int restore)
8231337658SMarcel Moolenaar {
8331337658SMarcel Moolenaar if (restore)
8431337658SMarcel Moolenaar save_argv = checkpoint_argv;
8531337658SMarcel Moolenaar else
8631337658SMarcel Moolenaar checkpoint_argv = save_argv;
8731337658SMarcel Moolenaar }
8831337658SMarcel Moolenaar
8931337658SMarcel Moolenaar /*
9031337658SMarcel Moolenaar * Our custom formatter is responsible for combining format string pieces
9131337658SMarcel Moolenaar * with our command line arguments to build strings. This involves faking
9231337658SMarcel Moolenaar * some printf-style logic.
9331337658SMarcel Moolenaar */
9431337658SMarcel Moolenaar static xo_ssize_t
formatter(xo_handle_t * xop,char * buf,xo_ssize_t bufsiz,const char * fmt,va_list vap UNUSED)9531337658SMarcel Moolenaar formatter (xo_handle_t *xop, char *buf, xo_ssize_t bufsiz,
9631337658SMarcel Moolenaar const char *fmt, va_list vap UNUSED)
97d1a0d267SMarcel Moolenaar {
98d1a0d267SMarcel Moolenaar int lflag UNUSED = 0; /* Parse long flag, though currently ignored */
9931337658SMarcel Moolenaar int hflag = 0, jflag = 0, tflag = 0,
10031337658SMarcel Moolenaar zflag = 0, qflag = 0, star1 = 0, star2 = 0;
10131337658SMarcel Moolenaar int rc = 0;
10231337658SMarcel Moolenaar int w1 = 0, w2 = 0;
10331337658SMarcel Moolenaar const char *cp;
10431337658SMarcel Moolenaar
10531337658SMarcel Moolenaar for (cp = fmt + 1; *cp; cp++) {
10631337658SMarcel Moolenaar if (*cp == 'l')
10731337658SMarcel Moolenaar lflag += 1;
10831337658SMarcel Moolenaar else if (*cp == 'h')
10931337658SMarcel Moolenaar hflag += 1;
11031337658SMarcel Moolenaar else if (*cp == 'j')
11131337658SMarcel Moolenaar jflag += 1;
11231337658SMarcel Moolenaar else if (*cp == 't')
11331337658SMarcel Moolenaar tflag += 1;
11431337658SMarcel Moolenaar else if (*cp == 'z')
11531337658SMarcel Moolenaar zflag += 1;
11631337658SMarcel Moolenaar else if (*cp == 'q')
11731337658SMarcel Moolenaar qflag += 1;
11831337658SMarcel Moolenaar else if (*cp == '*') {
11931337658SMarcel Moolenaar if (star1 == 0)
12031337658SMarcel Moolenaar star1 = 1;
12131337658SMarcel Moolenaar else
12231337658SMarcel Moolenaar star2 = 1;
12331337658SMarcel Moolenaar } else if (strchr("diouxXDOUeEfFgGaAcCsSp", *cp) != NULL)
12431337658SMarcel Moolenaar break;
12531337658SMarcel Moolenaar else if (*cp == 'n' || *cp == 'v') {
12631337658SMarcel Moolenaar if (opt_warn)
12731337658SMarcel Moolenaar xo_error_h(xop, "unsupported format: '%s'", fmt);
12831337658SMarcel Moolenaar return -1;
12931337658SMarcel Moolenaar }
13031337658SMarcel Moolenaar }
13131337658SMarcel Moolenaar
13231337658SMarcel Moolenaar char fc = *cp;
13331337658SMarcel Moolenaar
13431337658SMarcel Moolenaar /* Handle "%*.*s" */
13531337658SMarcel Moolenaar if (star1)
13631337658SMarcel Moolenaar w1 = strtol(next_arg(), NULL, 0);
13731337658SMarcel Moolenaar if (star2 > 1)
13831337658SMarcel Moolenaar w2 = strtol(next_arg(), NULL, 0);
13931337658SMarcel Moolenaar
14031337658SMarcel Moolenaar if (fc == 'D' || fc == 'O' || fc == 'U')
14131337658SMarcel Moolenaar lflag = 1;
14231337658SMarcel Moolenaar
14331337658SMarcel Moolenaar if (strchr("diD", fc) != NULL) {
14431337658SMarcel Moolenaar long long value = strtoll(next_arg(), NULL, 0);
14531337658SMarcel Moolenaar if (star1 && star2)
14631337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
14731337658SMarcel Moolenaar else if (star1)
14831337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, value);
14931337658SMarcel Moolenaar else
15031337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, value);
15131337658SMarcel Moolenaar
15231337658SMarcel Moolenaar } else if (strchr("ouxXOUp", fc) != NULL) {
15331337658SMarcel Moolenaar unsigned long long value = strtoull(next_arg(), NULL, 0);
15431337658SMarcel Moolenaar if (star1 && star2)
15531337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
15631337658SMarcel Moolenaar else if (star1)
15731337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, value);
15831337658SMarcel Moolenaar else
15931337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, value);
16031337658SMarcel Moolenaar
16131337658SMarcel Moolenaar } else if (strchr("eEfFgGaA", fc) != NULL) {
16231337658SMarcel Moolenaar double value = strtold(next_arg(), NULL);
16331337658SMarcel Moolenaar if (star1 && star2)
16431337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
16531337658SMarcel Moolenaar else if (star1)
16631337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, value);
16731337658SMarcel Moolenaar else
16831337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, value);
16931337658SMarcel Moolenaar
17031337658SMarcel Moolenaar } else if (fc == 'C' || fc == 'c' || fc == 'S' || fc == 's') {
17131337658SMarcel Moolenaar char *value = next_arg();
17231337658SMarcel Moolenaar if (star1 && star2)
17331337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, w2, value);
17431337658SMarcel Moolenaar else if (star1)
17531337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, w1, value);
17631337658SMarcel Moolenaar else
17731337658SMarcel Moolenaar rc = snprintf(buf, bufsiz, fmt, value);
17831337658SMarcel Moolenaar }
17931337658SMarcel Moolenaar
18031337658SMarcel Moolenaar return rc;
18131337658SMarcel Moolenaar }
18231337658SMarcel Moolenaar
18331337658SMarcel Moolenaar static void
print_version(void)18431337658SMarcel Moolenaar print_version (void)
18531337658SMarcel Moolenaar {
18631337658SMarcel Moolenaar fprintf(stderr, "libxo version %s%s\n",
18731337658SMarcel Moolenaar xo_version, xo_version_extra);
18831337658SMarcel Moolenaar fprintf(stderr, "xo version %s%s\n",
18931337658SMarcel Moolenaar LIBXO_VERSION, LIBXO_VERSION_EXTRA);
19031337658SMarcel Moolenaar }
19131337658SMarcel Moolenaar
19231337658SMarcel Moolenaar static void
print_help(void)19331337658SMarcel Moolenaar print_help (void)
19431337658SMarcel Moolenaar {
19531337658SMarcel Moolenaar fprintf(stderr,
19631337658SMarcel Moolenaar "Usage: xo [options] format [fields]\n"
19731337658SMarcel Moolenaar " --close <path> Close tags for the given path\n"
19831337658SMarcel Moolenaar " --close-instance <name> Close an open instance name\n"
19931337658SMarcel Moolenaar " --close-list <name> Close an open list name\n"
20031337658SMarcel Moolenaar " --continuation OR -C Output belongs on same line as previous output\n"
20131337658SMarcel Moolenaar " --depth <num> Set the depth for pretty printing\n"
20231337658SMarcel Moolenaar " --help Display this help text\n"
20331337658SMarcel Moolenaar " --html OR -H Generate HTML output\n"
204d1a0d267SMarcel Moolenaar " --instance OR -I <name> Wrap in an instance of the given name\n"
20531337658SMarcel Moolenaar " --json OR -J Generate JSON output\n"
20631337658SMarcel Moolenaar " --leading-xpath <path> OR -l <path> "
20731337658SMarcel Moolenaar "Add a prefix to generated XPaths (HTML)\n"
20831337658SMarcel Moolenaar " --not-first Indicate this object is not the first (JSON)\n"
20931337658SMarcel Moolenaar " --open <path> Open tags for the given path\n"
21031337658SMarcel Moolenaar " --open-instance <name> Open an instance given by name\n"
21131337658SMarcel Moolenaar " --open-list <name> Open a list given by name\n"
21231337658SMarcel Moolenaar " --option <opts> -or -O <opts> Give formatting options\n"
21331337658SMarcel Moolenaar " --pretty OR -p Make 'pretty' output (add indent, newlines)\n"
21431337658SMarcel Moolenaar " --style <style> OR -s <style> "
21531337658SMarcel Moolenaar "Generate given style (xml, json, text, html)\n"
21631337658SMarcel Moolenaar " --text OR -T Generate text output (the default style)\n"
21731337658SMarcel Moolenaar " --top-wrap Generate a top-level object wrapper (JSON)\n"
21831337658SMarcel Moolenaar " --version Display version information\n"
21931337658SMarcel Moolenaar " --warn OR -W Display warnings in text on stderr\n"
22031337658SMarcel Moolenaar " --warn-xml Display warnings in xml on stdout\n"
22131337658SMarcel Moolenaar " --wrap <path> Wrap output in a set of containers\n"
22231337658SMarcel Moolenaar " --xml OR -X Generate XML output\n"
22331337658SMarcel Moolenaar " --xpath Add XPath data to HTML output\n");
22431337658SMarcel Moolenaar }
22531337658SMarcel Moolenaar
22631337658SMarcel Moolenaar static struct opts {
22731337658SMarcel Moolenaar int o_close_instance;
22831337658SMarcel Moolenaar int o_close_list;
22931337658SMarcel Moolenaar int o_depth;
23031337658SMarcel Moolenaar int o_help;
23131337658SMarcel Moolenaar int o_not_first;
23231337658SMarcel Moolenaar int o_open_instance;
23331337658SMarcel Moolenaar int o_open_list;
23431337658SMarcel Moolenaar int o_top_wrap;
23531337658SMarcel Moolenaar int o_version;
23631337658SMarcel Moolenaar int o_warn_xml;
23731337658SMarcel Moolenaar int o_wrap;
23831337658SMarcel Moolenaar int o_xpath;
23931337658SMarcel Moolenaar } opts;
24031337658SMarcel Moolenaar
24131337658SMarcel Moolenaar static struct option long_opts[] = {
24231337658SMarcel Moolenaar { "close", required_argument, NULL, 'c' },
24331337658SMarcel Moolenaar { "close-instance", required_argument, &opts.o_close_instance, 1 },
24431337658SMarcel Moolenaar { "close-list", required_argument, &opts.o_close_list, 1 },
24531337658SMarcel Moolenaar { "continuation", no_argument, NULL, 'C' },
24631337658SMarcel Moolenaar { "depth", required_argument, &opts.o_depth, 1 },
24731337658SMarcel Moolenaar { "help", no_argument, &opts.o_help, 1 },
24831337658SMarcel Moolenaar { "html", no_argument, NULL, 'H' },
24931337658SMarcel Moolenaar { "instance", required_argument, NULL, 'I' },
25031337658SMarcel Moolenaar { "json", no_argument, NULL, 'J' },
25131337658SMarcel Moolenaar { "leading-xpath", required_argument, NULL, 'l' },
25231337658SMarcel Moolenaar { "not-first", no_argument, &opts.o_not_first, 1 },
25331337658SMarcel Moolenaar { "open", required_argument, NULL, 'o' },
25431337658SMarcel Moolenaar { "open-instance", required_argument, &opts.o_open_instance, 1 },
25531337658SMarcel Moolenaar { "open-list", required_argument, &opts.o_open_list, 1 },
25631337658SMarcel Moolenaar { "option", required_argument, NULL, 'O' },
25731337658SMarcel Moolenaar { "pretty", no_argument, NULL, 'p' },
25831337658SMarcel Moolenaar { "style", required_argument, NULL, 's' },
25931337658SMarcel Moolenaar { "text", no_argument, NULL, 'T' },
26031337658SMarcel Moolenaar { "top-wrap", no_argument, &opts.o_top_wrap, 1 },
26131337658SMarcel Moolenaar { "xml", no_argument, NULL, 'X' },
26231337658SMarcel Moolenaar { "xpath", no_argument, &opts.o_xpath, 1 },
263d1a0d267SMarcel Moolenaar { "version", no_argument, &opts.o_version, 1 },
26431337658SMarcel Moolenaar { "warn", no_argument, NULL, 'W' },
26531337658SMarcel Moolenaar { "warn-xml", no_argument, &opts.o_warn_xml, 1 },
26631337658SMarcel Moolenaar { "wrap", required_argument, &opts.o_wrap, 1 },
26731337658SMarcel Moolenaar { NULL, 0, NULL, 0 }
26831337658SMarcel Moolenaar };
26931337658SMarcel Moolenaar
27031337658SMarcel Moolenaar int
main(int argc UNUSED,char ** argv)27131337658SMarcel Moolenaar main (int argc UNUSED, char **argv)
27231337658SMarcel Moolenaar {
27331337658SMarcel Moolenaar char *fmt = NULL, *cp, *np;
27431337658SMarcel Moolenaar char *opt_opener = NULL, *opt_closer = NULL, *opt_wrapper = NULL;
27531337658SMarcel Moolenaar char *opt_options = NULL;
27631337658SMarcel Moolenaar char *opt_instance = NULL;
27731337658SMarcel Moolenaar char *opt_name = NULL;
27831337658SMarcel Moolenaar xo_state_t new_state = 0;
27931337658SMarcel Moolenaar int opt_depth = 0;
28031337658SMarcel Moolenaar int opt_not_first = 0;
28131337658SMarcel Moolenaar int opt_top_wrap = 0;
28231337658SMarcel Moolenaar int rc;
28331337658SMarcel Moolenaar
28431337658SMarcel Moolenaar argc = xo_parse_args(argc, argv);
28531337658SMarcel Moolenaar if (argc < 0)
28631337658SMarcel Moolenaar return 1;
28731337658SMarcel Moolenaar
28831337658SMarcel Moolenaar while ((rc = getopt_long(argc, argv, "Cc:HJl:O:o:ps:TXW",
28931337658SMarcel Moolenaar long_opts, NULL)) != -1) {
29031337658SMarcel Moolenaar switch (rc) {
29131337658SMarcel Moolenaar case 'C':
29231337658SMarcel Moolenaar xo_set_flags(NULL, XOF_CONTINUATION);
29331337658SMarcel Moolenaar break;
29431337658SMarcel Moolenaar
29531337658SMarcel Moolenaar case 'c':
29631337658SMarcel Moolenaar opt_closer = optarg;
29731337658SMarcel Moolenaar xo_set_flags(NULL, XOF_IGNORE_CLOSE);
29831337658SMarcel Moolenaar break;
29931337658SMarcel Moolenaar
30031337658SMarcel Moolenaar case 'H':
30131337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_HTML);
30231337658SMarcel Moolenaar break;
30331337658SMarcel Moolenaar
30431337658SMarcel Moolenaar case 'I':
30531337658SMarcel Moolenaar opt_instance = optarg;
30631337658SMarcel Moolenaar break;
30731337658SMarcel Moolenaar
30831337658SMarcel Moolenaar case 'J':
30931337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_JSON);
31031337658SMarcel Moolenaar break;
31131337658SMarcel Moolenaar
31231337658SMarcel Moolenaar case 'l':
31331337658SMarcel Moolenaar xo_set_leading_xpath(NULL, optarg);
31431337658SMarcel Moolenaar break;
31531337658SMarcel Moolenaar
31631337658SMarcel Moolenaar case 'O':
31731337658SMarcel Moolenaar opt_options = optarg;
31831337658SMarcel Moolenaar break;
31931337658SMarcel Moolenaar
32031337658SMarcel Moolenaar case 'o':
32131337658SMarcel Moolenaar opt_opener = optarg;
32231337658SMarcel Moolenaar break;
32331337658SMarcel Moolenaar
32431337658SMarcel Moolenaar case 'p':
32531337658SMarcel Moolenaar xo_set_flags(NULL, XOF_PRETTY);
32631337658SMarcel Moolenaar break;
32731337658SMarcel Moolenaar
32831337658SMarcel Moolenaar case 's':
32931337658SMarcel Moolenaar if (xo_set_style_name(NULL, optarg) < 0)
33031337658SMarcel Moolenaar xo_errx(1, "unknown style: %s", optarg);
33131337658SMarcel Moolenaar break;
33231337658SMarcel Moolenaar
33331337658SMarcel Moolenaar case 'T':
33431337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_TEXT);
33531337658SMarcel Moolenaar break;
33631337658SMarcel Moolenaar
33731337658SMarcel Moolenaar case 'X':
33831337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_XML);
33931337658SMarcel Moolenaar break;
34031337658SMarcel Moolenaar
34131337658SMarcel Moolenaar case 'W':
34231337658SMarcel Moolenaar opt_warn = 1;
34331337658SMarcel Moolenaar xo_set_flags(NULL, XOF_WARN);
34431337658SMarcel Moolenaar break;
34531337658SMarcel Moolenaar
34631337658SMarcel Moolenaar case ':':
34731337658SMarcel Moolenaar xo_errx(1, "missing argument");
34831337658SMarcel Moolenaar break;
34931337658SMarcel Moolenaar
35031337658SMarcel Moolenaar case 0:
35131337658SMarcel Moolenaar if (opts.o_depth) {
35231337658SMarcel Moolenaar opt_depth = atoi(optarg);
35331337658SMarcel Moolenaar
35431337658SMarcel Moolenaar } else if (opts.o_help) {
35531337658SMarcel Moolenaar print_help();
35631337658SMarcel Moolenaar return 1;
35731337658SMarcel Moolenaar
35831337658SMarcel Moolenaar } else if (opts.o_not_first) {
35931337658SMarcel Moolenaar opt_not_first = 1;
36031337658SMarcel Moolenaar
36131337658SMarcel Moolenaar } else if (opts.o_xpath) {
36231337658SMarcel Moolenaar xo_set_flags(NULL, XOF_XPATH);
36331337658SMarcel Moolenaar
36431337658SMarcel Moolenaar } else if (opts.o_version) {
36531337658SMarcel Moolenaar print_version();
366545ddfbeSMarcel Moolenaar return 0;
36731337658SMarcel Moolenaar
36831337658SMarcel Moolenaar } else if (opts.o_warn_xml) {
36931337658SMarcel Moolenaar opt_warn = 1;
37031337658SMarcel Moolenaar xo_set_flags(NULL, XOF_WARN | XOF_WARN_XML);
37131337658SMarcel Moolenaar
37231337658SMarcel Moolenaar } else if (opts.o_wrap) {
37331337658SMarcel Moolenaar opt_wrapper = optarg;
37431337658SMarcel Moolenaar
37531337658SMarcel Moolenaar } else if (opts.o_top_wrap) {
37631337658SMarcel Moolenaar opt_top_wrap = 1;
37731337658SMarcel Moolenaar
37831337658SMarcel Moolenaar } else if (opts.o_open_list) {
37931337658SMarcel Moolenaar if (opt_name)
38031337658SMarcel Moolenaar xo_errx(1, "only one open/close list/instance allowed: %s",
38131337658SMarcel Moolenaar optarg);
38231337658SMarcel Moolenaar
38331337658SMarcel Moolenaar opt_name = optarg;
38431337658SMarcel Moolenaar new_state = XSS_OPEN_LIST;
38531337658SMarcel Moolenaar
38631337658SMarcel Moolenaar } else if (opts.o_open_instance) {
38731337658SMarcel Moolenaar if (opt_name)
38831337658SMarcel Moolenaar xo_errx(1, "only one open/close list/instance allowed: %s",
38931337658SMarcel Moolenaar optarg);
39031337658SMarcel Moolenaar
39131337658SMarcel Moolenaar opt_name = optarg;
39231337658SMarcel Moolenaar new_state = XSS_OPEN_INSTANCE;
39331337658SMarcel Moolenaar
39431337658SMarcel Moolenaar } else if (opts.o_close_list) {
39531337658SMarcel Moolenaar if (opt_name)
39631337658SMarcel Moolenaar xo_errx(1, "only one open/close list/instance allowed: %s",
39731337658SMarcel Moolenaar optarg);
39831337658SMarcel Moolenaar
39931337658SMarcel Moolenaar opt_name = optarg;
40031337658SMarcel Moolenaar new_state = XSS_CLOSE_LIST;
40131337658SMarcel Moolenaar
40231337658SMarcel Moolenaar } else if (opts.o_close_instance) {
40331337658SMarcel Moolenaar if (opt_name)
40431337658SMarcel Moolenaar xo_errx(1, "only one open/close list/instance allowed: %s",
40531337658SMarcel Moolenaar optarg);
40631337658SMarcel Moolenaar
40731337658SMarcel Moolenaar opt_name = optarg;
40831337658SMarcel Moolenaar new_state = XSS_CLOSE_INSTANCE;
40931337658SMarcel Moolenaar
41031337658SMarcel Moolenaar } else {
41131337658SMarcel Moolenaar print_help();
41231337658SMarcel Moolenaar return 1;
41331337658SMarcel Moolenaar }
41431337658SMarcel Moolenaar
41531337658SMarcel Moolenaar bzero(&opts, sizeof(opts)); /* Reset all the options */
41631337658SMarcel Moolenaar break;
41731337658SMarcel Moolenaar
41831337658SMarcel Moolenaar default:
41931337658SMarcel Moolenaar print_help();
42031337658SMarcel Moolenaar return 1;
42131337658SMarcel Moolenaar }
42231337658SMarcel Moolenaar }
42331337658SMarcel Moolenaar
42431337658SMarcel Moolenaar argc -= optind;
42531337658SMarcel Moolenaar argv += optind;
42631337658SMarcel Moolenaar
42731337658SMarcel Moolenaar if (opt_options) {
42831337658SMarcel Moolenaar rc = xo_set_options(NULL, opt_options);
42931337658SMarcel Moolenaar if (rc < 0)
43031337658SMarcel Moolenaar xo_errx(1, "invalid options: %s", opt_options);
43131337658SMarcel Moolenaar }
43231337658SMarcel Moolenaar
43331337658SMarcel Moolenaar xo_set_formatter(NULL, formatter, checkpoint);
43431337658SMarcel Moolenaar xo_set_flags(NULL, XOF_NO_VA_ARG | XOF_NO_TOP | XOF_NO_CLOSE);
43531337658SMarcel Moolenaar
43631337658SMarcel Moolenaar /*
43731337658SMarcel Moolenaar * If we have some explicit state change, handle it
43831337658SMarcel Moolenaar */
43931337658SMarcel Moolenaar if (new_state) {
44031337658SMarcel Moolenaar if (opt_depth > 0)
441 xo_set_depth(NULL, opt_depth);
442
443 if (opt_not_first)
444 xo_set_flags(NULL, XOF_NOT_FIRST);
445
446 xo_explicit_transition(NULL, new_state, opt_name, 0);
447 xo_finish();
448 exit(0);
449 }
450
451 fmt = *argv++;
452 if (opt_opener == NULL && opt_closer == NULL && fmt == NULL) {
453 print_help();
454 return 1;
455 }
456
457 if (opt_top_wrap) {
458 /* If we have a closing path, we'll be one extra level deeper */
459 if (opt_closer && xo_get_style(NULL) == XO_STYLE_JSON)
460 opt_depth += 1;
461 else
462 xo_clear_flags(NULL, XOF_NO_TOP);
463 }
464
465 if (opt_closer) {
466 opt_depth += 1;
467 for (cp = opt_closer; cp && *cp; cp = np) {
468 np = strchr(cp, '/');
469 if (np == NULL)
470 break;
471 np += 1;
472 opt_depth += 1;
473 }
474 }
475
476 if (opt_depth > 0)
477 xo_set_depth(NULL, opt_depth);
478
479 if (opt_not_first)
480 xo_set_flags(NULL, XOF_NOT_FIRST);
481
482 /* If there's an opening hierarchy, open each element as a container */
483 if (opt_opener) {
484 for (cp = opt_opener; cp && *cp; cp = np) {
485 np = strchr(cp, '/');
486 if (np)
487 *np = '\0';
488 xo_open_container(cp);
489 if (np)
490 np += 1;
491 }
492 }
493
494 /* If there's an wrapper hierarchy, open each element as a container */
495 if (opt_wrapper) {
496 for (cp = opt_wrapper; cp && *cp; cp = np) {
497 np = strchr(cp, '/');
498 if (np)
499 *np = '\0';
500 xo_open_container(cp);
501 if (np)
502 *np++ = '/'; /* Put it back */
503 }
504 }
505
506 if (opt_instance)
507 xo_open_instance(opt_instance);
508
509 /* If there's a format string, call xo_emit to emit the contents */
510 if (fmt && *fmt) {
511 save_argv = argv;
512 prep_arg(fmt);
513 xo_emit(fmt); /* This call does the real formatting */
514 }
515
516 if (opt_instance)
517 xo_close_instance(opt_instance);
518
519 /* If there's an wrapper hierarchy, close each element's container */
520 while (opt_wrapper) {
521 np = strrchr(opt_wrapper, '/');
522 xo_close_container(np ? np + 1 : opt_wrapper);
523 if (np)
524 *np = '\0';
525 else
526 opt_wrapper = NULL;
527 }
528
529 /* Remember to undo the depth before calling xo_finish() */
530 opt_depth = (opt_closer && opt_top_wrap) ? -1 : 0;
531
532 /* If there's an closing hierarchy, close each element's container */
533 while (opt_closer) {
534 np = strrchr(opt_closer, '/');
535 xo_close_container(np ? np + 1 : opt_closer);
536 if (np)
537 *np = '\0';
538 else
539 opt_closer = NULL;
540 }
541
542 /* If there's a closer and a wrapper, we need to clean it up */
543 if (opt_depth) {
544 xo_set_depth(NULL, opt_depth);
545 xo_clear_flags(NULL, XOF_NO_TOP);
546 }
547
548 /* If we're wrapping the entire content, skip the closer */
549 if (opt_top_wrap && opt_opener)
550 xo_set_flags(NULL, XOF_NO_TOP);
551
552 xo_finish();
553
554 return 0;
555 }
556