131337658SMarcel Moolenaar /*
25e203a9dSPhil Shafer * 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"
18406a584dSPhil Shafer #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 */
948a6eceffSPhil Shafer static xo_ssize_t
formatter(xo_handle_t * xop,char * buf,xo_ssize_t bufsiz,const char * fmt,va_list vap UNUSED)958a6eceffSPhil Shafer formatter (xo_handle_t *xop, char *buf, xo_ssize_t bufsiz,
9631337658SMarcel Moolenaar const char *fmt, va_list vap UNUSED)
9731337658SMarcel Moolenaar {
98d1a0d267SMarcel Moolenaar int lflag UNUSED = 0; /* Parse long flag, though currently ignored */
99d1a0d267SMarcel 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"
198406a584dSPhil Shafer " --close-instance <name> Close an open instance name\n"
199406a584dSPhil Shafer " --close-list <name> Close an open list name\n"
200406a584dSPhil Shafer " --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"
204*76afb20cSPhil Shafer " --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"
208406a584dSPhil Shafer " --not-first Indicate this object is not the first (JSON)\n"
20931337658SMarcel Moolenaar " --open <path> Open tags for the given path\n"
210406a584dSPhil Shafer " --open-instance <name> Open an instance given by name\n"
211406a584dSPhil Shafer " --open-list <name> Open a list given by name\n"
212d1a0d267SMarcel 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"
217406a584dSPhil Shafer " --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 {
227406a584dSPhil Shafer int o_close_instance;
228406a584dSPhil Shafer int o_close_list;
22931337658SMarcel Moolenaar int o_depth;
23031337658SMarcel Moolenaar int o_help;
23131337658SMarcel Moolenaar int o_not_first;
232406a584dSPhil Shafer int o_open_instance;
233406a584dSPhil Shafer int o_open_list;
234406a584dSPhil Shafer int o_top_wrap;
23531337658SMarcel Moolenaar int o_version;
23631337658SMarcel Moolenaar int o_warn_xml;
23731337658SMarcel Moolenaar int o_wrap;
238406a584dSPhil Shafer int o_xpath;
23931337658SMarcel Moolenaar } opts;
24031337658SMarcel Moolenaar
24131337658SMarcel Moolenaar static struct option long_opts[] = {
24231337658SMarcel Moolenaar { "close", required_argument, NULL, 'c' },
243406a584dSPhil Shafer { "close-instance", required_argument, &opts.o_close_instance, 1 },
244406a584dSPhil Shafer { "close-list", required_argument, &opts.o_close_list, 1 },
245406a584dSPhil Shafer { "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' },
249*76afb20cSPhil Shafer { "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' },
254406a584dSPhil Shafer { "open-instance", required_argument, &opts.o_open_instance, 1 },
255406a584dSPhil Shafer { "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' },
260406a584dSPhil Shafer { "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 },
26331337658SMarcel 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;
276*76afb20cSPhil Shafer char *opt_instance = NULL;
277406a584dSPhil Shafer char *opt_name = NULL;
278406a584dSPhil Shafer xo_state_t new_state = 0;
27931337658SMarcel Moolenaar int opt_depth = 0;
28031337658SMarcel Moolenaar int opt_not_first = 0;
281406a584dSPhil Shafer 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
288406a584dSPhil Shafer while ((rc = getopt_long(argc, argv, "Cc:HJl:O:o:ps:TXW",
28931337658SMarcel Moolenaar long_opts, NULL)) != -1) {
29031337658SMarcel Moolenaar switch (rc) {
291406a584dSPhil Shafer case 'C':
292406a584dSPhil Shafer xo_set_flags(NULL, XOF_CONTINUATION);
293406a584dSPhil Shafer break;
294406a584dSPhil Shafer
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
304*76afb20cSPhil Shafer case 'I':
305*76afb20cSPhil Shafer opt_instance = optarg;
306*76afb20cSPhil Shafer break;
307*76afb20cSPhil Shafer
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();
36631337658SMarcel 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
375406a584dSPhil Shafer } else if (opts.o_top_wrap) {
376406a584dSPhil Shafer opt_top_wrap = 1;
377406a584dSPhil Shafer
378406a584dSPhil Shafer } else if (opts.o_open_list) {
379406a584dSPhil Shafer if (opt_name)
380406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s",
381406a584dSPhil Shafer optarg);
382406a584dSPhil Shafer
383406a584dSPhil Shafer opt_name = optarg;
384406a584dSPhil Shafer new_state = XSS_OPEN_LIST;
385406a584dSPhil Shafer
386406a584dSPhil Shafer } else if (opts.o_open_instance) {
387406a584dSPhil Shafer if (opt_name)
388406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s",
389406a584dSPhil Shafer optarg);
390406a584dSPhil Shafer
391406a584dSPhil Shafer opt_name = optarg;
392406a584dSPhil Shafer new_state = XSS_OPEN_INSTANCE;
393406a584dSPhil Shafer
394406a584dSPhil Shafer } else if (opts.o_close_list) {
395406a584dSPhil Shafer if (opt_name)
396406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s",
397406a584dSPhil Shafer optarg);
398406a584dSPhil Shafer
399406a584dSPhil Shafer opt_name = optarg;
400406a584dSPhil Shafer new_state = XSS_CLOSE_LIST;
401406a584dSPhil Shafer
402406a584dSPhil Shafer } else if (opts.o_close_instance) {
403406a584dSPhil Shafer if (opt_name)
404406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s",
405406a584dSPhil Shafer optarg);
406406a584dSPhil Shafer
407406a584dSPhil Shafer opt_name = optarg;
408406a584dSPhil Shafer new_state = XSS_CLOSE_INSTANCE;
409406a584dSPhil Shafer
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);
434545ddfbeSMarcel Moolenaar xo_set_flags(NULL, XOF_NO_VA_ARG | XOF_NO_TOP | XOF_NO_CLOSE);
43531337658SMarcel Moolenaar
436406a584dSPhil Shafer /*
437406a584dSPhil Shafer * If we have some explicit state change, handle it
438406a584dSPhil Shafer */
439406a584dSPhil Shafer if (new_state) {
440406a584dSPhil Shafer if (opt_depth > 0)
441406a584dSPhil Shafer xo_set_depth(NULL, opt_depth);
442406a584dSPhil Shafer
443406a584dSPhil Shafer if (opt_not_first)
444406a584dSPhil Shafer xo_set_flags(NULL, XOF_NOT_FIRST);
445406a584dSPhil Shafer
446406a584dSPhil Shafer xo_explicit_transition(NULL, new_state, opt_name, 0);
447406a584dSPhil Shafer xo_finish();
448406a584dSPhil Shafer exit(0);
449406a584dSPhil Shafer }
450406a584dSPhil Shafer
45131337658SMarcel Moolenaar fmt = *argv++;
45231337658SMarcel Moolenaar if (opt_opener == NULL && opt_closer == NULL && fmt == NULL) {
45331337658SMarcel Moolenaar print_help();
45431337658SMarcel Moolenaar return 1;
45531337658SMarcel Moolenaar }
45631337658SMarcel Moolenaar
457406a584dSPhil Shafer if (opt_top_wrap) {
458406a584dSPhil Shafer /* If we have a closing path, we'll be one extra level deeper */
459406a584dSPhil Shafer if (opt_closer && xo_get_style(NULL) == XO_STYLE_JSON)
460406a584dSPhil Shafer opt_depth += 1;
461406a584dSPhil Shafer else
462406a584dSPhil Shafer xo_clear_flags(NULL, XOF_NO_TOP);
463406a584dSPhil Shafer }
46431337658SMarcel Moolenaar
46531337658SMarcel Moolenaar if (opt_closer) {
46631337658SMarcel Moolenaar opt_depth += 1;
46731337658SMarcel Moolenaar for (cp = opt_closer; cp && *cp; cp = np) {
46831337658SMarcel Moolenaar np = strchr(cp, '/');
46931337658SMarcel Moolenaar if (np == NULL)
47031337658SMarcel Moolenaar break;
47131337658SMarcel Moolenaar np += 1;
47231337658SMarcel Moolenaar opt_depth += 1;
47331337658SMarcel Moolenaar }
47431337658SMarcel Moolenaar }
47531337658SMarcel Moolenaar
47631337658SMarcel Moolenaar if (opt_depth > 0)
47731337658SMarcel Moolenaar xo_set_depth(NULL, opt_depth);
47831337658SMarcel Moolenaar
479406a584dSPhil Shafer if (opt_not_first)
480406a584dSPhil Shafer xo_set_flags(NULL, XOF_NOT_FIRST);
481406a584dSPhil Shafer
482406a584dSPhil Shafer /* If there's an opening hierarchy, open each element as a container */
48331337658SMarcel Moolenaar if (opt_opener) {
48431337658SMarcel Moolenaar for (cp = opt_opener; cp && *cp; cp = np) {
48531337658SMarcel Moolenaar np = strchr(cp, '/');
48631337658SMarcel Moolenaar if (np)
48731337658SMarcel Moolenaar *np = '\0';
48831337658SMarcel Moolenaar xo_open_container(cp);
48931337658SMarcel Moolenaar if (np)
490406a584dSPhil Shafer np += 1;
49131337658SMarcel Moolenaar }
49231337658SMarcel Moolenaar }
49331337658SMarcel Moolenaar
494406a584dSPhil Shafer /* If there's an wrapper hierarchy, open each element as a container */
49531337658SMarcel Moolenaar if (opt_wrapper) {
49631337658SMarcel Moolenaar for (cp = opt_wrapper; cp && *cp; cp = np) {
49731337658SMarcel Moolenaar np = strchr(cp, '/');
49831337658SMarcel Moolenaar if (np)
49931337658SMarcel Moolenaar *np = '\0';
50031337658SMarcel Moolenaar xo_open_container(cp);
50131337658SMarcel Moolenaar if (np)
502406a584dSPhil Shafer *np++ = '/'; /* Put it back */
50331337658SMarcel Moolenaar }
50431337658SMarcel Moolenaar }
50531337658SMarcel Moolenaar
506*76afb20cSPhil Shafer if (opt_instance)
507*76afb20cSPhil Shafer xo_open_instance(opt_instance);
508*76afb20cSPhil Shafer
509406a584dSPhil Shafer /* If there's a format string, call xo_emit to emit the contents */
51031337658SMarcel Moolenaar if (fmt && *fmt) {
51131337658SMarcel Moolenaar save_argv = argv;
51231337658SMarcel Moolenaar prep_arg(fmt);
513406a584dSPhil Shafer xo_emit(fmt); /* This call does the real formatting */
51431337658SMarcel Moolenaar }
51531337658SMarcel Moolenaar
516*76afb20cSPhil Shafer if (opt_instance)
517*76afb20cSPhil Shafer xo_close_instance(opt_instance);
518*76afb20cSPhil Shafer
519406a584dSPhil Shafer /* If there's an wrapper hierarchy, close each element's container */
52031337658SMarcel Moolenaar while (opt_wrapper) {
52131337658SMarcel Moolenaar np = strrchr(opt_wrapper, '/');
52231337658SMarcel Moolenaar xo_close_container(np ? np + 1 : opt_wrapper);
52331337658SMarcel Moolenaar if (np)
52431337658SMarcel Moolenaar *np = '\0';
52531337658SMarcel Moolenaar else
52631337658SMarcel Moolenaar opt_wrapper = NULL;
52731337658SMarcel Moolenaar }
52831337658SMarcel Moolenaar
529406a584dSPhil Shafer /* Remember to undo the depth before calling xo_finish() */
530406a584dSPhil Shafer opt_depth = (opt_closer && opt_top_wrap) ? -1 : 0;
531406a584dSPhil Shafer
532406a584dSPhil Shafer /* If there's an closing hierarchy, close each element's container */
53331337658SMarcel Moolenaar while (opt_closer) {
53431337658SMarcel Moolenaar np = strrchr(opt_closer, '/');
53531337658SMarcel Moolenaar xo_close_container(np ? np + 1 : opt_closer);
53631337658SMarcel Moolenaar if (np)
53731337658SMarcel Moolenaar *np = '\0';
53831337658SMarcel Moolenaar else
53931337658SMarcel Moolenaar opt_closer = NULL;
54031337658SMarcel Moolenaar }
54131337658SMarcel Moolenaar
542406a584dSPhil Shafer /* If there's a closer and a wrapper, we need to clean it up */
543406a584dSPhil Shafer if (opt_depth) {
544406a584dSPhil Shafer xo_set_depth(NULL, opt_depth);
545406a584dSPhil Shafer xo_clear_flags(NULL, XOF_NO_TOP);
546406a584dSPhil Shafer }
547406a584dSPhil Shafer
548406a584dSPhil Shafer /* If we're wrapping the entire content, skip the closer */
549406a584dSPhil Shafer if (opt_top_wrap && opt_opener)
550406a584dSPhil Shafer xo_set_flags(NULL, XOF_NO_TOP);
551406a584dSPhil Shafer
55231337658SMarcel Moolenaar xo_finish();
55331337658SMarcel Moolenaar
55431337658SMarcel Moolenaar return 0;
55531337658SMarcel Moolenaar }
556