131337658SMarcel Moolenaar /* 2*5e203a9dSPhil 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 * 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 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 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 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 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 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" 20431337658SMarcel Moolenaar " --json OR -J Generate JSON output\n" 20531337658SMarcel Moolenaar " --leading-xpath <path> OR -l <path> " 20631337658SMarcel Moolenaar "Add a prefix to generated XPaths (HTML)\n" 207406a584dSPhil Shafer " --not-first Indicate this object is not the first (JSON)\n" 20831337658SMarcel Moolenaar " --open <path> Open tags for the given path\n" 209406a584dSPhil Shafer " --open-instance <name> Open an instance given by name\n" 210406a584dSPhil Shafer " --open-list <name> Open a list given by name\n" 211d1a0d267SMarcel Moolenaar " --option <opts> -or -O <opts> Give formatting options\n" 21231337658SMarcel Moolenaar " --pretty OR -p Make 'pretty' output (add indent, newlines)\n" 21331337658SMarcel Moolenaar " --style <style> OR -s <style> " 21431337658SMarcel Moolenaar "Generate given style (xml, json, text, html)\n" 21531337658SMarcel Moolenaar " --text OR -T Generate text output (the default style)\n" 216406a584dSPhil Shafer " --top-wrap Generate a top-level object wrapper (JSON)\n" 21731337658SMarcel Moolenaar " --version Display version information\n" 21831337658SMarcel Moolenaar " --warn OR -W Display warnings in text on stderr\n" 21931337658SMarcel Moolenaar " --warn-xml Display warnings in xml on stdout\n" 22031337658SMarcel Moolenaar " --wrap <path> Wrap output in a set of containers\n" 22131337658SMarcel Moolenaar " --xml OR -X Generate XML output\n" 22231337658SMarcel Moolenaar " --xpath Add XPath data to HTML output\n"); 22331337658SMarcel Moolenaar } 22431337658SMarcel Moolenaar 22531337658SMarcel Moolenaar static struct opts { 226406a584dSPhil Shafer int o_close_instance; 227406a584dSPhil Shafer int o_close_list; 22831337658SMarcel Moolenaar int o_depth; 22931337658SMarcel Moolenaar int o_help; 23031337658SMarcel Moolenaar int o_not_first; 231406a584dSPhil Shafer int o_open_instance; 232406a584dSPhil Shafer int o_open_list; 233406a584dSPhil Shafer int o_top_wrap; 23431337658SMarcel Moolenaar int o_version; 23531337658SMarcel Moolenaar int o_warn_xml; 23631337658SMarcel Moolenaar int o_wrap; 237406a584dSPhil Shafer int o_xpath; 23831337658SMarcel Moolenaar } opts; 23931337658SMarcel Moolenaar 24031337658SMarcel Moolenaar static struct option long_opts[] = { 24131337658SMarcel Moolenaar { "close", required_argument, NULL, 'c' }, 242406a584dSPhil Shafer { "close-instance", required_argument, &opts.o_close_instance, 1 }, 243406a584dSPhil Shafer { "close-list", required_argument, &opts.o_close_list, 1 }, 244406a584dSPhil Shafer { "continuation", no_argument, NULL, 'C' }, 24531337658SMarcel Moolenaar { "depth", required_argument, &opts.o_depth, 1 }, 24631337658SMarcel Moolenaar { "help", no_argument, &opts.o_help, 1 }, 24731337658SMarcel Moolenaar { "html", no_argument, NULL, 'H' }, 24831337658SMarcel Moolenaar { "json", no_argument, NULL, 'J' }, 24931337658SMarcel Moolenaar { "leading-xpath", required_argument, NULL, 'l' }, 25031337658SMarcel Moolenaar { "not-first", no_argument, &opts.o_not_first, 1 }, 25131337658SMarcel Moolenaar { "open", required_argument, NULL, 'o' }, 252406a584dSPhil Shafer { "open-instance", required_argument, &opts.o_open_instance, 1 }, 253406a584dSPhil Shafer { "open-list", required_argument, &opts.o_open_list, 1 }, 25431337658SMarcel Moolenaar { "option", required_argument, NULL, 'O' }, 25531337658SMarcel Moolenaar { "pretty", no_argument, NULL, 'p' }, 25631337658SMarcel Moolenaar { "style", required_argument, NULL, 's' }, 25731337658SMarcel Moolenaar { "text", no_argument, NULL, 'T' }, 258406a584dSPhil Shafer { "top-wrap", no_argument, &opts.o_top_wrap, 1 }, 25931337658SMarcel Moolenaar { "xml", no_argument, NULL, 'X' }, 26031337658SMarcel Moolenaar { "xpath", no_argument, &opts.o_xpath, 1 }, 26131337658SMarcel Moolenaar { "version", no_argument, &opts.o_version, 1 }, 26231337658SMarcel Moolenaar { "warn", no_argument, NULL, 'W' }, 26331337658SMarcel Moolenaar { "warn-xml", no_argument, &opts.o_warn_xml, 1 }, 26431337658SMarcel Moolenaar { "wrap", required_argument, &opts.o_wrap, 1 }, 26531337658SMarcel Moolenaar { NULL, 0, NULL, 0 } 26631337658SMarcel Moolenaar }; 26731337658SMarcel Moolenaar 26831337658SMarcel Moolenaar int 26931337658SMarcel Moolenaar main (int argc UNUSED, char **argv) 27031337658SMarcel Moolenaar { 27131337658SMarcel Moolenaar char *fmt = NULL, *cp, *np; 27231337658SMarcel Moolenaar char *opt_opener = NULL, *opt_closer = NULL, *opt_wrapper = NULL; 27331337658SMarcel Moolenaar char *opt_options = NULL; 274406a584dSPhil Shafer char *opt_name = NULL; 275406a584dSPhil Shafer xo_state_t new_state = 0; 27631337658SMarcel Moolenaar int opt_depth = 0; 27731337658SMarcel Moolenaar int opt_not_first = 0; 278406a584dSPhil Shafer int opt_top_wrap = 0; 27931337658SMarcel Moolenaar int rc; 28031337658SMarcel Moolenaar 28131337658SMarcel Moolenaar argc = xo_parse_args(argc, argv); 28231337658SMarcel Moolenaar if (argc < 0) 28331337658SMarcel Moolenaar return 1; 28431337658SMarcel Moolenaar 285406a584dSPhil Shafer while ((rc = getopt_long(argc, argv, "Cc:HJl:O:o:ps:TXW", 28631337658SMarcel Moolenaar long_opts, NULL)) != -1) { 28731337658SMarcel Moolenaar switch (rc) { 288406a584dSPhil Shafer case 'C': 289406a584dSPhil Shafer xo_set_flags(NULL, XOF_CONTINUATION); 290406a584dSPhil Shafer break; 291406a584dSPhil Shafer 29231337658SMarcel Moolenaar case 'c': 29331337658SMarcel Moolenaar opt_closer = optarg; 29431337658SMarcel Moolenaar xo_set_flags(NULL, XOF_IGNORE_CLOSE); 29531337658SMarcel Moolenaar break; 29631337658SMarcel Moolenaar 29731337658SMarcel Moolenaar case 'H': 29831337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_HTML); 29931337658SMarcel Moolenaar break; 30031337658SMarcel Moolenaar 30131337658SMarcel Moolenaar case 'J': 30231337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_JSON); 30331337658SMarcel Moolenaar break; 30431337658SMarcel Moolenaar 30531337658SMarcel Moolenaar case 'l': 30631337658SMarcel Moolenaar xo_set_leading_xpath(NULL, optarg); 30731337658SMarcel Moolenaar break; 30831337658SMarcel Moolenaar 30931337658SMarcel Moolenaar case 'O': 31031337658SMarcel Moolenaar opt_options = optarg; 31131337658SMarcel Moolenaar break; 31231337658SMarcel Moolenaar 31331337658SMarcel Moolenaar case 'o': 31431337658SMarcel Moolenaar opt_opener = optarg; 31531337658SMarcel Moolenaar break; 31631337658SMarcel Moolenaar 31731337658SMarcel Moolenaar case 'p': 31831337658SMarcel Moolenaar xo_set_flags(NULL, XOF_PRETTY); 31931337658SMarcel Moolenaar break; 32031337658SMarcel Moolenaar 32131337658SMarcel Moolenaar case 's': 32231337658SMarcel Moolenaar if (xo_set_style_name(NULL, optarg) < 0) 32331337658SMarcel Moolenaar xo_errx(1, "unknown style: %s", optarg); 32431337658SMarcel Moolenaar break; 32531337658SMarcel Moolenaar 32631337658SMarcel Moolenaar case 'T': 32731337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_TEXT); 32831337658SMarcel Moolenaar break; 32931337658SMarcel Moolenaar 33031337658SMarcel Moolenaar case 'X': 33131337658SMarcel Moolenaar xo_set_style(NULL, XO_STYLE_XML); 33231337658SMarcel Moolenaar break; 33331337658SMarcel Moolenaar 33431337658SMarcel Moolenaar case 'W': 33531337658SMarcel Moolenaar opt_warn = 1; 33631337658SMarcel Moolenaar xo_set_flags(NULL, XOF_WARN); 33731337658SMarcel Moolenaar break; 33831337658SMarcel Moolenaar 33931337658SMarcel Moolenaar case ':': 34031337658SMarcel Moolenaar xo_errx(1, "missing argument"); 34131337658SMarcel Moolenaar break; 34231337658SMarcel Moolenaar 34331337658SMarcel Moolenaar case 0: 34431337658SMarcel Moolenaar if (opts.o_depth) { 34531337658SMarcel Moolenaar opt_depth = atoi(optarg); 34631337658SMarcel Moolenaar 34731337658SMarcel Moolenaar } else if (opts.o_help) { 34831337658SMarcel Moolenaar print_help(); 34931337658SMarcel Moolenaar return 1; 35031337658SMarcel Moolenaar 35131337658SMarcel Moolenaar } else if (opts.o_not_first) { 35231337658SMarcel Moolenaar opt_not_first = 1; 35331337658SMarcel Moolenaar 35431337658SMarcel Moolenaar } else if (opts.o_xpath) { 35531337658SMarcel Moolenaar xo_set_flags(NULL, XOF_XPATH); 35631337658SMarcel Moolenaar 35731337658SMarcel Moolenaar } else if (opts.o_version) { 35831337658SMarcel Moolenaar print_version(); 35931337658SMarcel Moolenaar return 0; 36031337658SMarcel Moolenaar 36131337658SMarcel Moolenaar } else if (opts.o_warn_xml) { 36231337658SMarcel Moolenaar opt_warn = 1; 36331337658SMarcel Moolenaar xo_set_flags(NULL, XOF_WARN | XOF_WARN_XML); 36431337658SMarcel Moolenaar 36531337658SMarcel Moolenaar } else if (opts.o_wrap) { 36631337658SMarcel Moolenaar opt_wrapper = optarg; 36731337658SMarcel Moolenaar 368406a584dSPhil Shafer } else if (opts.o_top_wrap) { 369406a584dSPhil Shafer opt_top_wrap = 1; 370406a584dSPhil Shafer 371406a584dSPhil Shafer } else if (opts.o_open_list) { 372406a584dSPhil Shafer if (opt_name) 373406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s", 374406a584dSPhil Shafer optarg); 375406a584dSPhil Shafer 376406a584dSPhil Shafer opt_name = optarg; 377406a584dSPhil Shafer new_state = XSS_OPEN_LIST; 378406a584dSPhil Shafer 379406a584dSPhil Shafer } else if (opts.o_open_instance) { 380406a584dSPhil Shafer if (opt_name) 381406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s", 382406a584dSPhil Shafer optarg); 383406a584dSPhil Shafer 384406a584dSPhil Shafer opt_name = optarg; 385406a584dSPhil Shafer new_state = XSS_OPEN_INSTANCE; 386406a584dSPhil Shafer 387406a584dSPhil Shafer } else if (opts.o_close_list) { 388406a584dSPhil Shafer if (opt_name) 389406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s", 390406a584dSPhil Shafer optarg); 391406a584dSPhil Shafer 392406a584dSPhil Shafer opt_name = optarg; 393406a584dSPhil Shafer new_state = XSS_CLOSE_LIST; 394406a584dSPhil Shafer 395406a584dSPhil Shafer } else if (opts.o_close_instance) { 396406a584dSPhil Shafer if (opt_name) 397406a584dSPhil Shafer xo_errx(1, "only one open/close list/instance allowed: %s", 398406a584dSPhil Shafer optarg); 399406a584dSPhil Shafer 400406a584dSPhil Shafer opt_name = optarg; 401406a584dSPhil Shafer new_state = XSS_CLOSE_INSTANCE; 402406a584dSPhil Shafer 40331337658SMarcel Moolenaar } else { 40431337658SMarcel Moolenaar print_help(); 40531337658SMarcel Moolenaar return 1; 40631337658SMarcel Moolenaar } 40731337658SMarcel Moolenaar 40831337658SMarcel Moolenaar bzero(&opts, sizeof(opts)); /* Reset all the options */ 40931337658SMarcel Moolenaar break; 41031337658SMarcel Moolenaar 41131337658SMarcel Moolenaar default: 41231337658SMarcel Moolenaar print_help(); 41331337658SMarcel Moolenaar return 1; 41431337658SMarcel Moolenaar } 41531337658SMarcel Moolenaar } 41631337658SMarcel Moolenaar 41731337658SMarcel Moolenaar argc -= optind; 41831337658SMarcel Moolenaar argv += optind; 41931337658SMarcel Moolenaar 42031337658SMarcel Moolenaar if (opt_options) { 42131337658SMarcel Moolenaar rc = xo_set_options(NULL, opt_options); 42231337658SMarcel Moolenaar if (rc < 0) 42331337658SMarcel Moolenaar xo_errx(1, "invalid options: %s", opt_options); 42431337658SMarcel Moolenaar } 42531337658SMarcel Moolenaar 42631337658SMarcel Moolenaar xo_set_formatter(NULL, formatter, checkpoint); 427545ddfbeSMarcel Moolenaar xo_set_flags(NULL, XOF_NO_VA_ARG | XOF_NO_TOP | XOF_NO_CLOSE); 42831337658SMarcel Moolenaar 429406a584dSPhil Shafer /* 430406a584dSPhil Shafer * If we have some explicit state change, handle it 431406a584dSPhil Shafer */ 432406a584dSPhil Shafer if (new_state) { 433406a584dSPhil Shafer if (opt_depth > 0) 434406a584dSPhil Shafer xo_set_depth(NULL, opt_depth); 435406a584dSPhil Shafer 436406a584dSPhil Shafer if (opt_not_first) 437406a584dSPhil Shafer xo_set_flags(NULL, XOF_NOT_FIRST); 438406a584dSPhil Shafer 439406a584dSPhil Shafer xo_explicit_transition(NULL, new_state, opt_name, 0); 440406a584dSPhil Shafer xo_finish(); 441406a584dSPhil Shafer exit(0); 442406a584dSPhil Shafer } 443406a584dSPhil Shafer 44431337658SMarcel Moolenaar fmt = *argv++; 44531337658SMarcel Moolenaar if (opt_opener == NULL && opt_closer == NULL && fmt == NULL) { 44631337658SMarcel Moolenaar print_help(); 44731337658SMarcel Moolenaar return 1; 44831337658SMarcel Moolenaar } 44931337658SMarcel Moolenaar 450406a584dSPhil Shafer if (opt_top_wrap) { 451406a584dSPhil Shafer /* If we have a closing path, we'll be one extra level deeper */ 452406a584dSPhil Shafer if (opt_closer && xo_get_style(NULL) == XO_STYLE_JSON) 453406a584dSPhil Shafer opt_depth += 1; 454406a584dSPhil Shafer else 455406a584dSPhil Shafer xo_clear_flags(NULL, XOF_NO_TOP); 456406a584dSPhil Shafer } 45731337658SMarcel Moolenaar 45831337658SMarcel Moolenaar if (opt_closer) { 45931337658SMarcel Moolenaar opt_depth += 1; 46031337658SMarcel Moolenaar for (cp = opt_closer; cp && *cp; cp = np) { 46131337658SMarcel Moolenaar np = strchr(cp, '/'); 46231337658SMarcel Moolenaar if (np == NULL) 46331337658SMarcel Moolenaar break; 46431337658SMarcel Moolenaar np += 1; 46531337658SMarcel Moolenaar opt_depth += 1; 46631337658SMarcel Moolenaar } 46731337658SMarcel Moolenaar } 46831337658SMarcel Moolenaar 46931337658SMarcel Moolenaar if (opt_depth > 0) 47031337658SMarcel Moolenaar xo_set_depth(NULL, opt_depth); 47131337658SMarcel Moolenaar 472406a584dSPhil Shafer if (opt_not_first) 473406a584dSPhil Shafer xo_set_flags(NULL, XOF_NOT_FIRST); 474406a584dSPhil Shafer 475406a584dSPhil Shafer /* If there's an opening hierarchy, open each element as a container */ 47631337658SMarcel Moolenaar if (opt_opener) { 47731337658SMarcel Moolenaar for (cp = opt_opener; cp && *cp; cp = np) { 47831337658SMarcel Moolenaar np = strchr(cp, '/'); 47931337658SMarcel Moolenaar if (np) 48031337658SMarcel Moolenaar *np = '\0'; 48131337658SMarcel Moolenaar xo_open_container(cp); 48231337658SMarcel Moolenaar if (np) 483406a584dSPhil Shafer np += 1; 48431337658SMarcel Moolenaar } 48531337658SMarcel Moolenaar } 48631337658SMarcel Moolenaar 487406a584dSPhil Shafer /* If there's an wrapper hierarchy, open each element as a container */ 48831337658SMarcel Moolenaar if (opt_wrapper) { 48931337658SMarcel Moolenaar for (cp = opt_wrapper; cp && *cp; cp = np) { 49031337658SMarcel Moolenaar np = strchr(cp, '/'); 49131337658SMarcel Moolenaar if (np) 49231337658SMarcel Moolenaar *np = '\0'; 49331337658SMarcel Moolenaar xo_open_container(cp); 49431337658SMarcel Moolenaar if (np) 495406a584dSPhil Shafer *np++ = '/'; /* Put it back */ 49631337658SMarcel Moolenaar } 49731337658SMarcel Moolenaar } 49831337658SMarcel Moolenaar 499406a584dSPhil Shafer /* If there's a format string, call xo_emit to emit the contents */ 50031337658SMarcel Moolenaar if (fmt && *fmt) { 50131337658SMarcel Moolenaar save_argv = argv; 50231337658SMarcel Moolenaar prep_arg(fmt); 503406a584dSPhil Shafer xo_emit(fmt); /* This call does the real formatting */ 50431337658SMarcel Moolenaar } 50531337658SMarcel Moolenaar 506406a584dSPhil Shafer /* If there's an wrapper hierarchy, close each element's container */ 50731337658SMarcel Moolenaar while (opt_wrapper) { 50831337658SMarcel Moolenaar np = strrchr(opt_wrapper, '/'); 50931337658SMarcel Moolenaar xo_close_container(np ? np + 1 : opt_wrapper); 51031337658SMarcel Moolenaar if (np) 51131337658SMarcel Moolenaar *np = '\0'; 51231337658SMarcel Moolenaar else 51331337658SMarcel Moolenaar opt_wrapper = NULL; 51431337658SMarcel Moolenaar } 51531337658SMarcel Moolenaar 516406a584dSPhil Shafer /* Remember to undo the depth before calling xo_finish() */ 517406a584dSPhil Shafer opt_depth = (opt_closer && opt_top_wrap) ? -1 : 0; 518406a584dSPhil Shafer 519406a584dSPhil Shafer /* If there's an closing hierarchy, close each element's container */ 52031337658SMarcel Moolenaar while (opt_closer) { 52131337658SMarcel Moolenaar np = strrchr(opt_closer, '/'); 52231337658SMarcel Moolenaar xo_close_container(np ? np + 1 : opt_closer); 52331337658SMarcel Moolenaar if (np) 52431337658SMarcel Moolenaar *np = '\0'; 52531337658SMarcel Moolenaar else 52631337658SMarcel Moolenaar opt_closer = NULL; 52731337658SMarcel Moolenaar } 52831337658SMarcel Moolenaar 529406a584dSPhil Shafer /* If there's a closer and a wrapper, we need to clean it up */ 530406a584dSPhil Shafer if (opt_depth) { 531406a584dSPhil Shafer xo_set_depth(NULL, opt_depth); 532406a584dSPhil Shafer xo_clear_flags(NULL, XOF_NO_TOP); 533406a584dSPhil Shafer } 534406a584dSPhil Shafer 535406a584dSPhil Shafer /* If we're wrapping the entire content, skip the closer */ 536406a584dSPhil Shafer if (opt_top_wrap && opt_opener) 537406a584dSPhil Shafer xo_set_flags(NULL, XOF_NO_TOP); 538406a584dSPhil Shafer 53931337658SMarcel Moolenaar xo_finish(); 54031337658SMarcel Moolenaar 54131337658SMarcel Moolenaar return 0; 54231337658SMarcel Moolenaar } 543